Files
lingji-work-fe/src/views/property-marketing/assignment-management/components/task-item.vue

389 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-trigger
trigger="click"
position="br"
@click.stop
@popup-visible-change="onPopupVisibleChange"
v-model:popup-visible="popupVisible"
>
<div class="task-item">
<div class="color-indicator" :style="{ background: getTaskColor() }"></div>
<div>{{ timestampToTime(task.execution_time) }}</div>
<div class="task-name" :title="task?.name || '-'">{{ task?.name || 'AI生成内容' }}</div>
</div>
<template #content>
<div class="flex flex-col items-start popup-content" @click="gotoDetail">
<div class="flex flex-col items-start p-16px w-full" @click="gotoDetail">
<div class="flex justify-between w-full items-center">
<div class="flex items-center title-container">
<img
:src="getPlatformIcon(record.platform)"
style="border-radius: 8px; width: 16px; height: 16px; margin-right: 8px; font-size: 14px"
/>
<div class="task-title" :title="record.name || 'AI生成内容'">{{ record.name || 'AI生成内容' }}</div>
</div>
<div
class="status-tag"
:style="{
color: getTaskColor(),
backgroundColor: getTaskColor() + '50',
}"
>
{{ getTaskStatusText(task.status) }}
</div>
</div>
<div class="text-12px color-#939499 mt-4px h-22px" @click="gotoDetail">
{{ timestampToTime1(task.execution_time) }}
</div>
</div>
<div class="font-size-14px color-#211F24 color-#211F24 task-description" :title="task.name || 'AI生成内容'">
{{ task.name || 'AI生成内容' }}
</div>
<div v-if="task.ai_generate_status == 1" class="AILoding">
<ASpin />
<div style="color: #9a56ba">内容生成中...</div>
<div style="color: #9a56ba">完成后将自动展示您可先返回其他操作</div>
</div>
<div v-else-if="taskDetail" class="w-full pl-16px">
<div
v-for="item in choseTextArray"
:key="item.id"
class="flex items-center bg-#F7F8FA border-rounded-8px w-full justify-items-center pt-8px pb-8px pl-12px pr-12px mb-16px"
>
{{ item }}
</div>
<div class="flex items-center w-full">
<img
v-for="item in choseImgArray"
:key="item.id"
:src="item.cover || item.url"
class="w-88 h-88 mr-8px border-rounded-8px"
/>
</div>
<div class="flex items-center w-full">
<video
v-for="item in choseVideoArray"
:key="item.id"
:src="item.cover || item.url"
class="w-44 h-44 mr-8px border-rounded-8px object-fit-contain"
/>
</div>
</div>
<div class="flex flex-col w-full" v-if="task.status != 2">
<div class="flex items-center mt-12px w-full h-1px bg-#E6E6E8"></div>
<div class="flex items-center mt-12px mb-16px action-buttons w-full px-16px">
<div
class="flex items-center mr-12px"
@click.stop="handleDelete"
v-if="task.status == 0 || (task.status == 1 && task.ai_generate_status != 1)"
>
<icon-delete style="font-size: 20px; margin-left: 0" />
</div>
<div
class="flex w-full"
:class="{ 'justify-between': task.ai_generate_status == 0 }"
v-if="task.status == 0"
>
<button class="opt-btn flex-1" @click.stop="handleEditTask">修改任务</button>
<button
v-if="task.ai_generate_status == 0 && task.status != 3"
class="opt-btn ml-12px opt-right"
@click.stop="handleAICreate"
>
AI立即生成
</button>
</div>
<div class="flex w-full" :class="{ 'justify-between': task.ai_generate_status == 0 }" v-else>
<button
v-if="task.ai_generate_status == 0 && task.status != 3"
class="opt-btn flex-1"
@click.stop="handleAICreate"
>
删除任务
</button>
<button v-else class="opt-btn flex-1" @click.stop="handleEditTask">修改任务</button>
</div>
</div>
</div>
</div>
</template>
</a-trigger>
</template>
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { Spin as ASpin } from 'ant-design-vue';
import dayjs from 'dayjs';
import iconDy from '@/assets/img/platform/icon-dy.png';
import iconXhs from '@/assets/img/platform/icon-xhs.png';
import iconBilibili from '@/assets/img/platform/icon-bilibili.png';
import iconKs from '@/assets/img/platform/icon-ks.png';
import iconSph from '@/assets/img/platform/icon-sph.png';
import iconWb from '@/assets/img/platform/icon-wb.png';
import iconGzh from '@/assets/img/platform/icon-gzh.png';
import iconWarn from '@/assets/img/media-account/icon-warn.png';
import { getTaskSchedulesDetail } from '@/api/all/assignment-management';
// 定义props和emit
const props = defineProps({
task: Object,
record: Object,
});
const taskDetail = ref(null);
const choseImgArray = ref([]);
const choseTextArray = ref([]);
const choseVideoArray = ref([]);
const getTaskDetail = async () => {
if (!props.task || !props.task.id) return;
try {
const res = await getTaskSchedulesDetail(props.task.id);
if (res && res.data) {
datePickerValue.value = dayjs(res.data.execution_time * 1000);
console.log('任务详情:', datePickerValue.value);
if ('work' in res.data && res.data.work) {
taskDetail.value = res.data.work;
choseImgArray.value = res.data.work.files.filter((item) => [0].includes(item.type));
choseTextArray.value = res.data.work.files.filter((item) => [2].includes(item.type));
choseVideoArray.value = res.data.work.files.filter((item) => [1].includes(item.type));
} else {
taskDetail.value = res.data.raw_materials;
choseImgArray.value = taskDetail.value.filter((item) => [0].includes(item.type));
choseTextArray.value = taskDetail.value.filter((item) => [2].includes(item.type));
choseVideoArray.value = taskDetail.value.filter((item) => [1].includes(item.type));
}
}
} catch (error) {
console.error('获取任务详情失败:', error);
}
};
const onChange = (date, dateString) => {
console.log('Selected Date: ', date, dateString);
};
const onOk = (value) => {
console.log('DatePicker OK: ', value);
if (value) {
emit('handle-task', 'edit-time', props.task, value);
}
};
const onPopupVisibleChange = (visible) => {
popupVisible.value = visible;
if (visible) {
getTaskDetail();
}
};
const handleDelete = () => {
emit('handle-task', 'delete', props.task, props.record);
};
const gotoDetail = () => {
console.log('跳转详情');
emit('handle-task', 'goto-detail', props.task, props.record);
};
const handleAICreate = () => {
emit('handle-task', 'ai-create', props.task, props.record);
};
const handleEditTask = () => {
// 关闭当前弹窗
popupVisible.value = false;
emit('handle-task', 'edit-task', props.task, props.record);
};
const timestampToTime = (timestamp: number): string => {
// 如果没有传入时间戳,则返回空字符串
if (!timestamp) return '';
// 将时间戳转换为毫秒(如果时间戳是秒单位的话)
const date = new Date(timestamp * 1000);
// 格式化为 HH:mm 格式
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
};
const timestampToTime1 = (timestamp: number): string => {
// 如果没有传入时间戳,则使用当前时间
if (!timestamp) {
timestamp = Date.now() / 1000; // 使用秒级时间戳保持一致性
}
const date = new Date(timestamp * 1000);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 补零
const day = String(date.getDate()).padStart(2, '0'); // 补零
return `${month}${day}`;
};
const emit = defineEmits(['filter-change', 'handle-task']);
// 添加控制弹窗显示的响应式变量
const popupVisible = ref(false);
// 日期选择器的值
const datePickerValue = ref(null);
// 平台配置
const platformConfig = {
icons: {
0: iconDy,
1: iconXhs,
2: iconBilibili,
3: iconKs,
4: iconSph,
5: iconWb,
6: iconGzh,
},
};
// 获取平台图标
const getPlatformIcon = (platform: number) => platformConfig.icons[platform] || iconWarn;
// 根据任务类型获取颜色
const getTaskColor = () => {
if (!props.task) return '#000';
// 根据colorTip.vue中的颜色定义设置不同状态的颜色
switch (props.task.status) {
case 0: // 待生成
return '#ffae00';
case 1: // 待发布
return '#6d4cfe';
case 2: // 已发布
return '#939499';
case 3: // 发布失败
return '#f64b31';
default:
return props.task.color || '#939499';
}
};
const getTaskStatusText = (status) => {
console.log('任务状态:', status);
switch (status) {
case 0:
return '待生成';
case 1:
return '待发布';
case 2:
return '已发布';
case 3:
return '发布失败';
default:
return '未知状态';
}
};
</script>
<style lang="less" scoped>
.task-item {
width: 100%;
font-size: 12px;
height: 19px;
display: flex;
align-items: center;
gap: 4px;
min-width: 0;
&:last-child {
margin-bottom: 0;
}
}
.color-indicator {
width: 4px;
height: 18px;
border-radius: 2px;
flex-shrink: 0;
}
.task-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
width: 0;
}
.popup-content {
width: 388px;
background-color: #fff;
box-shadow: #e6e6e8 0px 2px 8px;
border-radius: 4px;
}
.title-container {
flex: 1;
min-width: 0;
}
.task-title {
font-size: 16px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
line-height: 1.2;
}
.task-description {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
flex: 1;
min-width: 0;
width: 365px;
margin-top: -10px;
margin-bottom: 12px;
padding: 0 16px;
}
.status-tag {
padding: 2px 8px;
border-radius: 4px;
flex-shrink: 0;
}
.opt-btn {
width: 154px;
height: 32px;
font-size: 14px;
background: #f2f3f5;
border: none;
border-radius: 4px;
}
.opt-right {
background: linear-gradient(90deg, #fbf9ff 0%, #f3fafe 100%);
color: #9a56ba;
}
.AILoding {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 356px;
height: 108px;
border-radius: 8px;
background: linear-gradient(90deg, #fbf9ff 0%, #f3fafe 100%);
color: linear-gradient(90deg, #9a56ba 0%, #576fd1 100%);
margin-left: 16px;
font-weight: 400;
font-style: Regular;
font-size: 12px;
leading-trim: NONE;
line-height: 20px;
letter-spacing: 0%;
text-align: center;
}
</style>