fix: 增加前端小红书逻辑

This commit is contained in:
Edan's Win11
2025-06-03 23:11:30 +08:00
parent d0244fec26
commit bde08fa9fa
3 changed files with 292 additions and 177 deletions
+2 -2
View File
@@ -13,8 +13,8 @@ export const accountApi = {
},
// 更新账号
updateAccount(id, data) {
return http.put(`/account/${id}`, data)
updateAccount(data) {
return http.post('/updateUserinfo', data)
},
// 删除账号
+29 -28
View File
@@ -338,7 +338,7 @@
v-model="accountForm.platform"
placeholder="请选择平台"
style="width: 100%"
:disabled="sseConnecting"
:disabled="dialogType === 'edit' || sseConnecting"
>
<el-option label="快手" value="快手" />
<el-option label="抖音" value="抖音" />
@@ -376,7 +376,7 @@
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false" :disabled="sseConnecting && !loginStatus">取消</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button
type="primary"
@click="submitAccountForm"
@@ -630,42 +630,31 @@ const connectSSE = (platform, name) => {
else if (data === '200' || data === '500') {
loginStatus.value = data
// 如果登录成功,添加账号到状态管理
// 如果登录成功
if (data === '200') {
setTimeout(() => {
const newId = accountStore.accounts.length > 0 ?
Math.max(...accountStore.accounts.map(a => a.id)) + 1 : 1
const newAccount = {
id: newId,
name: accountForm.name,
platform: accountForm.platform,
status: '正常',
avatar: '/vite.svg' // 默认头像
}
// 添加到状态管理
accountStore.addAccount(newAccount)
// 关闭连接
closeSSEConnection()
// 1秒后关闭对话框
// 1秒后关闭对话框并开始刷新
setTimeout(() => {
dialogVisible.value = false
sseConnecting.value = false
ElMessage.success('账号添加成功')
// 显示更新账号信息提示并刷新账号列表
// 显示更新账号信息提示
ElMessage({
type: 'info',
message: '更新账号信息中...',
duration: 2000
message: '正在同步账号信息...',
duration: 0
})
// 触发刷新操作
isRefreshing.value = true
fetchAccounts()
fetchAccounts().then(() => {
// 刷新完成后关闭提示
ElMessage.closeAll()
ElMessage.success('账号信息已更新')
})
}, 1000)
}, 1000)
} else {
@@ -699,12 +688,23 @@ const submitAccountForm = () => {
// 建立SSE连接
connectSSE(accountForm.platform, accountForm.name)
} else {
// 编辑账号逻辑保持不变
// 编辑账号逻辑
try {
// 更新状态管理中的账号
accountStore.updateAccount(accountForm.id, accountForm)
ElMessage.success('更新成功')
dialogVisible.value = false
const res = await accountApi.updateAccount({
id: accountForm.id,
type: Number(accountForm.platform === '快手' ? 1 : accountForm.platform === '抖音' ? 2 : accountForm.platform === '视频号' ? 3 : 4),
userName: accountForm.name
})
if (res.code === 200) {
// 更新状态管理中的账号
accountStore.updateAccount(accountForm.id, accountForm)
ElMessage.success('更新成功')
dialogVisible.value = false
// 刷新账号列表
fetchAccounts()
} else {
ElMessage.error(res.msg || '更新账号失败')
}
} catch (error) {
console.error('更新账号失败:', error)
ElMessage.error('更新账号失败')
@@ -805,6 +805,7 @@ onBeforeUnmount(() => {
max-width: 200px;
max-height: 200px;
border: 1px solid #ebeef5;
background-color: black;
}
}
+261 -147
View File
@@ -43,16 +43,6 @@
</div>
</div>
<!-- 批量发布状态提示 -->
<div v-if="batchPublishMessage" class="batch-publish-status">
<el-alert
:title="batchPublishMessage"
:type="batchPublishType"
:closable="false"
show-icon
/>
</div>
<!-- 内容区域 -->
<div class="publish-content">
<div class="tab-content-wrapper">
@@ -62,6 +52,16 @@
v-show="activeTab === tab.name"
class="tab-content"
>
<!-- 发布状态提示 -->
<div v-if="tab.publishStatus" class="publish-status">
<el-alert
:title="tab.publishStatus.message"
:type="tab.publishStatus.type"
:closable="false"
show-icon
/>
</div>
<!-- 视频上传区域 -->
<div class="upload-section">
<h3>视频</h3>
@@ -134,6 +134,59 @@
</el-upload>
</el-dialog>
<!-- 批量发布进度对话框 -->
<el-dialog
v-model="batchPublishDialogVisible"
title="批量发布进度"
width="500px"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
>
<div class="publish-progress">
<el-progress
:percentage="publishProgress"
:status="publishProgress === 100 ? 'success' : ''"
/>
<div v-if="currentPublishingTab" class="current-publishing">
正在发布:{{ currentPublishingTab.label }}
</div>
<!-- 发布结果列表 -->
<div class="publish-results" v-if="publishResults.length > 0">
<div
v-for="(result, index) in publishResults"
:key="index"
:class="['result-item', result.status]"
>
<el-icon v-if="result.status === 'success'"><Check /></el-icon>
<el-icon v-else-if="result.status === 'error'"><Close /></el-icon>
<el-icon v-else><InfoFilled /></el-icon>
<span class="label">{{ result.label }}</span>
<span class="message">{{ result.message }}</span>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button
@click="cancelBatchPublish"
:disabled="publishProgress === 100"
>
取消发布
</el-button>
<el-button
type="primary"
@click="batchPublishDialogVisible = false"
v-if="publishProgress === 100"
>
关闭
</el-button>
</div>
</template>
</el-dialog>
<!-- 素材库选择弹窗 -->
<el-dialog
v-model="materialLibraryVisible"
@@ -431,10 +484,10 @@ const batchPublishType = ref('info')
// 平台列表 - 对应后端type字段
const platforms = [
{ key: 1, name: '抖音' },
{ key: 3, name: '抖音' },
{ key: 4, name: '快手' },
{ key: 2, name: '视频号' },
{ key: 3, name: '小红书' }
{ key: 1, name: '小红书' }
]
// tab页数据 - 默认只有一个tab
@@ -451,7 +504,8 @@ const tabs = reactive([
scheduleEnabled: false, // 定时发布开关
videosPerDay: 1, // 每天发布视频数量
dailyTimes: ['10:00'], // 每天发布时间点列表
startDays: 0 // 从今天开始计算的发布天数,0表示明天,1表示后天
startDays: 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
publishStatus: null // 发布状态,包含message和type
}
])
@@ -466,9 +520,9 @@ const accountStore = useAccountStore()
// 根据选择的平台获取可用账号列表
const availableAccounts = computed(() => {
const platformMap = {
1: '抖音',
3: '抖音',
2: '视频号',
3: '小红书',
1: '小红书',
4: '快手'
}
const currentPlatform = currentTab.value ? platformMap[currentTab.value.selectedPlatform] : null
@@ -501,7 +555,8 @@ const addTab = () => {
scheduleEnabled: false,
videosPerDay: 1,
dailyTimes: ['10:00'],
startDays: 0
startDays: 0,
publishStatus: null
}
tabs.push(newTab)
activeTab.value = newTab.name
@@ -654,68 +709,87 @@ const cancelPublish = (tab) => {
}
// 确认发布
const confirmPublish = (tab) => {
// 数据验证
if (tab.fileList.length === 0) {
ElMessage.warning('请先上传视频文件')
return
}
if (!tab.title.trim()) {
ElMessage.warning('请输入标题')
return
}
if (!tab.selectedPlatform) {
ElMessage.warning('请选择发布平台')
return
}
if (tab.selectedAccounts.length === 0) {
ElMessage.warning('请选择发布账号')
return
}
// 构造发布数据,符合后端API格式
const publishData = {
type: tab.selectedPlatform,
title: tab.title,
tags: tab.selectedTopics, // 不带#号的话题列表
fileList: tab.fileList.map(file => file.path), // 只发送文件路径
accountList: tab.selectedAccounts.map(accountId => {
const account = accountStore.accounts.find(acc => acc.id === accountId)
return account ? account.filePath : accountId
}), // 发送账号的文件路径
category: tab.scheduleEnabled ? 1 : 0, // 是否启用定时发布,开启传1,不开启传0
videosPerDay: tab.scheduleEnabled ? tab.videosPerDay || 1 : 1, // 每天发布视频数量,1-55
dailyTimes: tab.scheduleEnabled ? tab.dailyTimes || ['10:00'] : ['10:00'], // 每天发布时间点
startDays: tab.scheduleEnabled ? tab.startDays || 0 : 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
}
// 调用后端发布API
fetch(`${apiBaseUrl}/postVideo`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...authHeaders.value
},
body: JSON.stringify(publishData)
})
.then(response => response.json())
.then(data => {
if (data.code === 200) {
ElMessage.success('发布成功')
// 清空当前tab的数据
tab.fileList = []
tab.displayFileList = []
tab.title = ''
tab.selectedTopics = []
tab.selectedAccounts = []
tab.scheduleEnabled = false
} else {
ElMessage.error(data.msg || '发布失败')
const confirmPublish = async (tab) => {
return new Promise((resolve, reject) => {
// 数据验证
if (tab.fileList.length === 0) {
ElMessage.error('请先上传视频文件')
reject(new Error('请先上传视频文件'))
return
}
})
.catch(error => {
console.error('发布错误:', error)
ElMessage.error('发布失败,请检查网络连接')
if (!tab.title.trim()) {
ElMessage.error('请输入标题')
reject(new Error('请输入标题'))
return
}
if (!tab.selectedPlatform) {
ElMessage.error('请选择发布平台')
reject(new Error('请选择发布平台'))
return
}
if (tab.selectedAccounts.length === 0) {
ElMessage.error('请选择发布账号')
reject(new Error('请选择发布账号'))
return
}
// 构造发布数据,符合后端API格式
const publishData = {
type: tab.selectedPlatform,
title: tab.title,
tags: tab.selectedTopics, // 不带#号的话题列表
fileList: tab.fileList.map(file => file.path), // 只发送文件路径
accountList: tab.selectedAccounts.map(accountId => {
const account = accountStore.accounts.find(acc => acc.id === accountId)
return account ? account.filePath : accountId
}), // 发送账号的文件路径
enableTimer: tab.scheduleEnabled ? 1 : 0, // 是否启用定时发布,开启传1,不开启传0
videosPerDay: tab.scheduleEnabled ? tab.videosPerDay || 1 : 1, // 每天发布视频数量,1-55
dailyTimes: tab.scheduleEnabled ? tab.dailyTimes || ['10:00'] : ['10:00'], // 每天发布时间点
startDays: tab.scheduleEnabled ? tab.startDays || 0 : 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
category: 0 //表示非原创
}
// 调用后端发布API
fetch(`${apiBaseUrl}/postVideo`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...authHeaders.value
},
body: JSON.stringify(publishData)
})
.then(response => response.json())
.then(data => {
if (data.code === 200) {
tab.publishStatus = {
message: '发布成功',
type: 'success'
}
// 清空当前tab的数据
tab.fileList = []
tab.displayFileList = []
tab.title = ''
tab.selectedTopics = []
tab.selectedAccounts = []
tab.scheduleEnabled = false
resolve()
} else {
tab.publishStatus = {
message: `发布失败:${data.msg || '发布失败'}`,
type: 'error'
}
reject(new Error(data.msg || '发布失败'))
}
})
.catch(error => {
console.error('发布错误:', error)
tab.publishStatus = {
message: '发布失败,请检查网络连接',
type: 'error'
}
reject(error)
})
})
}
@@ -798,92 +872,86 @@ const confirmMaterialSelection = () => {
ElMessage.success(`已添加 ${addedCount} 个素材`)
}
// 批量发布对话框状态
const batchPublishDialogVisible = ref(false)
const currentPublishingTab = ref(null)
const publishProgress = ref(0)
const publishResults = ref([])
const isCancelled = ref(false)
// 取消批量发布
const cancelBatchPublish = () => {
isCancelled.value = true
ElMessage.info('正在取消发布...')
}
// 批量发布方法
const batchPublish = async () => {
if (batchPublishing.value) return
batchPublishing.value = true
batchPublishMessage.value = '开始批量发布...'
batchPublishType.value = 'info'
currentPublishingTab.value = null
publishProgress.value = 0
publishResults.value = []
isCancelled.value = false
batchPublishDialogVisible.value = true
try {
for (let i = 0; i < tabs.length; i++) {
if (isCancelled.value) {
publishResults.value.push({
label: tabs[i].label,
status: 'cancelled',
message: '已取消'
})
continue
}
const tab = tabs[i]
batchPublishMessage.value = `正在发布第 ${i + 1} 个Tab: ${tab.label}`
// 数据验证
if (tab.fileList.length === 0) {
batchPublishMessage.value = `Tab "${tab.label}" 发布失败:请先上传视频文件`
batchPublishType.value = 'error'
break
}
if (!tab.title.trim()) {
batchPublishMessage.value = `Tab "${tab.label}" 发布失败:请输入标题`
batchPublishType.value = 'error'
break
}
if (!tab.selectedPlatform) {
batchPublishMessage.value = `Tab "${tab.label}" 发布失败:请选择发布平台`
batchPublishType.value = 'error'
break
}
if (tab.selectedAccounts.length === 0) {
batchPublishMessage.value = `Tab "${tab.label}" 发布失败:请选择发布账号`
batchPublishType.value = 'error'
break
}
// 构造发布数据
const publishData = {
type: tab.selectedPlatform,
title: tab.title,
tags: tab.selectedTopics,
fileList: tab.fileList.map(file => file.path),
accounts: tab.selectedAccounts,
scheduleEnabled: tab.scheduleEnabled,
videosPerDay: tab.videosPerDay,
dailyTimes: tab.dailyTimes,
startDays: tab.startDays
}
currentPublishingTab.value = tab
publishProgress.value = Math.floor((i / tabs.length) * 100)
try {
// 这里应该调用实际的发布API
// const response = await publishApi.publish(publishData)
// 模拟API调用
await new Promise(resolve => setTimeout(resolve, 1000))
// 模拟随机失败(用于测试)
if (Math.random() < 0.1) {
throw new Error('网络错误')
}
batchPublishMessage.value = `Tab "${tab.label}" 发布成功`
batchPublishType.value = 'success'
await confirmPublish(tab)
publishResults.value.push({
label: tab.label,
status: 'success',
message: '发布成功'
})
} catch (error) {
console.error('发布失败:', error)
batchPublishMessage.value = `Tab "${tab.label}" 发布失败:${error.message || '网络错误'}`
batchPublishType.value = 'error'
break
publishResults.value.push({
label: tab.label,
status: 'error',
message: error.message
})
// 不立即返回,继续显示发布结果
}
}
if (batchPublishType.value === 'success') {
batchPublishMessage.value = '所有Tab发布完成!'
ElMessage.success('批量发布完成')
publishProgress.value = 100
// 统计发布结果
const successCount = publishResults.value.filter(r => r.status === 'success').length
const failCount = publishResults.value.filter(r => r.status === 'error').length
const cancelCount = publishResults.value.filter(r => r.status === 'cancelled').length
if (isCancelled.value) {
ElMessage.warning(`发布已取消:${successCount}个成功,${failCount}个失败,${cancelCount}个未执行`)
} else if (failCount > 0) {
ElMessage.error(`发布完成:${successCount}个成功,${failCount}个失败`)
} else {
ElMessage.success('所有Tab发布成功')
setTimeout(() => {
batchPublishDialogVisible.value = false
}, 1000)
}
} catch (error) {
console.error('批量发布出错:', error)
batchPublishMessage.value = '批量发布出错,请重试'
batchPublishType.value = 'error'
ElMessage.error('批量发布出错,请重试')
} finally {
batchPublishing.value = false
// 5秒后自动清除消息
setTimeout(() => {
batchPublishMessage.value = ''
}, 5000)
isCancelled.value = false
}
}
</script>
@@ -981,13 +1049,59 @@ const batchPublish = async () => {
}
}
// 批量发布状态提示区域
.batch-publish-status {
margin: 10px 20px;
// 批量发布进度对话框样式
.publish-progress {
padding: 20px;
.el-alert {
border-radius: 6px;
.current-publishing {
margin: 15px 0;
text-align: center;
color: #606266;
}
.publish-results {
margin-top: 20px;
border-top: 1px solid #EBEEF5;
padding-top: 15px;
max-height: 300px;
overflow-y: auto;
.result-item {
display: flex;
align-items: center;
padding: 8px 0;
color: #606266;
.el-icon {
margin-right: 8px;
}
.label {
margin-right: 10px;
font-weight: 500;
}
.message {
color: #909399;
}
&.success {
color: #67C23A;
}
&.error {
color: #F56C6C;
}
&.cancelled {
color: #909399;
}
}
}
}
.dialog-footer {
text-align: right;
}
// 内容区域