diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4804332..195baf5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5554,7 +5554,7 @@ packages: eslint: '>=6.0.0' vue-lazyload@3.0.0: - resolution: {integrity: sha512-h2keL/Rj550dLgesgOtXJS9qOiSMmuJNeVlfNAYV1/IYwOQYaWk5mFJlwRxmZDK9YC5gECcFLYYj7z1lKSf9ug==, tarball: https://registry.npmmirror.com/vue-lazyload/-/vue-lazyload-3.0.0.tgz} + resolution: {integrity: sha512-h2keL/Rj550dLgesgOtXJS9qOiSMmuJNeVlfNAYV1/IYwOQYaWk5mFJlwRxmZDK9YC5gECcFLYYj7z1lKSf9ug==} vue-router@4.5.1: resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==} diff --git a/src/App.vue b/src/App.vue index 3db5a4f..5b115e0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -35,7 +35,6 @@ const redTheme = { const init = async () => { const { isLogin } = userStore; - // 已开通 if (isLogin) { await initApp(); @@ -49,7 +48,6 @@ const init = async () => { onMounted(() => { init(); - // 监听全局未处理错误 window.addEventListener('unhandledrejection', (event) => { event.preventDefault(); diff --git a/src/api/all/assignment-management.ts b/src/api/all/assignment-management.ts new file mode 100644 index 0000000..f9aa270 --- /dev/null +++ b/src/api/all/assignment-management.ts @@ -0,0 +1,39 @@ +import Http from '@/api'; + +// 任务管理-分页 +export const getTaskSchedules = (params = {}) => { + return Http.get('/v1/media-accounts/task-schedules', params); +}; + +// 任务管理-删除 +export const delTaskSchedules = (id: string) => { + console.log('id', id); + return Http.delete(`/v1/task-schedules/${id}`); +}; + +// 任务管理-修改 +export const editTaskSchedules = (id: string, params = {}) => { + console.log('id', id); + return Http.put(`/v1/task-schedules/${id}`, params); +}; + +// 任务管理-详情 +export const getTaskSchedulesDetail = (id: string) => { + console.log('id', id); + return Http.get(`/v1/task-schedules/${id}`); +}; +//任务管理-手动添加 +export const createTask = (params = {}) => { + return Http.post(`/v1/task-schedules/manual`, params); +}; + +//任务管理-手动添加 +export const generateContent = (id: string) => { + return Http.post(`/v1/task-schedules/${id}/generate-content`); +}; + +// 任务管理-修改 +export const editTaskSchedulesTime = (id: string, params = {}) => { + console.log('id', id); + return Http.patch(`/v1/task-schedules/${id}/execution-time`, params); +}; diff --git a/src/assets/img/media-account/icon-AI.png b/src/assets/img/media-account/icon-AI.png new file mode 100644 index 0000000..795b3bb Binary files /dev/null and b/src/assets/img/media-account/icon-AI.png differ diff --git a/src/assets/img/platform/icon-TikTok.png b/src/assets/img/platform/icon-TikTok.png new file mode 100644 index 0000000..3b20c75 Binary files /dev/null and b/src/assets/img/platform/icon-TikTok.png differ diff --git a/src/assets/img/platform/icon-bilibili.png b/src/assets/img/platform/icon-bilibili.png new file mode 100644 index 0000000..51177d8 Binary files /dev/null and b/src/assets/img/platform/icon-bilibili.png differ diff --git a/src/assets/img/platform/icon-gzh.png b/src/assets/img/platform/icon-gzh.png new file mode 100644 index 0000000..8db8a10 Binary files /dev/null and b/src/assets/img/platform/icon-gzh.png differ diff --git a/src/assets/img/platform/icon-ks.png b/src/assets/img/platform/icon-ks.png new file mode 100644 index 0000000..660ff80 Binary files /dev/null and b/src/assets/img/platform/icon-ks.png differ diff --git a/src/assets/img/platform/icon-sph.png b/src/assets/img/platform/icon-sph.png new file mode 100644 index 0000000..d50db1c Binary files /dev/null and b/src/assets/img/platform/icon-sph.png differ diff --git a/src/assets/img/platform/icon-wb.png b/src/assets/img/platform/icon-wb.png new file mode 100644 index 0000000..53b820d Binary files /dev/null and b/src/assets/img/platform/icon-wb.png differ diff --git a/src/components/common-select/index.vue b/src/components/common-select/index.vue index 47f04bf..2ca73d2 100644 --- a/src/components/common-select/index.vue +++ b/src/components/common-select/index.vue @@ -11,20 +11,35 @@ :allowClear="allClear" :showSearch="allowSearch" showArrow - :maxTagCount="maxTagCount" + :maxTagCount="maxTagCount !== undefined ? maxTagCount : multiple ? 3 : undefined" @change="handleChange" @dropdownVisibleChange="onDropdownVisibleChange" + :filterOption="allowSearch ? filterOption : undefined" > - + + + + diff --git a/src/components/filter-popup/index.vue b/src/components/filter-popup/index.vue new file mode 100644 index 0000000..435a0f9 --- /dev/null +++ b/src/components/filter-popup/index.vue @@ -0,0 +1,115 @@ + + + + + + \ No newline at end of file diff --git a/src/hooks/useTableSelectionWithPagination.ts b/src/hooks/useTableSelectionWithPagination.ts index ebc6b22..563f9b7 100644 --- a/src/hooks/useTableSelectionWithPagination.ts +++ b/src/hooks/useTableSelectionWithPagination.ts @@ -1,7 +1,10 @@ import { ref, computed } from 'vue'; +import { merge } from 'lodash-es'; +import { cloneDeep } from 'lodash-es'; interface UseTableSelectionWithPaginationOptions { rowKey?: string; // 主键字段名,默认 'id' + type?: 'checkbox' | 'radio'; // 选择类型,默认 'checkbox' pageInfo?: { page?: number; page_size?: number; @@ -20,6 +23,7 @@ const DEFAULT_PAGE_INFO = { export function useTableSelectionWithPagination(options: UseTableSelectionWithPaginationOptions = {}) { const rowKey = options.rowKey || 'id'; + const type = options.type || 'checkbox'; // 默认为复选框 const selectedRowKeys = ref>([]); const selectedRows = ref>([]); @@ -31,12 +35,24 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa // 单行选择 const handleSelect = (record: any, select: boolean) => { const _targetKey = record[rowKey]; - if (select) { - selectedRows.value.push(record); - selectedRowKeys.value.push(_targetKey); + if (type === 'radio') { + // 单选模式 + if (select) { + selectedRows.value = [record]; + selectedRowKeys.value = [_targetKey]; + } else { + selectedRows.value = []; + selectedRowKeys.value = []; + } } else { - selectedRows.value = selectedRows.value.filter((v) => v[rowKey] !== _targetKey); - selectedRowKeys.value = selectedRowKeys.value.filter((key) => key !== _targetKey); + // 多选模式(默认) + if (select) { + selectedRows.value.push(record); + selectedRowKeys.value.push(_targetKey); + } else { + selectedRows.value = selectedRows.value.filter((v) => v[rowKey] !== _targetKey); + selectedRowKeys.value = selectedRowKeys.value.filter((key) => key !== _targetKey); + } } options.onSelectChange?.(); @@ -44,6 +60,9 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa // 全选/取消全选 const handleSelectAll = (checked: boolean) => { + // 单选模式下不支持全选 + if (type === 'radio') return; + const currentPageRows = dataSource.value; const currentPageKeys = currentPageRows.map((v) => v[rowKey]); @@ -60,26 +79,44 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa options.onSelectChange?.(); }; + // 选择变更处理 + const handleSelectChange = (keys: Array, rows: Array) => { + if (type === 'radio') { + // 单选模式下只保留最后一个选择 + selectedRowKeys.value = keys.length > 0 ? [keys[keys.length - 1]] : []; + selectedRows.value = rows.length > 0 ? [rows[rows.length - 1]] : []; + } else { + // 多选模式 + selectedRowKeys.value = keys; + selectedRows.value = rows; + } + options.onSelectChange?.(); + }; + const onPageChange = (page: number, pageSize: number) => { // console.log('onPageChange', page, pageSize); pageInfo.value.page = page; pageInfo.value.page_size = pageSize; options.onPageChange?.(page); }; + const onPageSizeChange = (current: number, size: number) => { // console.log('onPageSizeChange', current, size); // pageInfo.value.page_size = size; // pageInfo.value.page = 1; // options.onPageSizeChange?.(size); }; + const resetPageInfo = () => { pageInfo.value = cloneDeep(DEFAULT_PAGE_INFO); }; const rowSelection = computed(() => ({ - type: 'checkbox', - showCheckedAll: true, + type: type, + showCheckedAll: type === 'checkbox', // 只有复选框模式才显示全选 width: 48, + selectedRowKeys: selectedRowKeys.value, + onChange: handleSelectChange })); return { @@ -92,7 +129,8 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa rowSelection, handleSelect, handleSelectAll, + handleSelectChange, resetPageInfo, DEFAULT_PAGE_INFO, }; -} +} \ No newline at end of file diff --git a/src/layouts/components/siderBar/menu-list.ts b/src/layouts/components/siderBar/menu-list.ts index ccd8871..ca11cc0 100644 --- a/src/layouts/components/siderBar/menu-list.ts +++ b/src/layouts/components/siderBar/menu-list.ts @@ -109,10 +109,11 @@ export const MENU_LIST = >{ ], }, { - key: 'ModTaskManage', + key: 'assignmentManagement', label: '任务管理', icon: ['svg-taskManage', 'svg-taskManage-active'], - routeName: 'TaskManagement', + routeName: 'AssignmentManagement', + activeMatch: ['AssignmentManagement'], }, ], [GROUP_WRITER_NAME]: [ @@ -149,16 +150,14 @@ export const MENU_LIST = >{ ], }, ], - [GROUP_MANAGEMENT_NAME]:[ + [GROUP_MANAGEMENT_NAME]: [ { key: 'ModManagementPerson', icon: ['svg-managementPerson', 'svg-managementPerson-active'], label: '个人信息', routeName: 'ManagementPerson', requireLogin: true, - activeMatch: [ - 'ManagementPerson', - ], + activeMatch: ['ManagementPerson'], }, { key: 'ModManagementEnterprise', @@ -167,9 +166,7 @@ export const MENU_LIST = >{ routeName: 'ManagementEnterprise', requireLogin: true, requireAuth: true, - activeMatch: [ - 'ManagementEnterprise', - ], + activeMatch: ['ManagementEnterprise'], }, { key: 'ModManagementAccount', @@ -180,5 +177,5 @@ export const MENU_LIST = >{ requireAuth: true, activeMatch: ['ManagementAccount'], }, - ] + ], }; diff --git a/src/main.ts b/src/main.ts index b42345c..150a597 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,7 +13,7 @@ import SvgIcon from '@/components/svg-icon/index.vue'; import '@/api/index'; import './core'; -import '@arco-design/web-vue/dist/arco.css'; // 已移除 Arco 样式 +// import '@arco-design/web-vue/dist/arco.css'; // 已移除 Arco 样式 import 'normalize.css'; import 'uno.css'; @@ -28,6 +28,7 @@ const app = createApp(App); app.component('NoData', NoData); app.component('SvgIcon', SvgIcon); +(Object.keys(directives) as Array).forEach((k) => app.use(directives[k])); // 注册指令 app.use(store); app.use(router); diff --git a/src/router/routes/modules/propertyMarketing.ts b/src/router/routes/modules/propertyMarketing.ts index bfb8fb2..40df5ad 100644 --- a/src/router/routes/modules/propertyMarketing.ts +++ b/src/router/routes/modules/propertyMarketing.ts @@ -73,6 +73,20 @@ const COMPONENTS: AppRouteRecordRaw[] = [ }, component: () => import('@/views/property-marketing/media-account/account-dashboard/index.vue'), }, + + { + path: 'management-detail/:id', + name: 'managementDetail', + meta: { + locale: '任务详情', + requiresAuth: true, + requireLogin: true, + roles: ['*'], + hideInMenu: true, + activeMenu: 'MediaAccountAccountDashboard', + }, + component: () => import('@/views/property-marketing/assignment-management/managementDetail.vue'), + }, { path: 'detail/:id', name: 'MediaAccountAccountDetails', @@ -172,6 +186,17 @@ const COMPONENTS: AppRouteRecordRaw[] = [ // }, // ], // }, + { + path: '/assignmentManagement', + name: 'AssignmentManagement', + meta: { + locale: '任务管理', + requiresAuth: true, + requireLogin: true, + roles: ['*'], + }, + component: () => import('@/views/property-marketing/assignment-management/index.vue'), + }, // { // path: '/intelligent-solution', // name: 'IntelligentSolution', diff --git a/src/stores/modules/side-bar/constants.ts b/src/stores/modules/side-bar/constants.ts index 2769953..b915916 100644 --- a/src/stores/modules/side-bar/constants.ts +++ b/src/stores/modules/side-bar/constants.ts @@ -114,3 +114,129 @@ // ], // }, // ]; +import { MENU_GROUP_IDS } from '@/router/constants'; +export const MENU_LIST = [ + { + id: MENU_GROUP_IDS.WORK_BENCH_ID, + name: '工作台', + routeName: 'Home', + includeRouteNames: ['Home'], + requiresAuth: false, + permissionKey: '', // 权限key,如果为空,则表示该菜单不需要权限,与后端约定 + }, + { + id: MENU_GROUP_IDS.MANAGEMENT_ID, + name: '任务管理', + routeName: 'assignmentManagement', + includeRouteNames: ['assignmentManagement'], + requiresAuth: false, + permissionKey: '', // 权限key,如果为空,则表示该菜单不需要权限,与后端约定 + }, + { + id: MENU_GROUP_IDS.DATA_ENGINE_ID, + name: '全域数据分析', + permissionKey: 'data_analysis', + requiresAuth: true, + children: [ + { + name: '行业热门话题洞察', + routeName: 'DataEngineHotTranslation', + includeRouteNames: ['DataEngineHotTranslation'], + }, + { + name: '行业词云', + routeName: 'DataEngineHotCloud', + includeRouteNames: ['DataEngineHotCloud'], + }, + { + name: '行业关键词动向', + routeName: 'DataEngineKeyWord', + includeRouteNames: ['DataEngineKeyWord'], + }, + { + name: '用户痛点观察', + routeName: 'DataEngineUserPainPoints', + includeRouteNames: ['DataEngineUserPainPoints'], + }, + { + name: '重点品牌动向', + routeName: 'DataEngineKeyBrandMovement', + includeRouteNames: ['DataEngineKeyBrandMovement'], + }, + { + name: '用户画像', + routeName: 'DataEngineUserPersona', + includeRouteNames: ['DataEngineUserPersona'], + }, + ], + }, + { + id: MENU_GROUP_IDS.CREATIVE_GENERATION_WORKSHOP_ID, + name: '创意生成工坊', + permissionKey: '', + requiresAuth: true, + children: [ + { + name: '内容稿件', + routeName: 'ManuscriptList', + includeRouteNames: [ + 'ManuscriptList', + 'ManuscriptUpload', + 'ManuscriptEdit', + 'ManuscriptDetail', + 'ManuscriptCheckList', + 'ManuscriptCheckListDetail', + 'ManuscriptCheck', + ], + }, + ], + }, + { + id: MENU_GROUP_IDS.PROPERTY_ID, + name: '营销资产中台', + permissionKey: 'marketing_asset', + requiresAuth: true, + children: [ + { + name: '品牌资产管理', + routeName: 'RepositoryBrandMaterials', + includeRouteNames: ['RepositoryBrandMaterials'], + }, + { + name: '账号资源中心', + routeName: 'MediaAccountAccountManagement', + includeRouteNames: [ + 'MediaAccountAccountManagement', + 'MediaAccountAccountDashboard', + 'MediaAccountAccountDetails', + 'assignmentManagement', + 'managementDetail', + ], + }, + { + name: '投放资源中心', + routeName: 'PutAccountAccountManagement', + includeRouteNames: [ + 'PutAccountAccountManagement', + 'PutAccountAccountData', + 'PutAccountAccountDashboard', + 'PutAccountInvestmentGuidelines', + 'guideDetail', + ], + }, + // { + // name: '智能方案管理', + // routeName: 'IntelligentSolutionBusinessAnalysisReport', + // includeRouteNames: [ + // 'IntelligentSolutionBusinessAnalysisReport', + // 'IntelligentSolutionCompetitiveProductAnalysisReport', + // ], + // }, + { + name: '项目管理', + routeName: 'ProjectList', + includeRouteNames: ['ProjectList'], + }, + ], + }, +]; diff --git a/src/utils/DateUtils.ts b/src/utils/DateUtils.ts new file mode 100644 index 0000000..dfcb77e --- /dev/null +++ b/src/utils/DateUtils.ts @@ -0,0 +1,382 @@ +/** + * 日期工具类 + * 提供月维度和周维度的开始结束日期获取功能 + * 周以星期日开始,星期六结束 + * 只返回日期部分,不包含时间 + */ +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), + }; + } + + static MonthStrToDate(dateStr: string): Date { + const year = parseInt(dateStr.split('年')[0]); + const month = parseInt(dateStr.split('年')[1].split('月')[0]) - 1; // 月份从0开始 + + const date = new Date(year, month, 1); + return date; + } + + /** + * 获取指定年份和月的范围 + * @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, + }; + } + + + + /** + * 获取指定年份的所有月份信息 + * @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; diff --git a/src/utils/platform.ts b/src/utils/platform.ts index 03f39c8..66db913 100644 --- a/src/utils/platform.ts +++ b/src/utils/platform.ts @@ -3,6 +3,11 @@ import icon2 from '@/assets/img/media-account/icon-jg.png'; import icon3 from '@/assets/img/media-account/icon-bili.png'; import icon4 from '@/assets/img/platform/icon-dy.png'; import icon5 from '@/assets/img/platform/icon-xhs.png'; +import icon6 from '@/assets/img/platform/icon-bilibili.png'; +import icon7 from '@/assets/img/platform/icon-ks.png'; +import icon8 from '@/assets/img/platform/icon-sph.png'; +import icon9 from '@/assets/img/platform/icon-wb.png'; +import icon10 from '@/assets/img/platform/icon-gzh.png'; // 投放账户 export enum ENUM_PUT_ACCOUNT_PLATFORM { @@ -14,6 +19,11 @@ export enum ENUM_PUT_ACCOUNT_PLATFORM { export enum ENUM_MEDIA_ACCOUNT_PLATFORM { dy = 0, xhs = 1, + bili = 2, + ks = 3, + sph = 4, + wb = 5, + gzh = 6, } export const PLATFORM_LIST = [ @@ -45,6 +55,31 @@ export const MEDIA_ACCOUNT_PLATFORMS = [ value: 1, icon: icon5, }, + { + label: 'B站', + value: 2, + icon: icon6, + }, + { + label: '快手', + value: 3, + icon: icon7, + }, + { + label: '视频号', + value: 4, + icon: icon8, + }, + { + label: '微博', + value: 5, + icon: icon9, + }, + { + label: '公众号', + value: 6, + icon: icon10, + }, ]; export const getPutAccountPlatformLogo = (value: ENUM_PUT_ACCOUNT_PLATFORM) => { diff --git a/src/views/components/login/index.vue b/src/views/components/login/index.vue new file mode 100644 index 0000000..b97b0db --- /dev/null +++ b/src/views/components/login/index.vue @@ -0,0 +1,346 @@ + + + + + + diff --git a/src/views/material-center/components/finished-products/manuscript/list/components/manuscript-table/constants.ts b/src/views/material-center/components/finished-products/manuscript/list/components/manuscript-table/constants.ts index a285027..8045360 100644 --- a/src/views/material-center/components/finished-products/manuscript/list/components/manuscript-table/constants.ts +++ b/src/views/material-center/components/finished-products/manuscript/list/components/manuscript-table/constants.ts @@ -43,14 +43,6 @@ export const TABLE_COLUMNS = [ dataIndex: 'origin', width: 120, }, - { - title: '上传时间', - dataIndex: 'created_at', - width: 180, - sortable: { - sortDirections: ['ascend', 'descend'], - }, - }, { title: '上传人员', dataIndex: 'uploader', diff --git a/src/views/property-marketing/assignment-management/components/colorTip.vue b/src/views/property-marketing/assignment-management/components/colorTip.vue new file mode 100644 index 0000000..9bb4524 --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/colorTip.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/components/date-selector.vue b/src/views/property-marketing/assignment-management/components/date-selector.vue new file mode 100644 index 0000000..9ad0dbb --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/date-selector.vue @@ -0,0 +1,280 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/components/draw-popup.vue b/src/views/property-marketing/assignment-management/components/draw-popup.vue new file mode 100644 index 0000000..5ac260f --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/draw-popup.vue @@ -0,0 +1,625 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/components/filter-popup.vue b/src/views/property-marketing/assignment-management/components/filter-popup.vue new file mode 100644 index 0000000..9398eac --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/filter-popup.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/components/finished-product-drawer.vue b/src/views/property-marketing/assignment-management/components/finished-product-drawer.vue new file mode 100644 index 0000000..835d499 --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/finished-product-drawer.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/components/raw-material-drawer.vue b/src/views/property-marketing/assignment-management/components/raw-material-drawer.vue new file mode 100644 index 0000000..df5253f --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/raw-material-drawer.vue @@ -0,0 +1,295 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/components/task-item.vue b/src/views/property-marketing/assignment-management/components/task-item.vue new file mode 100644 index 0000000..4786bd4 --- /dev/null +++ b/src/views/property-marketing/assignment-management/components/task-item.vue @@ -0,0 +1,369 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/index.vue b/src/views/property-marketing/assignment-management/index.vue new file mode 100644 index 0000000..7238362 --- /dev/null +++ b/src/views/property-marketing/assignment-management/index.vue @@ -0,0 +1,667 @@ + + + + + diff --git a/src/views/property-marketing/assignment-management/managementDetail.vue b/src/views/property-marketing/assignment-management/managementDetail.vue new file mode 100644 index 0000000..7d9d2fb --- /dev/null +++ b/src/views/property-marketing/assignment-management/managementDetail.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/src/views/property-marketing/media-account/account-manage/components/account-table/card.vue b/src/views/property-marketing/media-account/account-manage/components/account-table/card.vue index 9985c21..0a3ba32 100644 --- a/src/views/property-marketing/media-account/account-manage/components/account-table/card.vue +++ b/src/views/property-marketing/media-account/account-manage/components/account-table/card.vue @@ -39,7 +39,27 @@
平台 - +
账号ID @@ -150,7 +170,11 @@ import FooterBtn from './footer-btn'; 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'; const props = defineProps({ dataSource: { type: Array, diff --git a/src/views/property-marketing/media-account/account-manage/components/add-account-modal/index.vue b/src/views/property-marketing/media-account/account-manage/components/add-account-modal/index.vue index 3c8fa6c..150785c 100644 --- a/src/views/property-marketing/media-account/account-manage/components/add-account-modal/index.vue +++ b/src/views/property-marketing/media-account/account-manage/components/add-account-modal/index.vue @@ -43,8 +43,17 @@ import { import icon1 from '@/assets/img/media-account/icon-download.png'; import icon2 from '@/assets/img/media-account/icon-delete.png'; + + + import icon3 from '@/assets/img/platform/icon-dy.png'; import icon4 from '@/assets/img/platform/icon-xhs.png'; +import icon5 from '@/assets/img/platform/icon-bilibili.png'; +import icon6 from '@/assets/img/platform/icon-ks.png'; +import icon7 from '@/assets/img/platform/icon-sph.png'; +import icon8 from '@/assets/img/platform/icon-wb.png'; +import icon9 from '@/assets/img/platform/icon-gzh.png'; + // import icon5 from '@/assets/img/media-account/icon-warn-1.png'; // import icon6 from '@/assets/img/media-account/icon-success.png'; @@ -104,6 +113,7 @@ export default { }, ], operator_name: [{ required: true, message: '请输入运营人员' }], + end_work_link: [{ required: true, message: '请输入笔记链接' }], }; const isBatchImport = computed(() => uploadType.value === 'batch'); @@ -396,11 +406,37 @@ export default { {isEdit.value ? ( - + ) : ( 小红书 抖音 + B站 + 快手 + 视频号 + 微博 + 公众号 )} @@ -452,7 +488,8 @@ export default { renderLabel('笔记链接', '平台将从该笔记“之后”的内容开始同步,该笔记及更早的数据均不采集'), @@ -460,7 +497,7 @@ export default { >