增加导出配置及手动添加的关注对象
This commit is contained in:
@@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using Quartz.Util;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Xml.Linq;
|
||||
using static Dm.net.buffer.ByteArrayBuffer;
|
||||
|
||||
@@ -33,8 +35,55 @@ namespace dy.net.Controllers
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 导出配置
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("exportConf")]
|
||||
public async Task<IActionResult> ExportConf()
|
||||
{
|
||||
|
||||
// 1. 组装导出数据
|
||||
var dto = new AppConfigImportDto()
|
||||
{
|
||||
follows = await douyinFollowService.GetHandFollows(),
|
||||
conf = commonService.GetConfig()
|
||||
};
|
||||
|
||||
return Ok(new { code = 0, data = dto });
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 导入配置
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("importConf")]
|
||||
public async Task<IActionResult> ImportConf(AppConfigImportDto dto)
|
||||
{
|
||||
if (dto == null)
|
||||
return BadRequest("json数据为空");
|
||||
|
||||
var follows = dto.follows;
|
||||
if (follows != null && follows.Count > 0)
|
||||
{
|
||||
var add = await douyinFollowService.AddHandFollows(follows);
|
||||
if (add)
|
||||
Serilog.Log.Debug("关注列表导入成功");
|
||||
}
|
||||
|
||||
var conf = dto.conf;
|
||||
if (conf != null)
|
||||
{
|
||||
var update = await commonService.UpdateConfig(conf);
|
||||
if (update)
|
||||
Serilog.Log.Debug("配置导入成功");
|
||||
}
|
||||
|
||||
return Ok(new {code=0,data=true});
|
||||
}
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
@@ -50,9 +99,9 @@ namespace dy.net.Controllers
|
||||
data = new
|
||||
{
|
||||
data = list,
|
||||
total=totalCount,
|
||||
pageIndex= dto.PageIndex,
|
||||
pageSize= dto.PageSize
|
||||
total = totalCount,
|
||||
pageIndex = dto.PageIndex,
|
||||
pageSize = dto.PageSize
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -66,7 +115,7 @@ namespace dy.net.Controllers
|
||||
[HttpGet("list")]
|
||||
public async Task<IActionResult> GetAllList()
|
||||
{
|
||||
var follows= await douyinFollowService.GetGroupByCookieAsync();
|
||||
var follows = await douyinFollowService.GetGroupByCookieAsync();
|
||||
return Ok(new { code = 0, data = follows });
|
||||
}
|
||||
/// <summary>
|
||||
@@ -82,7 +131,7 @@ namespace dy.net.Controllers
|
||||
await ReStartJob();
|
||||
return Ok(new { code = 0 });
|
||||
}
|
||||
return BadRequest(new { code=-1, message = "添加失败" });
|
||||
return BadRequest(new { code = -1, message = "添加失败" });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +143,7 @@ namespace dy.net.Controllers
|
||||
|
||||
if (dyUserCookies.Id == "0")
|
||||
{
|
||||
dyUserCookies.Id=IdGener.GetLong().ToString();
|
||||
dyUserCookies.Id = IdGener.GetLong().ToString();
|
||||
var result = await dyCookieService.Add(dyUserCookies);
|
||||
if (result)
|
||||
{
|
||||
@@ -103,7 +152,8 @@ namespace dy.net.Controllers
|
||||
}
|
||||
return BadRequest(new { code = -1, message = "添加失败" });
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
var result = await dyCookieService.UpdateAsync(dyUserCookies);
|
||||
if (result)
|
||||
{
|
||||
@@ -121,8 +171,9 @@ namespace dy.net.Controllers
|
||||
[HttpGet("delete")]
|
||||
public async Task<IActionResult> DeleteAsync(string id)
|
||||
{
|
||||
var count = await dyCookieService.DeleteByIdsAsync(new List<string> { id});
|
||||
if (count > 0) {
|
||||
var count = await dyCookieService.DeleteByIdsAsync(new List<string> { id });
|
||||
if (count > 0)
|
||||
{
|
||||
await ReStartJob();
|
||||
}
|
||||
return Ok(new { code = 0, deletedCount = count });
|
||||
@@ -139,7 +190,8 @@ namespace dy.net.Controllers
|
||||
public async Task<IActionResult> UpdateConfig(AppConfig config)
|
||||
{
|
||||
var data = await commonService.UpdateConfig(config);
|
||||
if (data) {
|
||||
if (data)
|
||||
{
|
||||
await ReStartJob();
|
||||
}
|
||||
return Ok(new { code = 0, data = data });
|
||||
@@ -154,15 +206,16 @@ namespace dy.net.Controllers
|
||||
public async Task<IActionResult> ExecuteJobNow()
|
||||
{
|
||||
var config = commonService.GetConfig();
|
||||
if (config!=null)
|
||||
if (config != null)
|
||||
await quartzJobService.InitOrReStartAllJobs(config.Cron.ToString());
|
||||
return Ok(new { code = 0 , error = "" });
|
||||
return Ok(new { code = 0, error = "" });
|
||||
}
|
||||
|
||||
|
||||
private async Task ReStartJob() {
|
||||
var config= commonService.GetConfig();
|
||||
if (config!=null)
|
||||
private async Task ReStartJob()
|
||||
{
|
||||
var config = commonService.GetConfig();
|
||||
if (config != null)
|
||||
quartzJobService.InitOrReStartAllJobs(config.Cron.ToString());
|
||||
//避免前端等待
|
||||
}
|
||||
@@ -173,13 +226,13 @@ namespace dy.net.Controllers
|
||||
[HttpGet("mytag")]
|
||||
public async Task<IActionResult> GetMyTag()
|
||||
{
|
||||
return Ok(new { code = 0, data =Appsettings.Get("tagName") });
|
||||
return Ok(new { code = 0, data = Appsettings.Get("tagName") });
|
||||
}
|
||||
|
||||
[HttpGet("checktag")]
|
||||
public async Task<IActionResult> CheckTag()
|
||||
{
|
||||
var data =await DouyinHttpHelper.GetTenImage(Appsettings.Get("tagName"));
|
||||
var data = await DouyinHttpHelper.GetTenImage(Appsettings.Get("tagName"));
|
||||
if (data.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await data.Content.ReadAsStringAsync();
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ ____/ _|_)_____/ _| _| \_|\____|
|
||||
// 重置博主作品同步状态为未同步
|
||||
commonService.UpdateAllCookieSyncedToZero();
|
||||
|
||||
//if (!isDevelopment)
|
||||
if (!isDevelopment)
|
||||
{
|
||||
// 启动定时任务
|
||||
var quartzJobService = services.GetRequiredService<DouyinQuartzJobService>();
|
||||
|
||||
@@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl>
|
||||
<History>True|2025-12-08T04:40:19.2430740Z||;True|2025-12-08T12:02:30.6005542+08:00||;True|2025-12-08T11:34:29.6673185+08:00||;False|2025-12-08T11:30:56.2857042+08:00||;True|2025-12-08T10:52:43.7427594+08:00||;True|2025-12-08T07:05:03.2845531+08:00||;True|2025-12-07T23:02:10.0037815+08:00||;True|2025-12-07T22:48:25.7859648+08:00||;True|2025-12-07T20:49:13.6683281+08:00||;True|2025-12-07T08:47:30.1236366+08:00||;True|2025-12-06T13:14:32.4410202+08:00||;True|2025-12-06T13:07:29.7182102+08:00||;True|2025-12-06T13:05:46.2855366+08:00||;False|2025-12-06T13:05:40.3550904+08:00||;True|2025-12-06T13:03:47.8773880+08:00||;True|2025-12-06T13:03:28.9521030+08:00||;True|2025-12-05T23:11:51.5026151+08:00||;True|2025-12-05T12:46:26.1415079+08:00||;False|2025-12-05T12:46:19.1274332+08:00||;True|2025-12-05T09:04:36.7111717+08:00||;True|2025-12-05T08:22:51.7343317+08:00||;True|2025-12-05T08:20:32.0383739+08:00||;True|2025-12-04T21:58:29.4112766+08:00||;True|2025-12-04T21:58:10.0382218+08:00||;True|2025-12-04T21:57:55.3894059+08:00||;True|2025-12-04T21:10:38.8943797+08:00||;True|2025-12-04T21:09:31.5024569+08:00||;True|2025-12-04T08:22:47.9617427+08:00||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||;True|2025-11-30T23:54:29.6203368+08:00||;True|2025-11-30T23:54:27.5383120+08:00||;False|2025-11-30T23:54:17.0823982+08:00||;True|2025-11-30T22:41:11.4538820+08:00||;True|2025-11-30T22:38:19.7064566+08:00||;True|2025-11-30T22:37:35.2889186+08:00||;True|2025-11-30T21:42:31.1408314+08:00||;True|2025-11-30T21:42:19.5385333+08:00||;</History>
|
||||
<History>True|2025-12-08T08:43:45.2425324Z||;False|2025-12-08T16:42:23.0308163+08:00||;True|2025-12-08T16:41:52.4103868+08:00||;True|2025-12-08T16:41:49.8972006+08:00||;False|2025-12-08T16:41:39.5343442+08:00||;True|2025-12-08T12:40:19.2430740+08:00||;True|2025-12-08T12:02:30.6005542+08:00||;True|2025-12-08T11:34:29.6673185+08:00||;False|2025-12-08T11:30:56.2857042+08:00||;True|2025-12-08T10:52:43.7427594+08:00||;True|2025-12-08T07:05:03.2845531+08:00||;True|2025-12-07T23:02:10.0037815+08:00||;True|2025-12-07T22:48:25.7859648+08:00||;True|2025-12-07T20:49:13.6683281+08:00||;True|2025-12-07T08:47:30.1236366+08:00||;True|2025-12-06T13:14:32.4410202+08:00||;True|2025-12-06T13:07:29.7182102+08:00||;True|2025-12-06T13:05:46.2855366+08:00||;False|2025-12-06T13:05:40.3550904+08:00||;True|2025-12-06T13:03:47.8773880+08:00||;True|2025-12-06T13:03:28.9521030+08:00||;True|2025-12-05T23:11:51.5026151+08:00||;True|2025-12-05T12:46:26.1415079+08:00||;False|2025-12-05T12:46:19.1274332+08:00||;True|2025-12-05T09:04:36.7111717+08:00||;True|2025-12-05T08:22:51.7343317+08:00||;True|2025-12-05T08:20:32.0383739+08:00||;True|2025-12-04T21:58:29.4112766+08:00||;True|2025-12-04T21:58:10.0382218+08:00||;True|2025-12-04T21:57:55.3894059+08:00||;True|2025-12-04T21:10:38.8943797+08:00||;True|2025-12-04T21:09:31.5024569+08:00||;True|2025-12-04T08:22:47.9617427+08:00||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||;True|2025-11-30T23:54:29.6203368+08:00||;True|2025-11-30T23:54:27.5383120+08:00||;False|2025-11-30T23:54:17.0823982+08:00||;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+224
-32
@@ -1,23 +1,24 @@
|
||||
<template>
|
||||
<a-card :bordered="false" :body-style="{ padding: '20px' }">
|
||||
<a-card :bordered="false" :body-style="{ padding: '10px' }">
|
||||
<a-form :model="formState" :label-col="labelCol" :rules="rules" :wrapper-col="wrapperCol" ref="formRef" label-align="right">
|
||||
<!-- 原有所有表单内容保持不变 -->
|
||||
<!-- 任务调度配置 -->
|
||||
<div class="form-section">
|
||||
<h3 class="section-title">任务调度</h3>
|
||||
|
||||
<a-form-item has-feedback label="同步周期(分钟)" name="Cron" :wrapper-col="{ span: 6}" style="margin-left:30px">
|
||||
<a-form-item has-feedback label="同步周期(分钟)" name="Cron" :wrapper-col="{ span: 20}" style="margin-left:30px">
|
||||
<a-input-number v-model:value="formState.Cron" placeholder="请输入数字" :min="15" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>同步任务的执行间隔,最小15分钟,建议使用默认值</span>
|
||||
<span>同步任务执行间隔,最小15分钟,建议使用默认值</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item has-feedback label="每次同步上限" name="BatchCount" :wrapper-col="{ span:10}" style="margin-left:30px">
|
||||
<a-form-item has-feedback label="每次同步上限" name="BatchCount" :wrapper-col="{ span:20}" style="margin-left:30px">
|
||||
<a-input-number v-model:value="formState.BatchCount" placeholder="请输入每次下载数量上限(最大30)" :min="10" :max="30" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>每次同步获取的条数,范围10-30条(建议使用默认值18,抖音默认的分页大小)</span>
|
||||
<span>每次最大下载数量:10-30</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
@@ -30,7 +31,7 @@
|
||||
<a-switch v-model:checked="formState.UperUseViedoTitle" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>启用后,关注的视频文件名将直接使用原视频标题,否则使用模板生成,如果既没有模板也没有开启,则系统默认使用视频Id作为文件名。</span>
|
||||
<span>启用用原标题,未启用用模板;无模板则默认用视频Id</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
@@ -38,7 +39,7 @@
|
||||
<a-switch v-model:checked="formState.UperSaveTogether" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>默认是按博主名字创建文件夹存储,启用后,关注的视频直接存放在根目录。</span>
|
||||
<span>默认按博主名建文件夹,启用后直接存映射目录根目录</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
@@ -47,11 +48,7 @@
|
||||
<a-select v-model:value="formState.FollowedTitleTemplate" :options="template_options" mode="multiple" size="middle" placeholder="请选择占位符组合"></a-select>
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>
|
||||
选择生成文件名的占位符,顺序即为文件名顺序(需配合分隔符使用)<br />
|
||||
<strong class="text-gray-700">占位符说明:</strong>
|
||||
{Id}=视频ID、{VideoTitle}=视频标题、{ReleaseTime}=发布时间、{Author}=博主名称、{FileHash}=文件哈希、{Resolution}=分辨率
|
||||
</span>
|
||||
<span>选择文件名占位符(顺序为文件名顺序,需配合分隔符)<br /><strong class="text-gray-700">占位符:</strong>{Id}=视频ID、{VideoTitle}=标题、{ReleaseTime}=发布时间、{Author}=博主名、{FileHash}=文件哈希、{Resolution}=分辨率</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
@@ -81,16 +78,24 @@
|
||||
|
||||
<div class="form-section" v-if="downImgVideo">
|
||||
<h3 class="section-title">图文视频</h3>
|
||||
|
||||
<a-form-item has-feedback label="下载图文视频" name="DownImageVideo" :wrapper-col="{ span: 6 }">
|
||||
<a-form-item has-feedback label="是否单独存储" name="ImageViedoSaveAlone" :wrapper-col="{ span: 20 }">
|
||||
<a-switch v-model:checked="formState.ImageViedoSaveAlone" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>
|
||||
开启:图文视频统一存入抖音授权 Cookie 配置的目录,且需提前配置该存储路径。关闭:按类型分别存入对应文件夹(如收藏视频存入收藏视频目录)
|
||||
</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback label="下载图文视频" name="DownImageVideo" :wrapper-col="{ span: 20 }">
|
||||
<a-switch v-model:checked="formState.DownImageVideo" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>启用后,图文视频将合成为视频文件下载</span>
|
||||
<span>启用后,会将图片合成为视频文件下载</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item has-feedback label="额外下载音频" name="DownMp3" :wrapper-col="{ span: 6 }">
|
||||
<a-form-item has-feedback label="下载音频文件" name="DownMp3" :wrapper-col="{ span: 20 }">
|
||||
<a-switch v-model:checked="formState.DownMp3" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
@@ -98,36 +103,28 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item has-feedback label="额外下载图片" name="DownImage" :wrapper-col="{ span: 6 }">
|
||||
<a-form-item has-feedback label="下载图片文件" name="DownImage" :wrapper-col="{ span: 20 }">
|
||||
<a-switch v-model:checked="formState.DownImage" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>启用后,将单独下载所有图片文件</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback label="下载动态视频" name="DownImage" :wrapper-col="{ span: 6 }">
|
||||
<a-form-item has-feedback label="下载动态视频" name="DownImage" :wrapper-col="{ span: 20 }">
|
||||
<a-switch v-model:checked="formState.DownDynamicVideo" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>针对有些视频是多个视频生成的,实际是分为多个视频,启用后将会分别下载多个视频,名字带_001,002这样</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback label="是否统一存储" name="ImageViedoSaveAlone" :wrapper-col="{ span: 10 }">
|
||||
<a-switch v-model:checked="formState.ImageViedoSaveAlone" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>
|
||||
启用后,所有图文视频统一存储到 Cookie(抖音授权) 设置的目录。<br />否则,按类型存储到对应文件夹(比如视频属于收藏的视频,则存储到收藏视频的目录)
|
||||
</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 系统配置 -->
|
||||
<div class="form-section">
|
||||
<h3 class="section-title">其他配置</h3>
|
||||
<h3 class="section-title">去重配置</h3>
|
||||
|
||||
<a-form-item v-show="formState.AutoDistinct" has-feedback label="去重优先等级" name="PriorityLevel" :wrapper-col="{ span: 8 }">
|
||||
<a-form-item v-show="formState.AutoDistinct" has-feedback label="去重优先等级" name="PriorityLevel" :wrapper-col="{ span: 20 }">
|
||||
<!-- Tag 拖拽容器 -->
|
||||
<div class="tag-drag-container">
|
||||
<!-- Tag 拖拽容器(绑定 ref 供 Sortable 初始化) -->
|
||||
@@ -146,13 +143,13 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item has-feedback label="日志保留(天数)" name="LogKeepDay" :wrapper-col="{ span: 6 }" style="margin-left:30px">
|
||||
<!-- <a-form-item has-feedback label="日志保留(天数)" name="LogKeepDay" :wrapper-col="{ span: 6 }" style="margin-left:30px">
|
||||
<a-input-number v-model:value="formState.LogKeepDay" placeholder="请输入保留天数" :min="1" :max="90" />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
<InfoCircleOutlined class="text-blue-400 mr-1 mt-0.5" />
|
||||
<span>系统运行日志的保留天数,范围1-90天,过期自动清理</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form-item> -->
|
||||
<!-- <a-form-item has-feedback label="是否自动去重" name="AutoDistinct" :wrapper-col="{ span: 10 }">
|
||||
<a-switch v-model:checked="formState.AutoDistinct" disabled />
|
||||
<div class="flex items-start mt-1 text-sm text-gray-500">
|
||||
@@ -179,6 +176,26 @@
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
<!-- 配置导入导出悬浮按钮(优化布局+动画) -->
|
||||
<div class="config-float-btn-container">
|
||||
<!-- 主按钮 -->
|
||||
<a-button class="main-float-btn" type="primary" shape="circle">
|
||||
<tool-outlined />
|
||||
</a-button>
|
||||
|
||||
<!-- 子按钮容器(新增:绝对定位向上展开) -->
|
||||
<div class="float-sub-btn-wrapper">
|
||||
<a-button class="sub-float-btn export-btn" type="default" shape="circle" @click="exportConfig" tooltip="导出配置">
|
||||
<cloud-download-outlined />
|
||||
</a-button>
|
||||
<a-button class="sub-float-btn import-btn" type="default" shape="circle" @click="triggerImportFile" tooltip="导入配置">
|
||||
<cloud-upload-outlined />
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<input ref="importFileInput" type="file" accept=".json" class="import-file-input" @change="handleImportFile">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -191,7 +208,16 @@ import { useApiStore } from '@/store';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { Sortable } from 'sortablejs';
|
||||
|
||||
import { InfoCircleOutlined, SaveOutlined, CheckOutlined } from '@ant-design/icons-vue';
|
||||
import {
|
||||
InfoCircleOutlined,
|
||||
SaveOutlined,
|
||||
CheckOutlined,
|
||||
// 新增图标
|
||||
SettingOutlined,
|
||||
UpOutlined,
|
||||
DownloadOutlined,
|
||||
UploadOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref<FormInstance>();
|
||||
@@ -210,6 +236,10 @@ const template_options = [
|
||||
const componentDisabled = ref(true);
|
||||
const downImgVideo = ref(true);
|
||||
|
||||
// 新增:悬浮菜单相关状态
|
||||
const floatMenuVisible = ref(false);
|
||||
const importFileInput = ref<HTMLInputElement | null>(null);
|
||||
|
||||
// 表单数据结构(新增 FullFollowedTitleTemplate 字段)
|
||||
interface FormState {
|
||||
Cron: number;
|
||||
@@ -450,6 +480,97 @@ const onCancel = () => {
|
||||
formState.FullFollowedTitleTemplate = computeFullTemplate.value;
|
||||
}
|
||||
};
|
||||
|
||||
const importOrexportConf = ref();
|
||||
// 新增:导出配置
|
||||
const exportConfig = () => {
|
||||
try {
|
||||
useApiStore()
|
||||
.ExportConf()
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
importOrexportConf.value = res.data;
|
||||
|
||||
// 转换为JSON字符串并格式化
|
||||
const jsonStr = JSON.stringify(importOrexportConf.value, null, 2);
|
||||
const blob = new Blob([jsonStr], { type: 'application/json' });
|
||||
|
||||
// 创建下载链接
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `配置及手动关注列表备份_${new Date().getTime()}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
// 清理
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
message.success('导出配置及手动关注列表导出成功');
|
||||
floatMenuVisible.value = false;
|
||||
}
|
||||
})
|
||||
.catch((x) => {
|
||||
console.log(x);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('导出配置及手动关注列表失败:', error);
|
||||
message.error('导出配置及手动关注列表,请稍后重试');
|
||||
}
|
||||
};
|
||||
|
||||
// 新增:触发导入文件选择
|
||||
const triggerImportFile = () => {
|
||||
if (importFileInput.value) {
|
||||
importFileInput.value.click();
|
||||
}
|
||||
};
|
||||
|
||||
// 新增:处理导入文件
|
||||
const handleImportFile = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const file = target.files?.[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
if (file.type !== 'application/json' && !file.name.endsWith('.json')) {
|
||||
message.error('请选择JSON格式的配置文件');
|
||||
target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
try {
|
||||
const content = event.target?.result as string;
|
||||
const importData = JSON.parse(content);
|
||||
useApiStore()
|
||||
.ImportConf(importData)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
message.success('配置及手动关注列表导入成功,下次运行会按新的配置规则运行。');
|
||||
floatMenuVisible.value = false;
|
||||
getConfig();
|
||||
} else {
|
||||
message.error(`配置及手动关注列表导入失败`);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('解析配置文件失败:', error);
|
||||
message.error(`配置及手动关注列表导入失败:${(error as Error).message}`);
|
||||
} finally {
|
||||
// 清空文件选择
|
||||
target.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
@@ -551,4 +672,75 @@ const onCancel = () => {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
// 1. 悬浮按钮容器(恢复固定定位,作为子按钮的定位基准)
|
||||
.config-float-btn-container {
|
||||
position: fixed; // 关键:恢复固定定位,确保在页面右下角
|
||||
right: 30px;
|
||||
bottom: 100px;
|
||||
z-index: 1000;
|
||||
width: 60px; // 与主按钮宽度一致,确保居中
|
||||
height: auto; // 自适应高度,不限制子按钮展开
|
||||
|
||||
&:hover {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 子按钮容器(修正定位,基于父容器居中)
|
||||
.float-sub-btn-wrapper {
|
||||
position: absolute;
|
||||
bottom: 70px; // 主按钮高度(60px)+ 间距(10px),向上展开
|
||||
left: 50%;
|
||||
transform: translateX(-50%); // 水平居中
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
// 其他样式(主按钮、子按钮)保持不变
|
||||
.main-float-btn {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
font-size: 20px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05); // 移除多余的 translateX(-50%)
|
||||
}
|
||||
}
|
||||
|
||||
.sub-float-btn {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
opacity: 0;
|
||||
transform: translateY(10px) scale(0.9); // 仅保留垂直偏移,水平居中由父容器控制
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&.export-btn {
|
||||
transition-delay: 0.08s;
|
||||
}
|
||||
|
||||
&.import-btn {
|
||||
transition-delay: 0.16s;
|
||||
}
|
||||
}
|
||||
|
||||
.config-float-btn-container:hover .sub-float-btn {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1); // 恢复正常位置
|
||||
}
|
||||
|
||||
.import-file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 修复子按钮tooltip显示
|
||||
:deep(.ant-tooltip) {
|
||||
z-index: 1001 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -220,7 +220,25 @@ export const useApiStore = defineStore('coreapi', () => {
|
||||
});
|
||||
}
|
||||
|
||||
//导出配置
|
||||
async function ExportConf() {
|
||||
return http.request<any, Response<any>>('/api/config/exportConf', 'get').then(r => {
|
||||
return r.data;
|
||||
}).finally(() => {
|
||||
|
||||
});
|
||||
}
|
||||
//导入配置
|
||||
async function ImportConf(param: object) {
|
||||
return http.request<any, Response<any>>('/api/config/importConf', 'post_json', param).then(r => {
|
||||
return r.data;
|
||||
}).finally(() => {
|
||||
|
||||
});
|
||||
}
|
||||
return {
|
||||
ExportConf,
|
||||
ImportConf,
|
||||
GetDeleteViedos,
|
||||
DelFollow,
|
||||
AddFollow,
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"dbconn": "",
|
||||
//"tagName": "arm_1.8.4",
|
||||
//"tagName": "dev_1.2.4",
|
||||
"tagName": "beta_1.8.4",
|
||||
//"tagName": "arm_1.8.5",
|
||||
//"tagName": "dev_1.8.5",
|
||||
"tagName": "beta_1.8.5",
|
||||
"dbtype": "Sqlite"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using dy.net.model;
|
||||
|
||||
namespace dy.net.dto
|
||||
{
|
||||
public class AppConfigImportDto
|
||||
{
|
||||
|
||||
public List<DouyinFollowed> follows { get; set; }
|
||||
|
||||
public AppConfig conf { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ namespace dy.net.service
|
||||
Id = IdGener.GetLong().ToString(),
|
||||
Cron = 30,
|
||||
BatchCount = 18,
|
||||
LogKeepDay = 10,
|
||||
LogKeepDay = 7,
|
||||
UperSaveTogether = false,//博主视频:true-->每个视频单独一个文件夹 false-->所有视频放在同一个文件夹
|
||||
UperUseViedoTitle = false,//博主视频:true-->使用视频标题作为文件名 false-->使用视频id作为文件名
|
||||
DownImageVideo = true,//默认下载图文视频
|
||||
|
||||
@@ -51,6 +51,57 @@ namespace dy.net.service
|
||||
{
|
||||
return await _followRepository.GetPagedAsync(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有手动添加的非关注者
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<DouyinFollowed>> GetHandFollows()
|
||||
{
|
||||
return await _followRepository.GetListAsync(x=>x.IsNoFollowed);
|
||||
}
|
||||
/// <summary>
|
||||
/// 导入非关注
|
||||
/// </summary>
|
||||
/// <param name="douyinFolloweds"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> AddHandFollows(List<DouyinFollowed> douyinFolloweds)
|
||||
{
|
||||
if (douyinFolloweds == null || !douyinFolloweds.Any()) return false;
|
||||
|
||||
var ids = douyinFolloweds.Select(x => x.Id).Distinct().ToList();
|
||||
var existingFolloweds = await _followRepository.GetListAsync(x => ids.Contains(x.Id));
|
||||
|
||||
var toAddList = douyinFolloweds
|
||||
.Where(x => !existingFolloweds.Any(e => e.Id == x.Id))
|
||||
.ToList();
|
||||
|
||||
// 批量更新:先整理需要更新的实体
|
||||
var toUpdateEntities = new List<DouyinFollowed>();
|
||||
foreach (var updateItem in douyinFolloweds)
|
||||
{
|
||||
var existingItem = existingFolloweds.FirstOrDefault(e => e.Id == updateItem.Id);
|
||||
if (existingItem != null)
|
||||
{
|
||||
toUpdateEntities.Add(updateItem);
|
||||
}
|
||||
}
|
||||
|
||||
int operateCount = 0;
|
||||
// 批量新增
|
||||
if (toAddList.Any())
|
||||
{
|
||||
operateCount += await _followRepository.InsertRangeAsync(toAddList);
|
||||
}
|
||||
// 批量更新
|
||||
if (toUpdateEntities.Any())
|
||||
{
|
||||
await _followRepository.UpdateRangeAsync(toUpdateEntities);
|
||||
operateCount += toUpdateEntities.Count;
|
||||
}
|
||||
|
||||
return operateCount > 0;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user