1、博主签名字符串长度限制
2、仅下载图片时-一直重复下载BUG修复 3、cookie授权界面优化
This commit is contained in:
@@ -29,16 +29,13 @@ columns.value = [
|
||||
{ title: '收藏路径', dataIndex: 'savePath' },
|
||||
{ title: '喜欢路径', dataIndex: 'favSavePath' },
|
||||
{ title: '博主路径', dataIndex: 'upSavePath' },
|
||||
// { title: '图文视频', dataIndex: 'imgSavePath' },
|
||||
// { title: 'Cookie', dataIndex: 'cookies' },
|
||||
{ title: '状态', dataIndex: 'status', width: 180 },
|
||||
{ title: '操作', dataIndex: 'edit', width: 200 }, // 加宽操作列宽度
|
||||
{ title: '操作', dataIndex: 'edit', width: 200 },
|
||||
];
|
||||
|
||||
// 定义数组中单个对象的类型:包含uper和uid字段(可选字符串类型,根据实际需求调整是否可选)
|
||||
interface UpSecUserIdItem {
|
||||
uper?: string; // 若要求必填,可去掉问号 `uper: string;`
|
||||
uid?: string; // 同上,必填则去掉问号
|
||||
uper?: string;
|
||||
uid?: string;
|
||||
syncAll: boolean;
|
||||
}
|
||||
|
||||
@@ -54,8 +51,6 @@ type DataItem = {
|
||||
upSecUserIdsJson?: UpSecUserIdItem[];
|
||||
upSecUserIds?: string;
|
||||
upSavePath?: string;
|
||||
// imgSavePath?: string;
|
||||
// useSinglePath?: boolean; // 新增:是否全部用一个地址
|
||||
useCollectFolder?: boolean;
|
||||
downMix?: boolean;
|
||||
downSeries?: boolean;
|
||||
@@ -118,17 +113,15 @@ const newCookie = (cookie?: DataItem) => {
|
||||
cookie.savePath = undefined;
|
||||
cookie.favSavePath = undefined;
|
||||
cookie.secUserId = undefined;
|
||||
cookie.status = 0; // 0=关闭,1=开启
|
||||
cookie.status = 0;
|
||||
cookie.id = '0';
|
||||
cookie.upSecUserIdsJson = undefined;
|
||||
cookie.upSavePath = undefined;
|
||||
// cookie.imgSavePath = undefined;
|
||||
// cookie.useSinglePath = false; // 新增:默认不使用单一路径
|
||||
cookie.useCollectFolder = false; //是否按收藏夹来下载。
|
||||
cookie.downMix = false; //是否下载收藏夹的合集
|
||||
cookie.downSeries = false; //是否下载短剧
|
||||
cookie.mixPath = undefined; //合集存储路径
|
||||
cookie.seriesPath = undefined; //短剧存储路径
|
||||
cookie.useCollectFolder = false;
|
||||
cookie.downMix = false;
|
||||
cookie.downSeries = false;
|
||||
cookie.mixPath = undefined;
|
||||
cookie.seriesPath = undefined;
|
||||
cookie.downCollect = false;
|
||||
cookie.downFavorite = false;
|
||||
cookie.downFollowd = false;
|
||||
@@ -144,19 +137,6 @@ const copyObject = (target: any, source?: any) => {
|
||||
|
||||
const form = reactive<DataItem>(newCookie());
|
||||
|
||||
// 新增:监听收藏路径变化,当启用单一路径时同步到其他路径
|
||||
// watch(
|
||||
// [() => form.savePath, () => form.useSinglePath],
|
||||
// ([newSavePath, useSinglePath]) => {
|
||||
// // if (useSinglePath && newSavePath) {
|
||||
// // form.favSavePath = newSavePath;
|
||||
// // form.upSavePath = newSavePath;
|
||||
// // // form.imgSavePath = newSavePath;
|
||||
// // }
|
||||
// },
|
||||
// { immediate: true }
|
||||
// );
|
||||
|
||||
function reset() {
|
||||
return newCookie(form);
|
||||
}
|
||||
@@ -177,7 +157,6 @@ function submit() {
|
||||
?.validateFields()
|
||||
.then((resData: DataItem) => {
|
||||
if (form._isNew) {
|
||||
// authors.push({ ...res });
|
||||
} else {
|
||||
copyObject(editRecord.value, resData);
|
||||
}
|
||||
@@ -236,17 +215,10 @@ function edit(record: DataItem) {
|
||||
editRecord.value = record;
|
||||
console.log(record);
|
||||
copyObject(form, record);
|
||||
// 确保useSinglePath有默认值
|
||||
// if (form.useSinglePath === undefined) {
|
||||
// form.useSinglePath = false;
|
||||
// }
|
||||
showModal.value = true;
|
||||
}
|
||||
|
||||
// 新增:切换同步状态方法
|
||||
|
||||
const switchSyncStatus = (record: DataItem) => {
|
||||
// 保存原始状态,用于弹窗取消后还原
|
||||
const statusText = record.status === 1 ? '开启' : '停止';
|
||||
const title = `确认${statusText}同步`;
|
||||
const content = `确定要${statusText}【${record.userName || '该'}】Cookie的同步任务吗?`;
|
||||
@@ -267,7 +239,7 @@ const switchSyncStatus = (record: DataItem) => {
|
||||
loading.value = false;
|
||||
if (res.code === 0) {
|
||||
message.success(`${statusText}同步成功`);
|
||||
GetRecords(); // 刷新列表,更新 switch 状态
|
||||
GetRecords();
|
||||
} else {
|
||||
message.error(`${statusText}同步失败:${res.message || '未知错误'}`);
|
||||
record.status = record.status === 1 ? 0 : 1;
|
||||
@@ -292,19 +264,6 @@ const StatusDict = {
|
||||
};
|
||||
|
||||
const dataSource = ref(datas);
|
||||
const showCookiesModal = ref(false);
|
||||
let showCookiesData = '';
|
||||
const showCookies = (recode: DataItem) => {
|
||||
showCookiesModal.value = true;
|
||||
showCookiesData = recode.cookies;
|
||||
};
|
||||
|
||||
const showUpersModal = ref(false);
|
||||
let showUpersData = '';
|
||||
const showUpers = (recode: DataItem) => {
|
||||
showUpersModal.value = true;
|
||||
showUpersData = recode.upSecUserIds;
|
||||
};
|
||||
|
||||
const addRow = () => {
|
||||
if (!form.upSecUserIdsJson) {
|
||||
@@ -319,47 +278,38 @@ const removeRow = (index: number) => {
|
||||
};
|
||||
const rowCount = 10;
|
||||
|
||||
// 组件挂载时获取配置
|
||||
onMounted(() => {
|
||||
GetRecords();
|
||||
});
|
||||
|
||||
// ========== 抽屉相关响应式数据 ==========
|
||||
// 抽屉显示状态
|
||||
const showDrawer = ref(false);
|
||||
// 抽屉类型(区分收藏夹/合集/短剧)
|
||||
type DrawerType = 'collect' | 'mix' | 'series';
|
||||
|
||||
const cookieId = ref('');
|
||||
const cateType = ref(5);
|
||||
|
||||
const drawerType = ref<DrawerType>('collect');
|
||||
// 抽屉滚动容器引用(用于监听触底分页)
|
||||
const drawerScrollRef = ref<HTMLDivElement | null>(null);
|
||||
// 抽屉数据列表
|
||||
const drawerDataList = ref<DrawerItem[]>([]);
|
||||
// 抽屉分页配置
|
||||
const drawerPagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
hasMore: true, // 是否还有更多数据
|
||||
hasMore: true,
|
||||
});
|
||||
|
||||
// ========== 定义抽屉数据项接口 ==========
|
||||
interface DrawerItem {
|
||||
id: string; // 不显示
|
||||
name: string; // 名称
|
||||
saveFolder: string; // 保存文件夹
|
||||
sync: boolean; // 是否同步
|
||||
coverUrl: string; // 封面
|
||||
cookieId: string; // 不显示
|
||||
xId: string; // 不显示
|
||||
id: string;
|
||||
name: string;
|
||||
saveFolder: string;
|
||||
sync: boolean;
|
||||
coverUrl: string;
|
||||
cookieId: string;
|
||||
xId: string;
|
||||
total: number;
|
||||
}
|
||||
|
||||
// ========== 3个打开抽屉的方法 ==========
|
||||
const openCollectFolderSetModal = () => {
|
||||
drawerType.value = 'collect';
|
||||
cateType.value = 5;
|
||||
@@ -378,16 +328,13 @@ const openSeriesDownSetModal = () => {
|
||||
openCommonDrawer();
|
||||
};
|
||||
|
||||
// ========== 公用抽屉打开逻辑(替换原来的) ==========
|
||||
const openCommonDrawer = () => {
|
||||
// 重置抽屉状态
|
||||
drawerDataList.value = [];
|
||||
drawerPagination.current = 1;
|
||||
drawerPagination.total = 0;
|
||||
drawerPagination.hasMore = true;
|
||||
showDrawer.value = true;
|
||||
|
||||
// 确保DOM渲染后再加载 + 绑定事件
|
||||
nextTick()
|
||||
.then(() => {
|
||||
loadDrawerData();
|
||||
@@ -395,54 +342,24 @@ const openCommonDrawer = () => {
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
// ========== 绑定抽屉滚动触底事件 ==========
|
||||
// const bindDrawerScrollEvent = () => {
|
||||
// const scrollContainer = drawerScrollRef.value;
|
||||
// if (!scrollContainer) return;
|
||||
|
||||
// // 先移除原有事件,避免重复绑定
|
||||
// scrollContainer.removeEventListener('scroll', handleDrawerScroll);
|
||||
// // 添加滚动事件
|
||||
// scrollContainer.addEventListener('scroll', handleDrawerScroll);
|
||||
// };
|
||||
// ========== 绑定抽屉滚动触底事件(替换原来的) ==========
|
||||
const bindDrawerScrollEvent = () => {
|
||||
const scrollContainer = drawerScrollRef.value;
|
||||
if (!scrollContainer) {
|
||||
// 延迟重试绑定,确保DOM渲染完成
|
||||
setTimeout(() => {
|
||||
bindDrawerScrollEvent();
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
// 先清除所有旧事件
|
||||
scrollContainer.removeEventListener('scroll', handleDrawerScroll);
|
||||
// 重新绑定
|
||||
scrollContainer.addEventListener('scroll', handleDrawerScroll);
|
||||
|
||||
// 额外:首次加载如果内容不足一屏,自动加载下一页
|
||||
setTimeout(() => {
|
||||
handleDrawerScroll();
|
||||
}, 200);
|
||||
};
|
||||
// ========== 滚动触底处理逻辑 ==========
|
||||
// const handleDrawerScroll = () => {
|
||||
// const scrollContainer = drawerScrollRef.value;
|
||||
// if (!scrollContainer || drawerPagination.loading || !drawerPagination.hasMore) return;
|
||||
|
||||
// // 计算滚动位置(触底阈值20px,避免精准触底才触发)
|
||||
// const { scrollTop, clientHeight, scrollHeight } = scrollContainer;
|
||||
// const isBottom = scrollTop + clientHeight >= scrollHeight - 20;
|
||||
|
||||
// if (isBottom) {
|
||||
// // 加载下一页
|
||||
// drawerPagination.current += 1;
|
||||
// loadDrawerData();
|
||||
// }
|
||||
// };
|
||||
|
||||
// 防抖函数(防止滚动触发太频繁)
|
||||
const debounce = (func: Function, delay = 100) => {
|
||||
let timeoutId: any;
|
||||
return (...args: any[]) => {
|
||||
@@ -450,14 +367,13 @@ const debounce = (func: Function, delay = 100) => {
|
||||
timeoutId = setTimeout(() => func.apply(this, args), delay);
|
||||
};
|
||||
};
|
||||
// ========== 滚动触底处理逻辑(替换原来的) ==========
|
||||
|
||||
const handleDrawerScroll = debounce(() => {
|
||||
const scrollContainer = drawerScrollRef.value;
|
||||
if (!scrollContainer) return;
|
||||
if (drawerPagination.loading || !drawerPagination.hasMore) return;
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
||||
// 兼容所有设备的触底判断(距离底部 50px 就触发)
|
||||
const isBottom = scrollTop + clientHeight + 50 >= scrollHeight;
|
||||
|
||||
if (isBottom) {
|
||||
@@ -465,9 +381,8 @@ const handleDrawerScroll = debounce(() => {
|
||||
drawerPagination.current += 1;
|
||||
loadDrawerData();
|
||||
}
|
||||
}, 100); // 100ms 防抖
|
||||
}, 100);
|
||||
|
||||
// ========== 加载抽屉数据(替换原来的) ==========
|
||||
const loadDrawerData = () => {
|
||||
if (drawerPagination.loading || !drawerPagination.hasMore) {
|
||||
console.log('🚫 阻止重复加载');
|
||||
@@ -488,10 +403,8 @@ const loadDrawerData = () => {
|
||||
drawerDataList.value = [...drawerDataList.value, ...newData];
|
||||
|
||||
drawerPagination.total = res.data.total || 0;
|
||||
// 判断是否还有更多
|
||||
drawerPagination.hasMore = drawerDataList.value.length < drawerPagination.total;
|
||||
|
||||
// 加载完成后立刻检查是否需要继续加载(适配大屏)
|
||||
setTimeout(() => {
|
||||
handleDrawerScroll();
|
||||
}, 100);
|
||||
@@ -507,7 +420,6 @@ const loadDrawerData = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// ========== 获取抽屉类型名称(用于页面展示) ==========
|
||||
const getDrawerTypeName = () => {
|
||||
switch (drawerType.value) {
|
||||
case 'collect':
|
||||
@@ -521,24 +433,21 @@ const getDrawerTypeName = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 切换同步状态(可根据需求对接真实接口) ==========
|
||||
const toggleDrawerItemSync = (item: DrawerItem, index: number) => {
|
||||
if (drawerDataList.value[index]) {
|
||||
drawerDataList.value[index].sync = !item.sync;
|
||||
console.log(`切换${getDrawerTypeName()}【${item.name}】的同步状态为:${!item.sync}`);
|
||||
}
|
||||
};
|
||||
// ========== 关闭抽屉清理资源 ==========
|
||||
|
||||
const closeDrawer = () => {
|
||||
showDrawer.value = false;
|
||||
// 移除滚动事件监听
|
||||
const scrollContainer = drawerScrollRef.value;
|
||||
if (scrollContainer) {
|
||||
scrollContainer.removeEventListener('scroll', handleDrawerScroll);
|
||||
}
|
||||
};
|
||||
|
||||
// 2. 新增:抽屉右上角保存按钮的点击方法(仅抽屉相关,不影响其他逻辑)
|
||||
const saveDrawerData = () => {
|
||||
if (drawerDataList.value.length === 0) {
|
||||
message.info('暂无需要保存的配置数据');
|
||||
@@ -587,12 +496,10 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:下载收藏视频 - 拆分Form.Item,用a-form-item-rest包裹非收集字段 -->
|
||||
<a-form-item label="下载收藏视频" name="downCollect">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downCollect" @change="switchdownCollect" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<!-- 非收集字段用a-form-item-rest包裹 -->
|
||||
<a-form-item-rest v-if="form.downCollect">
|
||||
<a-form-item name="savePath" noStyle>
|
||||
<a-input v-model:value="form.savePath" placeholder='请输入容器路径' class="form-item-div-input" />
|
||||
@@ -603,7 +510,6 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:自定义收藏夹 - 拆分Form.Item -->
|
||||
<a-form-item v-if="form.savePath && form.savePath.length>0" label="自定义收藏夹" name="useCollectFolder">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
@@ -619,7 +525,6 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:下载喜欢视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载喜欢视频" name="downFavorite">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
@@ -637,7 +542,6 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:下载关注视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载关注视频" name="downFollowd">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
@@ -655,7 +559,6 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:下载合集视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载合集视频" name="downMix">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
@@ -673,7 +576,6 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:下载短剧视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载短剧视频" name="downSeries">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
@@ -687,12 +589,10 @@ const switchdownCollect = (e: any) => {
|
||||
</a-button>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
<a-alert message="开启后自动下载收藏的短剧视频(还需要开启短剧同步开关,不填目录径默认存储到收藏目录,设置后记得docker里面加映射,注意:付费视频下载后无法播放)
|
||||
" :type="form.downSeries?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
<a-alert message="开启后自动下载收藏的短剧视频(还需要开启短剧同步开关,不填目录径默认存储到收藏目录,设置后记得docker里面加映射,注意:付费视频下载后无法播放)" :type="form.downSeries?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 任务同步状态 - 保持原有结构(仅一个Switch,无警告) -->
|
||||
<a-form-item label="任务同步状态" name="status">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<a-switch v-model:checked="form.status" :checked-value="1" :un-checked-value="0" size="default" />
|
||||
@@ -702,9 +602,7 @@ const switchdownCollect = (e: any) => {
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 公用抽屉组件(层级高于原有弹窗)- 优化后 -->
|
||||
<a-drawer :title="getDrawerTypeName()+'配置'" v-model:visible="showDrawer" placement="right" width="800px" :z-index="10010" :mask-z-index="10009" @close="closeDrawer" class="common-drawer">
|
||||
<!-- 抽屉右上角:添加保存按钮(利用 extra 插槽,不改动其他模板) -->
|
||||
<template #extra>
|
||||
<a-button type="primary" :loading="drawerPagination.loading" @click="saveDrawerData" class="drawer-save-btn">
|
||||
<template #icon>
|
||||
@@ -714,28 +612,22 @@ const switchdownCollect = (e: any) => {
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<!-- 抽屉滚动容器(绑定ref和滚动样式) -->
|
||||
<div ref="drawerScrollRef" class="drawer-scroll-container">
|
||||
<!-- 加载中状态 -->
|
||||
<div v-if="drawerPagination.loading && drawerDataList.length === 0" class="drawer-loading">
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
|
||||
<!-- 卡片网格展示 - 优化布局(横向一行展示名称、保存路径) -->
|
||||
<a-card v-else :bordered="false" class="drawer-card-container grid-container">
|
||||
<a-card-grid v-for="(item, index) in drawerDataList" :key="item.id" class="drawer-card-grid">
|
||||
<!-- 竖向封面(移除预览功能,仅保留基础展示) -->
|
||||
<div class="grid-cover vertical-cover" v-if="drawerType!='collect'">
|
||||
<a-image :preview="false" :src="item.coverUrl" fit="cover" />
|
||||
</div>
|
||||
|
||||
<!-- 名称:横向一行展示(标签 + 内容 在同一行) -->
|
||||
<div class="grid-item horizontal-item name">
|
||||
<label class="drawer-label">名称:</label>
|
||||
<span>{{ item.name || '未命名' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 保存文件夹:横向一行展示(标签 + 输入框 在同一行) -->
|
||||
<div class="grid-item horizontal-item save-folder">
|
||||
<label class="drawer-label">保存:</label>
|
||||
<a-input v-model:value="item.saveFolder" size="small" placeholder="默认用名称作文件夹" class="save-path-input" />
|
||||
@@ -745,7 +637,6 @@ const switchdownCollect = (e: any) => {
|
||||
<span>{{ item.total || '0' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 同步开关(保持原有逻辑,横向对齐) -->
|
||||
<div class="grid-item horizontal-item sync-switch">
|
||||
<label class="drawer-label">同步:</label>
|
||||
<a-switch :checked="item.sync" @change="() => toggleDrawerItemSync(item, index)" size="small" />
|
||||
@@ -753,19 +644,16 @@ const switchdownCollect = (e: any) => {
|
||||
</a-card-grid>
|
||||
</a-card>
|
||||
|
||||
<!-- 无更多数据提示 -->
|
||||
<div v-if="!drawerPagination.hasMore && drawerDataList.length > 0" class="no-more-data">
|
||||
<!-- 已加载全部{{ getDrawerTypeName() }}数据 -->
|
||||
</div>
|
||||
|
||||
<!-- 加载下一页中 -->
|
||||
<div v-if="drawerPagination.loading && drawerDataList.length > 0" class="loading-more">
|
||||
<Spin size="small" />
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-drawer>
|
||||
<!-- 成员表格 -->
|
||||
|
||||
<a-table v-bind="$attrs" :columns="columns" :dataSource="dataSource" :pagination="false">
|
||||
<template #title>
|
||||
<div class="flex justify-end pr-4">
|
||||
@@ -786,7 +674,6 @@ const switchdownCollect = (e: any) => {
|
||||
</template>
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<!-- 新:a-switch 显示状态,绑定切换逻辑 -->
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<a-switch v-model:checked="record.status" :checked-value="1" :un-checked-value="0" size="small" :disabled="loading" @change="() => switchSyncStatus(record)" />
|
||||
<span :style="{
|
||||
@@ -797,14 +684,7 @@ const switchdownCollect = (e: any) => {
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'cookies'">
|
||||
<a-button @click="showCookies(record)">查看</a-button>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'upSecUserIds'">
|
||||
<a-button @click="showUpers(record)">查看</a-button>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'edit'">
|
||||
<!-- 已删除「开启/停止」按钮,仅保留编辑和删除 -->
|
||||
<a-button :disabled="showModal || loading" type="link" @click="edit(record)">
|
||||
<template #icon>
|
||||
<EditFilled />
|
||||
@@ -824,51 +704,12 @@ const switchdownCollect = (e: any) => {
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<!-- Cookie详情弹窗 -->
|
||||
<a-modal title="Cookie 详情" :visible="showCookiesModal" style="width:1200px;" @cancel="showCookiesModal = false" @ok="showCookiesModal = false">
|
||||
<div class="cookie-content">
|
||||
{{ showCookiesData || '无Cookie数据' }}
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
<!-- 博主信息弹窗 -->
|
||||
<a-modal title="要同步的博主信息" :visible="showUpersModal" style="width:1200px;" @cancel="showUpersModal = false" @ok="showUpersModal = false">
|
||||
<div class="cookie-content">
|
||||
{{ showUpersData || '未设置' }}
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
// 原有非抽屉样式(保留,不改动)
|
||||
.cookie-content {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
/* 透明滚动条样式 - WebKit内核浏览器 */
|
||||
.cookie-content::-webkit-scrollbar {
|
||||
width: 6px; /* 更细的滚动条 */
|
||||
}
|
||||
.cookie-content::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
.cookie-content::-webkit-scrollbar-thumb {
|
||||
background: rgba(150, 150, 150, 0.2); /* 浅灰透明 */
|
||||
border-radius: 3px;
|
||||
}
|
||||
.cookie-content::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(150, 150, 150, 0.4); /* 略深一点的透明 */
|
||||
}
|
||||
.cookie-content::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
.form-item-div {
|
||||
width: 300px;
|
||||
}
|
||||
@@ -876,13 +717,7 @@ const switchdownCollect = (e: any) => {
|
||||
width: 180px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
/* Firefox 透明滚动条适配 */
|
||||
.cookie-content {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(150, 150, 150, 0.2) transparent;
|
||||
}
|
||||
|
||||
/* a-textarea 透明滚动条 */
|
||||
:deep(.ant-input-textarea-input) {
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
@@ -906,102 +741,81 @@ const switchdownCollect = (e: any) => {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 禁用状态的输入框样式优化 */
|
||||
:deep(.ant-input-disabled) {
|
||||
background-color: #f5f5f5 !important;
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
/* 修复:移除对alert的自定义样式修改,还原官方默认样式 */
|
||||
.alert-wrapper {
|
||||
flex: 1;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
// ========== 精准匹配模板:a-card-grid 样式优化 ==========
|
||||
/* 父容器:解决卡片间隙,避免换行(不改动模板,仅样式控制) */
|
||||
|
||||
.drawer-card-container.grid-container {
|
||||
// 清除 a-card 自带内边距,避免与卡片间隙冲突
|
||||
:deep(.ant-card-body) {
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
// 启用 Flex 布局,实现卡片均匀间隙(核心:gap 不与组件自带样式冲突)
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px; /* 卡片之间的横向/纵向间隙(可自定义,不会换行) */
|
||||
gap: 20px;
|
||||
box-sizing: border-box;
|
||||
/* 固定左对齐:单元素/多元素都保持从左往右排列 */
|
||||
justify-content: flex-start;
|
||||
/* 新增:兜底最小高度,避免空容器塌陷 */
|
||||
min-height: 200px;
|
||||
/* 新增:左内边距,让单元素和多元素视觉对齐一致 */
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
/* 新增:单元素样式修复 - 关键修复(仅防变形,不居中) */
|
||||
.drawer-card-container.grid-container:has(:only-child) :deep(.drawer-card-grid) {
|
||||
/* 单元素时保持3列布局的宽度,不拉伸,防止变形 */
|
||||
width: calc(33.333% - 10.333px) !important;
|
||||
/* 可选:如果觉得单元素太窄,可取消下面注释,设置固定宽度 */
|
||||
/* width: 300px !important; */
|
||||
min-width: 200px; /* 强制最小宽度,防止压缩变形 */
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
/* a-card-grid 核心样式:圆角 + 固定宽度 + 内边距 */
|
||||
:deep(.drawer-card-grid) {
|
||||
// 精确宽度计算:3列均分,减去 gap 分摊值,避免换行
|
||||
width: calc(33.333% - 10.333px) !important; /* 20px gap 分摊到3列,每列减 ~13.333px */
|
||||
/* 新增:最小宽度限制,防止变形(核心) */
|
||||
width: calc(33.333% - 10.333px) !important;
|
||||
min-width: 200px;
|
||||
margin: 5px !important; /* 清除组件自带 margin,避免间隙重复 */
|
||||
border-radius: 12px !important; /* 卡片圆角(可自定义大小) */
|
||||
padding: 16px !important; /* 卡片内部整体内边距 */
|
||||
margin: 5px !important;
|
||||
border-radius: 12px !important;
|
||||
padding: 16px !important;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #f0f0f0; /* 卡片边框,增强圆角视觉感 */
|
||||
// 卡片内部竖向排列,确保每个内容块独占一行
|
||||
border: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px; /* 卡片内部元素之间的间距(可自定义) */
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* 图片容器:横向铺满卡片 + 自带内边距 */
|
||||
:deep(.drawer-card-grid .grid-cover.vertical-cover) {
|
||||
width: 100% !important; /* 横向铺满卡片 */
|
||||
padding: 4px; /* 图片内部内边距(可自定义,实现图片与卡片边框的间距) */
|
||||
width: 100% !important;
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px; /* 图片容器轻微圆角,与卡片圆角呼应 */
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 图片:强制铺满容器,不拉伸 */
|
||||
:deep(.drawer-card-grid .vertical-cover .ant-image) {
|
||||
width: 100% !important;
|
||||
height: auto !important; /* 高度自适应,保持图片比例 */
|
||||
height: auto !important;
|
||||
display: block;
|
||||
}
|
||||
:deep(.drawer-card-grid .vertical-cover .ant-image-img) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: cover !important; /* 保持图片比例,裁剪多余部分 */
|
||||
object-fit: cover !important;
|
||||
}
|
||||
|
||||
/* 名称、保存路径、同步开关:独占一行样式 */
|
||||
:deep(.drawer-card-grid .grid-item.horizontal-item) {
|
||||
width: 100% !important; /* 独占一行,横向铺满卡片 */
|
||||
width: 100% !important;
|
||||
display: flex;
|
||||
align-items: center; /* 标签与内容垂直居中 */
|
||||
margin: 0 !important; /* 清除多余间距,确保独占一行 */
|
||||
padding: 4px 0; /* 上下轻微内边距,增强可读性 */
|
||||
align-items: center;
|
||||
margin: 0 !important;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
// 亮色模式(保留)
|
||||
:deep(.drawer-label) {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* 名称内容、输入框:占满剩余宽度 */
|
||||
:deep(.drawer-card-grid .horizontal-item span) {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
@@ -1016,20 +830,16 @@ const switchdownCollect = (e: any) => {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 同步开关:两端对齐,保持独占一行 */
|
||||
:deep(.drawer-card-grid .sync-switch) {
|
||||
justify-content: space-between; /* 标签左对齐,开关右对齐 */
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* 响应式适配:小屏幕自动调整列数,保持间隙不换行 */
|
||||
@media (max-width: 768px) {
|
||||
:deep(.drawer-card-grid) {
|
||||
width: calc(50% - 10px) !important; /* 2列均分,20px gap 每列减10px */
|
||||
/* 新增:响应式最小宽度 */
|
||||
width: calc(50% - 10px) !important;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
/* 响应式下单元素适配(保持左对齐) */
|
||||
.drawer-card-container.grid-container:has(:only-child) :deep(.drawer-card-grid) {
|
||||
width: calc(50% - 10px) !important;
|
||||
min-width: 180px;
|
||||
@@ -1037,51 +847,38 @@ const switchdownCollect = (e: any) => {
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
:deep(.drawer-card-grid) {
|
||||
width: 100% !important; /* 1列铺满,无间距分摊 */
|
||||
/* 新增:移动端最小宽度铺满 */
|
||||
width: 100% !important;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
/* 移动端单元素适配(1列铺满) */
|
||||
.drawer-card-container.grid-container:has(:only-child) :deep(.drawer-card-grid) {
|
||||
width: 100% !important;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 黑暗模式样式(html.dark-mode + 链式类名,光效增强 + hover 效果) ==========
|
||||
/* 卡片:深色背景 + 隐式边框 + 增强光效(默认状态) */
|
||||
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid {
|
||||
border-color: rgba(142, 140, 140, 0.1) !important; /* 边框透明化(隐掉) */
|
||||
border-color: rgba(142, 140, 140, 0.1) !important;
|
||||
background-color: #1a1a2e !important;
|
||||
/* 增强光效:双层阴影+浅蓝紫微光,更醒目且不刺眼(核心修改) */
|
||||
box-shadow: 0 6px 16px rgba(0, 20, 60, 0.4),
|
||||
/* 主阴影:加深蓝紫调,增大模糊半径,光效更明显 */ 0 2px 6px rgba(100, 120, 255, 0.2),
|
||||
/* 辅阴影:新增浅蓝紫微光,光效更突出 */ inset 0 1px 0 rgba(255, 255, 255, 0.05) !important; /* 内阴影:轻微高光,增强卡片质感 */
|
||||
/* 可选:完全隐藏边框 */
|
||||
/* border: none !important; */
|
||||
transition: all 0.3s ease-in-out !important; /* 过渡动画:hover 效果平滑切换,不生硬 */
|
||||
box-shadow: 0 6px 16px rgba(0, 20, 60, 0.4), 0 2px 6px rgba(100, 120, 255, 0.2),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.05) !important;
|
||||
transition: all 0.3s ease-in-out !important;
|
||||
}
|
||||
|
||||
/* 卡片 hover 效果:悬浮时光效更突出,层次感拉满 */
|
||||
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid:hover {
|
||||
box-shadow: 0 8px 24px rgba(0, 30, 80, 0.5),
|
||||
/* 主阴影:进一步加深、扩大,立体感更强 */ 0 4px 12px rgba(120, 140, 255, 0.35),
|
||||
/* 辅阴影:蓝紫微光更亮,光效更醒目 */ inset 0 1px 0 rgba(255, 255, 255, 0.08) !important; /* 内阴影:高光增强,质感更优 */
|
||||
transform: translateY(-2px) !important; /* 可选:轻微上浮,增强交互感(可删除) */
|
||||
box-shadow: 0 8px 24px rgba(0, 30, 80, 0.5), 0 4px 12px rgba(120, 140, 255, 0.35),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.08) !important;
|
||||
transform: translateY(-2px) !important;
|
||||
}
|
||||
|
||||
/* label:强制纯白色(核心需求,格式不变) */
|
||||
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .horizontal-item label {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
/* 名称内容:浅白色(格式不变) */
|
||||
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .horizontal-item span {
|
||||
color: rgba(255, 255, 255, 0.88) !important;
|
||||
}
|
||||
|
||||
/* 输入框:深色适配(格式不变) */
|
||||
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-input {
|
||||
background-color: #2f2f2f !important;
|
||||
border-color: #404040 !important;
|
||||
@@ -1089,7 +886,6 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 新增全局样式块,确保alert样式不受scoped影响(仅针对alert还原默认) -->
|
||||
<style lang="less">
|
||||
.full-modal {
|
||||
.ant-modal {
|
||||
@@ -1108,11 +904,9 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
}
|
||||
}
|
||||
|
||||
/* 还原Ant Design Vue alert官方默认样式,消除scoped样式的间接影响 */
|
||||
.ant-alert {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
/* padding: 16px 16px; */
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-size: 14px;
|
||||
line-height: 1.5714285714;
|
||||
@@ -1127,7 +921,6 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* 还原alert不同类型的官方默认颜色 */
|
||||
.ant-alert-info {
|
||||
background-color: #e6f4ff;
|
||||
border: 1px solid #91caff;
|
||||
@@ -1135,7 +928,6 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
.ant-alert-info .ant-alert-message {
|
||||
color: #1677ff;
|
||||
}
|
||||
/* 还原alert不同类型的官方默认颜色 */
|
||||
.ant-alert-success {
|
||||
background-color: #daf1d3;
|
||||
border: 1px solid #5bbc51;
|
||||
@@ -1144,14 +936,12 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
color: #228b22;
|
||||
}
|
||||
|
||||
/* 还原 Alert 各类型的官方默认颜色 */
|
||||
/* 错误(error)类型 - 红色系 */
|
||||
.ant-alert-error {
|
||||
background-color: #fff1f0; /* 错误类型背景色 */
|
||||
border: 1px solid #ff4d4f; /* 错误类型边框色 */
|
||||
background-color: #fff1f0;
|
||||
border: 1px solid #ff4d4f;
|
||||
}
|
||||
.ant-alert-error .ant-alert-message {
|
||||
color: #f5222d; /* 错误类型文字主色 */
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.ant-alert-warning {
|
||||
@@ -1161,7 +951,6 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
.ant-alert-warning .ant-alert-message {
|
||||
color: #faad14;
|
||||
}
|
||||
/* 确保alert图标颜色同步官方样式 */
|
||||
.ant-alert-info .ant-alert-icon {
|
||||
color: #1677ff;
|
||||
}
|
||||
@@ -1169,10 +958,8 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
// 抽屉滚动容器样式(核心修复)
|
||||
.drawer-scroll-container {
|
||||
width: 100%;
|
||||
/* 固定抽屉内部高度,强制出现滚动区域 */
|
||||
height: calc(100vh - 130px) !important;
|
||||
min-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
@@ -1182,7 +969,6 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
/* 优化滚动条 */
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
@@ -1198,7 +984,6 @@ html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-inpu
|
||||
}
|
||||
}
|
||||
|
||||
// 加载中样式
|
||||
.drawer-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
+3
-1
@@ -22,7 +22,9 @@ const prodRollupOptions = {
|
||||
},
|
||||
},
|
||||
};
|
||||
// vite 配置
|
||||
// vite 配置
|
||||
// net stop winnat
|
||||
// net start winnat
|
||||
export default ({ command, mode }) => {
|
||||
// 获取环境变量
|
||||
const env = loadEnv(mode, process.cwd());
|
||||
|
||||
@@ -646,6 +646,12 @@ namespace dy.net.job
|
||||
}
|
||||
else
|
||||
{
|
||||
//2026-06-16 21:56:40 bug修复 ,之前会一直重复下载这个图片
|
||||
//判断如果文件路径="/" 说明是仅下载图片的记录,不处理,直接跳过也不用删除记录
|
||||
if(exitVideo.VideoUrl=="/"&& exitVideo.IsMergeVideo == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//文件不存在,直接删掉原始记录
|
||||
await douyinVideoService.DeleteById(exitVideo.Id);
|
||||
}
|
||||
@@ -1212,6 +1218,7 @@ namespace dy.net.job
|
||||
VideoHeight = height > 0 ? height : 1920, // 视频高度
|
||||
};
|
||||
|
||||
|
||||
// 执行图片合成视频操作
|
||||
var mergeResult = await douyinMergeVideoService.MergeToVideo(cookie.Cookies, AppContext.BaseDirectory, reqParams, savePath, fileNamefolder, config.DownImageVideo, config.DownImage, config.DownMp3);
|
||||
if (!mergeResult)
|
||||
@@ -1220,7 +1227,6 @@ namespace dy.net.job
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 获取不带扩展名的完整路径
|
||||
//string fullPathWithoutExtension = Path.Combine(Path.GetDirectoryName(savePath),Path.GetFileNameWithoutExtension(savePath) );
|
||||
if (config.DownImageVideo)
|
||||
|
||||
@@ -111,6 +111,17 @@ namespace dy.net.repository
|
||||
return (0, 0, false);
|
||||
}
|
||||
|
||||
|
||||
//处理list里面 Signature 字段 可能存在一些导致SQL无法执行的特殊字符,需要清洗一下
|
||||
// ========== 新增:清洗 Signature 字段特殊字符 ==========
|
||||
foreach (var item in followInfos)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.Signature))
|
||||
{
|
||||
item.Signature = CleanSignature(item.Signature);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 2. 开启SqlSugar事务
|
||||
@@ -268,5 +279,42 @@ namespace dy.net.repository
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清洗签名字段,移除会导致SQL执行异常的特殊字符
|
||||
/// </summary>
|
||||
private string CleanSignature(string input,int maxLength=100)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return string.Empty;
|
||||
|
||||
// 1. 移除所有不可见控制字符(ASCII 0-31、127):空字符、换行、制表符、响铃等
|
||||
// 如需保留换行/制表符,可放开注释里的判断条件
|
||||
char[] validChars = input.Where(c =>
|
||||
{
|
||||
// if (c == '\n' || c == '\r' || c == '\t') return true; // 保留换行、回车、制表符
|
||||
return !char.IsControl(c);
|
||||
}).ToArray();
|
||||
|
||||
string result = new string(validChars);
|
||||
|
||||
// 2. 转义SQL单引号(SQL语法标准:单引号用双单引号转义,避免语句截断)
|
||||
result = result.Replace("'", "''");
|
||||
|
||||
// 3. 去除首尾空白
|
||||
result = result.Trim();
|
||||
|
||||
// 4. 可选:过滤反斜杠、空字节等其他高危字符(按需开启)
|
||||
result = result.Replace("\\", string.Empty);
|
||||
result = result.Replace("\0", string.Empty);
|
||||
|
||||
if (result.Length > maxLength)
|
||||
{
|
||||
result = result.Substring(0, maxLength);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user