任务管理
This commit is contained in:
6
src/api/all/assignment-management.ts
Normal file
6
src/api/all/assignment-management.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import Http from '@/api';
|
||||
|
||||
// 获取用户自定义列
|
||||
export const getTaskSchedules = (params = {}) => {
|
||||
return Http.get('/v1/media-accounts/task-schedules', params);
|
||||
};
|
||||
@ -73,6 +73,17 @@ const COMPONENTS: AppRouteRecordRaw[] = [
|
||||
},
|
||||
component: () => import('@/views/property-marketing/media-account/account-dashboard/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'management',
|
||||
name: 'assignmentManagement',
|
||||
meta: {
|
||||
locale: '任务管理',
|
||||
// requiresAuth: true,
|
||||
// requireLogin: true,
|
||||
// roles: ['*'],
|
||||
},
|
||||
component: () => import('@/views/property-marketing/assignment-management/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'detail/:id',
|
||||
name: 'MediaAccountAccountDetails',
|
||||
|
||||
430
src/utils/DateUtils.ts
Normal file
430
src/utils/DateUtils.ts
Normal file
@ -0,0 +1,430 @@
|
||||
/**
|
||||
* 日期工具类
|
||||
* 提供月维度和周维度的开始结束日期获取功能
|
||||
* 周以星期日开始,星期六结束
|
||||
* 只返回日期部分,不包含时间
|
||||
*/
|
||||
class DateUtils {
|
||||
/**
|
||||
* 获取当前时间的月开始日期和结束日期
|
||||
* @returns 包含开始和结束日期的对象
|
||||
*/
|
||||
static getMonthRange(): {
|
||||
start: Date;
|
||||
end: Date;
|
||||
startFormatted: string;
|
||||
endFormatted: string;
|
||||
} {
|
||||
const now = new Date();
|
||||
|
||||
// 月开始日期(当月第一天)
|
||||
const start = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
|
||||
// 月结束日期(当月最后一天)
|
||||
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
||||
end.setHours(0, 0, 0, 0);
|
||||
|
||||
return {
|
||||
start,
|
||||
end,
|
||||
startFormatted: this.formatDate(start),
|
||||
endFormatted: this.formatDate(end),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年份和月的范围
|
||||
* @param year 年份
|
||||
* @param month 月份(1-12)
|
||||
*/
|
||||
static getMonthRangeByYearMonth(
|
||||
year: number,
|
||||
month: number,
|
||||
): {
|
||||
start: Date;
|
||||
end: Date;
|
||||
startFormatted: string;
|
||||
endFormatted: string;
|
||||
} {
|
||||
// 月开始日期
|
||||
const start = new Date(year, month - 1, 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
|
||||
// 月结束日期
|
||||
const end = new Date(year, month, 0);
|
||||
end.setHours(0, 0, 0, 0);
|
||||
|
||||
return {
|
||||
start,
|
||||
end,
|
||||
startFormatted: this.formatDate(start),
|
||||
endFormatted: this.formatDate(end),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间的周范围(以星期日开始)
|
||||
* @returns 包含开始和结束日期的对象
|
||||
*/
|
||||
static getWeekRange(): {
|
||||
start: Date;
|
||||
end: Date;
|
||||
startFormatted: string;
|
||||
endFormatted: string;
|
||||
} {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const dayOfWeek = today.getDay(); // 0是周日,1是周一,...,6是周六
|
||||
|
||||
// 周开始日期(周日)
|
||||
const start = new Date(today);
|
||||
start.setDate(today.getDate() - dayOfWeek);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
|
||||
// 周结束日期(周六)
|
||||
const end = new Date(start);
|
||||
end.setDate(start.getDate() + 6);
|
||||
end.setHours(0, 0, 0, 0);
|
||||
|
||||
return {
|
||||
start,
|
||||
end,
|
||||
startFormatted: this.formatDate(start),
|
||||
endFormatted: this.formatDate(end),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期的周范围
|
||||
* @param date 指定日期
|
||||
*/
|
||||
static getWeekRangeByDate(date: Date): {
|
||||
start: Date;
|
||||
end: Date;
|
||||
startFormatted: string;
|
||||
endFormatted: string;
|
||||
} {
|
||||
const inputDate = new Date(date);
|
||||
inputDate.setHours(0, 0, 0, 0);
|
||||
const dayOfWeek = inputDate.getDay();
|
||||
|
||||
// 周开始日期(周日)
|
||||
const start = new Date(inputDate);
|
||||
start.setDate(inputDate.getDate() - dayOfWeek);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
|
||||
// 周结束日期(周六)
|
||||
const end = new Date(start);
|
||||
end.setDate(start.getDate() + 6);
|
||||
end.setHours(0, 0, 0, 0);
|
||||
|
||||
return {
|
||||
start,
|
||||
end,
|
||||
startFormatted: this.formatDate(start),
|
||||
endFormatted: this.formatDate(end),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期(只返回日期部分)
|
||||
* @param date 日期对象
|
||||
* @returns 格式化后的日期字符串 (YYYY-MM-DD)
|
||||
*/
|
||||
static formatDate(date: Date): string {
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期信息
|
||||
* @returns 包含各种格式的当前日期信息
|
||||
*/
|
||||
static getCurrentDateInfo() {
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
|
||||
const monthRange = this.getMonthRange();
|
||||
const weekRange = this.getWeekRange();
|
||||
|
||||
return {
|
||||
current: {
|
||||
date: now,
|
||||
formatted: this.formatDate(now),
|
||||
dayOfWeek: this.getChineseDayOfWeek(now),
|
||||
},
|
||||
month: {
|
||||
start: monthRange.start,
|
||||
end: monthRange.end,
|
||||
startFormatted: monthRange.startFormatted,
|
||||
endFormatted: monthRange.endFormatted,
|
||||
totalDays: this.getDaysInMonth(now.getFullYear(), now.getMonth() + 1),
|
||||
},
|
||||
week: {
|
||||
start: weekRange.start,
|
||||
end: weekRange.end,
|
||||
startFormatted: weekRange.startFormatted,
|
||||
endFormatted: weekRange.endFormatted,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定月份的天数
|
||||
* @param year 年份
|
||||
* @param month 月份(1-12)
|
||||
* @returns 该月的天数
|
||||
*/
|
||||
static getDaysInMonth(year: number, month: number): number {
|
||||
return new Date(year, month, 0).getDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中文星期几
|
||||
* @param date 日期对象
|
||||
* @returns 中文星期几
|
||||
*/
|
||||
static getChineseDayOfWeek(date: Date): string {
|
||||
const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||||
return days[date.getDay()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中文月份名称
|
||||
* @param month 月份(1-12)
|
||||
* @returns 中文月份名称
|
||||
*/
|
||||
static getChineseMonthName(month: number): string {
|
||||
const months = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
|
||||
return months[month - 1] || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为同一天
|
||||
* @param date1 日期1
|
||||
* @param date2 日期2
|
||||
* @returns 是否为同一天
|
||||
*/
|
||||
static isSameDay(date1: Date, date2: Date): boolean {
|
||||
return this.formatDate(date1) === this.formatDate(date2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期差(天数)
|
||||
* @param date1 日期1
|
||||
* @param date2 日期2
|
||||
* @returns 相差的天数
|
||||
*/
|
||||
static getDaysDifference(date1: Date, date2: Date): number {
|
||||
const d1 = new Date(date1);
|
||||
const d2 = new Date(date2);
|
||||
d1.setHours(0, 0, 0, 0);
|
||||
d2.setHours(0, 0, 0, 0);
|
||||
|
||||
const diffTime = Math.abs(d2.getTime() - d1.getTime());
|
||||
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
/**
|
||||
* 获取当前周的所有日期及星期几
|
||||
* @param startDay 周起始日(0-6,0表示周日,默认1表示周一)
|
||||
* @returns 当前周的日期数组
|
||||
*/
|
||||
static getWeekDaysByDate(targetDate: Date, startDay: number = 1) {
|
||||
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
const currentDay = targetDate.getDay();
|
||||
const firstDayOffset = (currentDay - startDay + 7) % 7;
|
||||
const firstDayOfWeek = new Date(targetDate);
|
||||
firstDayOfWeek.setDate(targetDate.getDate() - firstDayOffset);
|
||||
return Array.from({ length: 7 }).map((_, i) => {
|
||||
const date = new Date(firstDayOfWeek);
|
||||
date.setDate(firstDayOfWeek.getDate() + i);
|
||||
return {
|
||||
date,
|
||||
day: date.getDate(),
|
||||
weekday: weekdays[date.getDay()] + ' ' + date.getDate(),
|
||||
month: date.getMonth() + 1, // 添加月份信息(1-12)
|
||||
year: date.getFullYear(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 获取某个月每一天的星期几
|
||||
static getDaysAndWeekdays(year: number, month: number): Array<{ day: number; weekday: string }> {
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate(); // 获取当月总天数
|
||||
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; // 中文星期数组
|
||||
const days: Array<{ day: number; weekday: string }> = []; // 结果数组
|
||||
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const date = new Date(year, month, day);
|
||||
const weekdayIndex = date.getDay(); // 获取星期几的索引(0-6)
|
||||
days.push({
|
||||
day,
|
||||
weekday: weekdays[weekdayIndex] + ' ' + day,
|
||||
});
|
||||
}
|
||||
|
||||
return days;
|
||||
}
|
||||
/**
|
||||
* 获取当前的年份
|
||||
* @returns 当前年份
|
||||
*/
|
||||
static getCurrentYear(): number {
|
||||
return new Date().getFullYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的月份
|
||||
* @returns 当前月份 (1-12)
|
||||
*/
|
||||
static getCurrentMonth(): number {
|
||||
return new Date().getMonth() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的年份和月份
|
||||
* @returns 包含当前年份和月份的对象
|
||||
*/
|
||||
static getCurrentYearMonth(): { year: number; month: number } {
|
||||
const now = new Date();
|
||||
return {
|
||||
year: now.getFullYear(),
|
||||
month: now.getMonth() + 1,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取格式化的当前年月字符串
|
||||
* @param separator 分隔符,默认为 '-'
|
||||
* @returns 格式化的年月字符串 (YYYY-MM)
|
||||
*/
|
||||
static getFormattedYearMonth(separator: string = '-'): string {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
return `${year}${separator}${month}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中文格式的当前年月
|
||||
* @returns 中文年月字符串 (YYYY年MM月)
|
||||
*/
|
||||
static getChineseYearMonth(): string {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
return `${year}年${month}月`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前季度
|
||||
* @returns 当前季度 (1-4)
|
||||
*/
|
||||
static getCurrentQuarter(): number {
|
||||
const month = new Date().getMonth() + 1;
|
||||
return Math.ceil(month / 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前季度的开始和结束月份
|
||||
* @returns 包含季度开始和结束月份的对象
|
||||
*/
|
||||
static getCurrentQuarterRange(): { startMonth: number; endMonth: number } {
|
||||
const quarter = this.getCurrentQuarter();
|
||||
return {
|
||||
startMonth: (quarter - 1) * 3 + 1,
|
||||
endMonth: quarter * 3,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期信息(增强版,包含年月信息)
|
||||
* @returns 包含各种格式的当前日期信息
|
||||
*/
|
||||
static getCurrentDateInfo() {
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
|
||||
const monthRange = this.getMonthRange();
|
||||
const weekRange = this.getWeekRange();
|
||||
const yearMonth = this.getCurrentYearMonth();
|
||||
|
||||
return {
|
||||
current: {
|
||||
date: now,
|
||||
formatted: this.formatDate(now),
|
||||
dayOfWeek: this.getChineseDayOfWeek(now),
|
||||
day: now.getDate(),
|
||||
month: yearMonth.month,
|
||||
year: yearMonth.year,
|
||||
},
|
||||
month: {
|
||||
start: monthRange.start,
|
||||
end: monthRange.end,
|
||||
startFormatted: monthRange.startFormatted,
|
||||
endFormatted: monthRange.endFormatted,
|
||||
totalDays: this.getDaysInMonth(now.getFullYear(), now.getMonth() + 1),
|
||||
month: yearMonth.month,
|
||||
year: yearMonth.year,
|
||||
formatted: this.getFormattedYearMonth(),
|
||||
chinese: this.getChineseYearMonth(),
|
||||
},
|
||||
week: {
|
||||
start: weekRange.start,
|
||||
end: weekRange.end,
|
||||
startFormatted: weekRange.startFormatted,
|
||||
endFormatted: weekRange.endFormatted,
|
||||
weekNumber: this.getWeekNumber(now),
|
||||
},
|
||||
year: yearMonth.year,
|
||||
quarter: {
|
||||
number: this.getCurrentQuarter(),
|
||||
range: this.getCurrentQuarterRange(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在的周数
|
||||
* @param date 日期对象
|
||||
* @returns 周数 (1-53)
|
||||
*/
|
||||
static getWeekNumber(date: Date): number {
|
||||
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
|
||||
const pastDaysOfYear = (date.getTime() - firstDayOfYear.getTime()) / 86400000;
|
||||
return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年份的所有月份信息
|
||||
* @param year 年份
|
||||
* @returns 包含所有月份信息的数组
|
||||
*/
|
||||
static getYearMonths(year: number): Array<{
|
||||
month: number;
|
||||
name: string;
|
||||
days: number;
|
||||
formatted: string;
|
||||
}> {
|
||||
return Array.from({ length: 12 }, (_, i) => {
|
||||
const month = i + 1;
|
||||
return {
|
||||
month,
|
||||
name: this.getChineseMonthName(month),
|
||||
days: this.getDaysInMonth(year, month),
|
||||
formatted: `${year}-${month.toString().padStart(2, '0')}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
static formatDateToWeekdayDay(date: Date): string {
|
||||
const day = date.getDate();
|
||||
const weekday = this.getChineseDayOfWeek(date).replace('星期', '周');
|
||||
return `${weekday} ${day}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default DateUtils;
|
||||
628
src/views/property-marketing/assignment-management/index.vue
Normal file
628
src/views/property-marketing/assignment-management/index.vue
Normal file
@ -0,0 +1,628 @@
|
||||
<template>
|
||||
<div class="flex-column justify-between">
|
||||
<div class="flex justify-between items-start" style="width: 100%">
|
||||
<div class="flex justify-between items-center" style="width: 100%">
|
||||
<div class="flex items-center">
|
||||
<a-date-picker
|
||||
class="w-188px size-14px"
|
||||
v-if="choseType === '日'"
|
||||
@change="onChangeDate"
|
||||
v-model="dayModel"
|
||||
format="YYYY年MM月DD日周dd"
|
||||
/>
|
||||
<a-week-picker
|
||||
class="w-188px size-14px"
|
||||
v-else-if="choseType === '周'"
|
||||
@change="onChangeWeek"
|
||||
v-model="weekModel"
|
||||
/>
|
||||
<a-month-picker
|
||||
class="w-188px size-14px"
|
||||
v-else
|
||||
@change="onChangeMonth"
|
||||
v-model="monthModel"
|
||||
format="YYYY年MM月"
|
||||
/>
|
||||
<div class="flex items-center ml-12px">
|
||||
<a-button class="mr-4px" @click="handlePrev">
|
||||
<template #icon>
|
||||
<icon-left />
|
||||
</template>
|
||||
</a-button>
|
||||
|
||||
<a-button @click="handleToday">今天</a-button>
|
||||
<a-button class="ml-4px" @click="handleNext">
|
||||
<template #icon>
|
||||
<icon-right />
|
||||
</template>
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="flex items-center ml-12px">
|
||||
<a-space class="flex justify-between">
|
||||
<a-dropdown position="bottom" @select="handleSelect">
|
||||
<a-button class="w-80px flex justify-between">{{ choseType }}<icon-down /></a-button>
|
||||
<template #content>
|
||||
<a-doption value="日" class="w-80px">日</a-doption>
|
||||
<a-doption value="周" class="w-80px">周</a-doption>
|
||||
<a-doption value="月" class="w-80px">月</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start">
|
||||
<a-trigger
|
||||
trigger="click"
|
||||
style="
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
box-shadow: #00000010 0px 2px 8px;
|
||||
width: 120px;
|
||||
height: 64px;
|
||||
padding: 8px;
|
||||
margin-top: 8px;
|
||||
"
|
||||
>
|
||||
<a-button size="small" class="mr-12px">
|
||||
<template #icon>
|
||||
<icon-info-circle-fill size="16" class="color-#55585F" />
|
||||
</template>
|
||||
<template #default>颜色示意</template>
|
||||
</a-button>
|
||||
<template #content>
|
||||
<div class="flex items-center mb-8px">
|
||||
<div
|
||||
style="background-color: #6d4cfe; width: 16px; height: 16px; margin-right: 5px; border-radius: 4px"
|
||||
></div>
|
||||
<div>选题</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
style="background-color: #ffae00; width: 16px; height: 16px; margin-right: 5px; border-radius: 4px"
|
||||
></div>
|
||||
<div>内容稿件</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
|
||||
<a-trigger
|
||||
trigger="click"
|
||||
style="
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
box-shadow: #00000010 0px 2px 8px;
|
||||
width: 308px;
|
||||
height: 180px;
|
||||
padding: 24px;
|
||||
margin-top: 8px;
|
||||
"
|
||||
>
|
||||
<a-button size="small">
|
||||
<template #icon>
|
||||
<icon-filter size="16" class="color-#55585F" />
|
||||
</template>
|
||||
<template #default>筛选</template>
|
||||
</a-button>
|
||||
<template #content>
|
||||
<div>
|
||||
<div class="flex items-center mb-24px">
|
||||
<div class="w-70px">运营人员</div>
|
||||
<a-space class="w-200px">
|
||||
<CommonSelect
|
||||
:multiple="false"
|
||||
:options="operators"
|
||||
v-model="query.operator_id"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="flex items-center mb-24px">
|
||||
<div class="w-70px">发布平台</div>
|
||||
<a-space class="w-200px">
|
||||
<CommonSelect
|
||||
:multiple="false"
|
||||
:options="platformOptions"
|
||||
v-model="query.platform"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="w-70px">账号名称</div>
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
:style="{ width: '200px' }"
|
||||
placeholder="输入账号名称"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-start mt-16px" style="width: 100%">
|
||||
<a-table :columns="columns" :data="data" :bordered="{ cell: true }" style="width: 100%" :pagination="false">
|
||||
<template #name="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
:src="getPlatformIcon(record.platform)"
|
||||
style="border-radius: 8px; width: 16px; height: 16px; margin-right: 8px"
|
||||
/>
|
||||
{{ record.name || '-' }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 动态日期列渲染 -->
|
||||
<template #dateCell="{ record, column }">
|
||||
<div v-if="record[column.dataIndex] && record[column.dataIndex].length > 0" class="task-container">
|
||||
<div v-if="record[column.dataIndex].length >= 3" class="task-more" @click="handleMore(record, column)">
|
||||
<div
|
||||
:key="record[column.dataIndex][0].id"
|
||||
class="task-item size-12px"
|
||||
:title="record[column.dataIndex][0].name || '-'"
|
||||
>
|
||||
<div class="size-12px color-#211F24 mr-4px">
|
||||
{{ timestampToTime(record[column.dataIndex][0].execution_time) }}
|
||||
</div>
|
||||
<div :style="{ color: getTaskColor(record[column.dataIndex][0].type) }">
|
||||
{{ formatTaskName(record[column.dataIndex][0].name) }}{{ record[column.dataIndex][0].type }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="size-12px color-#8f959f" style="padding: 0px 8px">
|
||||
还有{{ record[column.dataIndex].length - 1 }}项
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
v-for="task in record[column.dataIndex]"
|
||||
:key="task.id"
|
||||
class="task-item"
|
||||
:title="task.name || '-'"
|
||||
>
|
||||
<div class="size-12px color-#211F24 mr-4px">
|
||||
{{ timestampToTime(record[column.dataIndex][0].execution_time) }}
|
||||
</div>
|
||||
<div :style="{ color: getTaskColor(task.type) }">
|
||||
{{ formatTaskName(record[column.dataIndex][0].name) }}{{ record[column.dataIndex][0].type }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-task"></div>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, onMounted, watch, computed } from 'vue';
|
||||
import { getTaskSchedules } from '@/api/all/assignment-management';
|
||||
import { fetchAccountOperators } from '@/api/all/propertyMarketing';
|
||||
|
||||
import icon1 from '@/assets/img/platform/icon-dy.png';
|
||||
import icon2 from '@/assets/img/platform/icon-xhs.png';
|
||||
import icon3 from '@/assets/img/media-account/icon-warn.png';
|
||||
import icon4 from '@/assets/img/platform/icon-sph.png';
|
||||
import icon5 from '@/assets/img/platform/icon-wb.png';
|
||||
import icon6 from '@/assets/img/platform/icon-gzh.png';
|
||||
import icon7 from '@/assets/img/platform/icon-ks.png';
|
||||
import icon8 from '@/assets/img/platform/icon-bilibili.png';
|
||||
import DateUtils from '@/utils/DateUtils';
|
||||
|
||||
const choseType = ref('周');
|
||||
const currentDateRange = reactive({
|
||||
start: '',
|
||||
end: '',
|
||||
});
|
||||
const weekModel = ref(DateUtils.formatDate(new Date()));
|
||||
const dayModel = ref(DateUtils.formatDate(new Date()));
|
||||
const monthModel = ref(DateUtils.formatDate(new Date()));
|
||||
|
||||
const columns = ref([]);
|
||||
const data = ref([]);
|
||||
const operators = ref([]);
|
||||
const platformOptions = ref([
|
||||
{ value: 0, label: '抖音' },
|
||||
{ value: 1, label: '小红书' },
|
||||
{ value: 2, label: 'B站' },
|
||||
{ value: 3, label: '快手' },
|
||||
{ value: 4, label: '视频号' },
|
||||
{ value: 5, label: '微博' },
|
||||
{ value: 6, label: '公众号' },
|
||||
]);
|
||||
|
||||
const pageInfo = reactive({
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const query = reactive({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
platform: '',
|
||||
operator_id: undefined,
|
||||
name: '',
|
||||
execution_time: [] as string[],
|
||||
});
|
||||
|
||||
const handleMore = (record: any[], column: number) => {
|
||||
console.log('record', record);
|
||||
console.log('column', column);
|
||||
console.log('data', record[column.dataIndex]);
|
||||
};
|
||||
|
||||
// 计算当前日期范围内的所有日期,统一返回 number 数组
|
||||
const currentDateHeaders = computed(() => {
|
||||
if (choseType.value === '周') {
|
||||
const specificWeek = DateUtils.getWeekDaysByDate(new Date(currentDateRange.start || new Date().toString()), 0);
|
||||
return specificWeek.map((item) => parseInt(item.day, 10)); // 转换为数字数组
|
||||
} else if (choseType.value === '月') {
|
||||
const currentYearMonth = DateUtils.getCurrentYearMonth();
|
||||
const tabTitle = DateUtils.getDaysAndWeekdays(currentYearMonth.year, currentYearMonth.month);
|
||||
return tabTitle.map((item) => parseInt(item.day, 10)); // 转换为数字数组
|
||||
} else {
|
||||
// 日维度,返回当天的日期数字
|
||||
const day = new Date(dayModel.value).getDate();
|
||||
return [day];
|
||||
}
|
||||
});
|
||||
|
||||
// 获取平台图标
|
||||
const getPlatformIcon = (platform: number) => {
|
||||
const platformIcons: Record<number, any> = {
|
||||
0: icon1, // 抖音
|
||||
1: icon2, // 小红书
|
||||
2: icon8, // B站
|
||||
3: icon7, // 快手
|
||||
4: icon4, // 视频号
|
||||
5: icon5, // 微博
|
||||
6: icon6, // 公众号
|
||||
};
|
||||
|
||||
return platformIcons[platform] || icon3; // 默认图标
|
||||
};
|
||||
|
||||
// 获取任务颜色
|
||||
const getTaskColor = (taskType: number) => {
|
||||
console.log('taskType', taskType);
|
||||
// 根据API文档,type: 0=选题,1=内容稿件
|
||||
return taskType === 0 ? '#6d4cfe' : '#ffae00';
|
||||
};
|
||||
|
||||
// 格式化任务名称
|
||||
const formatTaskName = (name: string) => {
|
||||
if (!name) return '未命名';
|
||||
return name.length > 8 ? name.substring(0, 8) + '...' : name;
|
||||
};
|
||||
|
||||
// 时间戳转日期格式,并提取日期数字
|
||||
const timestampToDayNumber = (timestamp: number) => {
|
||||
const date = new Date(timestamp * 1000); // 假设时间戳是秒级
|
||||
return parseInt(date.getDate().toString().padStart(2, '0')); // 返回 '01', '02', ..., '31'
|
||||
};
|
||||
|
||||
// 时间戳转时间格式 (HH:MM)
|
||||
const timestampToTime = (timestamp: number): string => {
|
||||
const date = new Date(timestamp * 1000); // 假设时间戳是秒级
|
||||
|
||||
// 获取小时和分钟
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
|
||||
return `${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
// 处理表格数据,使其与动态表头匹配
|
||||
const processTableData = (apiData: any[]) => {
|
||||
const processedData: any[] = [];
|
||||
|
||||
// 处理每条账号数据
|
||||
apiData.forEach((account) => {
|
||||
const rowData: any = {
|
||||
id: account.id,
|
||||
name: account.name,
|
||||
platform: account.platform,
|
||||
};
|
||||
|
||||
// 初始化所有日期列为空数组
|
||||
currentDateHeaders.value.forEach((day) => {
|
||||
rowData[day] = [];
|
||||
});
|
||||
|
||||
// 将任务按日期分组
|
||||
if (account.task_schedules && account.task_schedules.length > 0) {
|
||||
account.task_schedules.forEach((task: any) => {
|
||||
const taskDay = timestampToDayNumber(task.execution_time);
|
||||
console.log('taskDay', taskDay, typeof taskDay);
|
||||
console.log('currentDateHeaders', currentDateHeaders.value);
|
||||
console.log('rowData', currentDateHeaders.value.includes(taskDay));
|
||||
// 如果这个日期在当前表头中,则添加到对应列
|
||||
if (currentDateHeaders.value.includes(taskDay)) {
|
||||
console.log('taskDay', task);
|
||||
rowData[taskDay].push({
|
||||
id: task.id,
|
||||
name: task.name,
|
||||
type: task.type,
|
||||
execution_time: task.execution_time,
|
||||
});
|
||||
console.log('taskDay', rowData[taskDay]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processedData.push(rowData);
|
||||
});
|
||||
|
||||
return processedData;
|
||||
};
|
||||
|
||||
// 设置日期范围
|
||||
const setDateRange = () => {
|
||||
if (choseType.value === '周') {
|
||||
const weekRange = DateUtils.getWeekRangeByDate(new Date(weekModel.value));
|
||||
currentDateRange.start = weekRange.startFormatted;
|
||||
currentDateRange.end = weekRange.endFormatted;
|
||||
query.execution_time = [currentDateRange.start, currentDateRange.end];
|
||||
} else if (choseType.value === '月') {
|
||||
const monthRange = DateUtils.getMonthRangeByYearMonth(
|
||||
new Date(monthModel.value).getFullYear(),
|
||||
new Date(monthModel.value).getMonth() + 1
|
||||
);
|
||||
currentDateRange.start = monthRange.startFormatted;
|
||||
currentDateRange.end = monthRange.endFormatted;
|
||||
query.execution_time = [currentDateRange.start, currentDateRange.end];
|
||||
} else {
|
||||
// 日维度
|
||||
currentDateRange.start = dayModel.value;
|
||||
currentDateRange.end = dayModel.value;
|
||||
query.execution_time = [currentDateRange.start, currentDateRange.end];
|
||||
}
|
||||
};
|
||||
|
||||
// 设置table的头部
|
||||
const setTableSpecific = () => {
|
||||
columns.value = [
|
||||
{
|
||||
title: '账号与发布平台',
|
||||
slotName: 'name',
|
||||
width: 150,
|
||||
minWidth: 100,
|
||||
fixed: 'left',
|
||||
},
|
||||
];
|
||||
|
||||
let dateHeaders: any[] = [];
|
||||
|
||||
if (choseType.value === '周') {
|
||||
const specificWeek = DateUtils.getWeekDaysByDate(new Date(currentDateRange.start || new Date().toString()), 0);
|
||||
dateHeaders = specificWeek;
|
||||
} else if (choseType.value === '月') {
|
||||
const currentYearMonth = DateUtils.getCurrentYearMonth();
|
||||
const tabTitle = DateUtils.getDaysAndWeekdays(currentYearMonth.year, currentYearMonth.month);
|
||||
dateHeaders = tabTitle;
|
||||
} else {
|
||||
// 日维度
|
||||
const date = new Date(dayModel.value);
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const weekday = DateUtils.formatDateToWeekdayDay(date);
|
||||
dateHeaders = [{ day, weekday }];
|
||||
}
|
||||
|
||||
// 添加日期列
|
||||
dateHeaders.forEach((item) => {
|
||||
columns.value.push({
|
||||
title: `${item.weekday}`,
|
||||
dataIndex: item.day, // 使用日期数字作为dataIndex
|
||||
key: item.day,
|
||||
slotName: 'dateCell',
|
||||
width: 135,
|
||||
minWidth: 100,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 日期变化处理
|
||||
const onChangeDate = (val: any) => {
|
||||
if (val) {
|
||||
dayModel.value = DateUtils.formatDate(new Date(val));
|
||||
setDateRange();
|
||||
setTableSpecific();
|
||||
handleSearch();
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeWeek = (val: any) => {
|
||||
console.log('onChangeWeek val', val);
|
||||
if (val) {
|
||||
const weekRange = DateUtils.getWeekRange(new Date(val));
|
||||
console.log('weekRange', weekRange);
|
||||
currentDateRange.start = weekRange.startFormatted;
|
||||
currentDateRange.end = weekRange.endFormatted;
|
||||
query.execution_time = [currentDateRange.start, currentDateRange.end];
|
||||
weekModel.value = val;
|
||||
setTableSpecific();
|
||||
handleSearch();
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeMonth = (val: any) => {
|
||||
console.log('val', val);
|
||||
if (val) {
|
||||
const monthRange = DateUtils.getMonthRange(new Date(val));
|
||||
currentDateRange.start = monthRange.startFormatted;
|
||||
currentDateRange.end = monthRange.endFormatted;
|
||||
query.execution_time = [currentDateRange.start, currentDateRange.end];
|
||||
const date = new Date(val);
|
||||
monthModel.value = val;
|
||||
setTableSpecific();
|
||||
handleSearch();
|
||||
}
|
||||
};
|
||||
|
||||
// 设置维度
|
||||
const handleSelect = (val: string) => {
|
||||
choseType.value = val;
|
||||
setDateRange();
|
||||
setTableSpecific();
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
// 日期导航
|
||||
const handlePrev = () => {
|
||||
// 根据当前维度向前导航
|
||||
if (choseType.value === '周') {
|
||||
const prevWeek = new Date(weekModel.value);
|
||||
prevWeek.setDate(prevWeek.getDate() - 7);
|
||||
onChangeWeek(DateUtils.formatDate(prevWeek, false));
|
||||
} else if (choseType.value === '月') {
|
||||
const prevMonth = new Date(monthModel.value);
|
||||
prevMonth.setMonth(prevMonth.getMonth() - 1);
|
||||
onChangeMonth(DateUtils.formatDate(prevMonth, false));
|
||||
} else {
|
||||
const prevDay = new Date(dayModel.value);
|
||||
prevDay.setDate(prevDay.getDate() - 1);
|
||||
onChangeDate(DateUtils.formatDate(prevDay, false));
|
||||
}
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
// 根据当前维度向后导航
|
||||
if (choseType.value === '周') {
|
||||
const nextWeek = new Date(weekModel.value);
|
||||
nextWeek.setDate(nextWeek.getDate() + 7);
|
||||
onChangeWeek(DateUtils.formatDate(nextWeek, false));
|
||||
} else if (choseType.value === '月') {
|
||||
const nextMonth = new Date(monthModel.value);
|
||||
nextMonth.setMonth(nextMonth.getMonth() + 1);
|
||||
onChangeMonth(DateUtils.formatDate(nextMonth, false));
|
||||
} else {
|
||||
const nextDay = new Date(dayModel.value);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
onChangeDate(DateUtils.formatDate(nextDay, false));
|
||||
}
|
||||
};
|
||||
|
||||
const handleToday = () => {
|
||||
// 回到今天
|
||||
const today = new Date();
|
||||
if (choseType.value === '周') {
|
||||
onChangeWeek(DateUtils.formatDate(today, false));
|
||||
} else if (choseType.value === '月') {
|
||||
onChangeMonth(DateUtils.formatDate(today, false));
|
||||
} else {
|
||||
onChangeDate(DateUtils.formatDate(today, false));
|
||||
}
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const handleSearch = () => {
|
||||
query.page = pageInfo.page;
|
||||
query.page_size = pageInfo.page_size;
|
||||
console.log('query', query);
|
||||
getTaskSchedules(query)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
// 根据API响应结构调整
|
||||
const apiData = response.data.data || response.data;
|
||||
data.value = processTableData(apiData);
|
||||
pageInfo.total = response.data.total || apiData.length;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取任务排期数据失败:', error);
|
||||
data.value = [];
|
||||
});
|
||||
};
|
||||
|
||||
// 获取运营人员
|
||||
const getOperators = async () => {
|
||||
try {
|
||||
const { code, data: operatorsData } = await fetchAccountOperators();
|
||||
if (code === 200) {
|
||||
operators.value = operatorsData.map((op: any) => ({
|
||||
value: op.id,
|
||||
label: op.name,
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取运营人员数据失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 监听日期维度变化
|
||||
watch(choseType, (newVal) => {
|
||||
setDateRange();
|
||||
setTableSpecific();
|
||||
handleSearch();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setDateRange();
|
||||
setTableSpecific();
|
||||
handleSearch();
|
||||
getOperators();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.content {
|
||||
background: white;
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.arco-dropdown-open .arco-icon-down {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.task-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
line-height: 1.4;
|
||||
word-break: break-word;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.task-item:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.no-task {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.tip-trigger {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
}
|
||||
.tip-trigger:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
@ -40,7 +40,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
// 目标地址
|
||||
target: 'https://lingjiapi.lvfunai.com/api',
|
||||
// target: 'https://lingjiapi.lvfunai.com/api',
|
||||
target: 'http://192.168.40.7/api',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user