初步完成进度管理和人员组织
This commit is contained in:
parent
a3f30bf2d0
commit
ee5534d052
|
@ -0,0 +1,54 @@
|
||||||
|
import type * as T from './type'
|
||||||
|
import http from '@/utils/http'
|
||||||
|
|
||||||
|
const BASE_URL = '/project/personnel-organization'
|
||||||
|
|
||||||
|
/** @desc 获取项目列表 */
|
||||||
|
export function getProjectList(query?: T.ProjectQuery) {
|
||||||
|
return http.get<PageRes<T.ProjectResp[]>>('/project/list', query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取项目人员组织信息 */
|
||||||
|
export function getPersonnelOrganization(projectId: string | number) {
|
||||||
|
return http.get<T.PersonnelOrganizationResp>(`${BASE_URL}/${projectId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取工种列表 */
|
||||||
|
export function getWorkTypeList() {
|
||||||
|
return http.get<T.WorkTypeResp[]>('/work-type/list')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取施工人员列表 */
|
||||||
|
export function getConstructorList(query: T.ConstructorQuery) {
|
||||||
|
return http.get<PageRes<T.ConstructorResp[]>>('/constructor/list', query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取施工人员技能证书 */
|
||||||
|
export function getConstructorCertifications(constructorId: string | number) {
|
||||||
|
return http.get<T.CertificationResp[]>(`/constructor/${constructorId}/certifications`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 分配施工人员到项目 */
|
||||||
|
export function assignConstructorToProject(data: T.AssignConstructorReq) {
|
||||||
|
return http.post(`${BASE_URL}/assign`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 移除项目施工人员 */
|
||||||
|
export function removeConstructorFromProject(data: T.RemoveConstructorReq) {
|
||||||
|
return http.delete(`${BASE_URL}/remove`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 更新施工人员分配信息 */
|
||||||
|
export function updateConstructorAssignment(data: T.UpdateAssignmentReq) {
|
||||||
|
return http.put(`${BASE_URL}/update`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取项目人员统计 */
|
||||||
|
export function getPersonnelStats(projectId: string | number) {
|
||||||
|
return http.get<T.PersonnelStatsResp>(`${BASE_URL}/${projectId}/stats`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 导出项目人员组织 */
|
||||||
|
export function exportPersonnelOrganization(projectId: string | number) {
|
||||||
|
return http.download(`${BASE_URL}/${projectId}/export`)
|
||||||
|
}
|
|
@ -327,7 +327,137 @@ export interface UpdateRequirementStatusForm {
|
||||||
status: 'pending' | 'recruiting' | 'completed'
|
status: 'pending' | 'recruiting' | 'completed'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 人员组织相关类型 ====================
|
||||||
|
|
||||||
|
/** 工种响应 */
|
||||||
|
export interface WorkTypeResp {
|
||||||
|
id: string | number
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
description?: string
|
||||||
|
requiredCertifications?: string[]
|
||||||
|
sort?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 施工人员响应 */
|
||||||
|
export interface ConstructorResp {
|
||||||
|
id: string | number
|
||||||
|
name: string
|
||||||
|
phone: string
|
||||||
|
email?: string
|
||||||
|
avatar?: string
|
||||||
|
workTypes: string[] // 工种列表
|
||||||
|
certifications: CertificationResp[]
|
||||||
|
experience: number // 工作经验(年)
|
||||||
|
status: 'ACTIVE' | 'INACTIVE' | 'BUSY'
|
||||||
|
rating: number // 评分
|
||||||
|
joinDate: string
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 证书响应 */
|
||||||
|
export interface CertificationResp {
|
||||||
|
id: string | number
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
code: string
|
||||||
|
issueDate: string
|
||||||
|
expiryDate: string
|
||||||
|
issuingAuthority: string
|
||||||
|
status: 'VALID' | 'EXPIRED' | 'EXPIRING_SOON'
|
||||||
|
imageUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 施工人员查询参数 */
|
||||||
|
export interface ConstructorQuery extends PageQuery {
|
||||||
|
name?: string
|
||||||
|
workType?: string
|
||||||
|
status?: string
|
||||||
|
hasCertification?: boolean
|
||||||
|
experienceMin?: number
|
||||||
|
experienceMax?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员组织响应 */
|
||||||
|
export interface PersonnelOrganizationResp {
|
||||||
|
projectId: string | number
|
||||||
|
projectName: string
|
||||||
|
workTypeAssignments: WorkTypeAssignmentResp[]
|
||||||
|
totalPersonnel: number
|
||||||
|
assignedPersonnel: number
|
||||||
|
availablePersonnel: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工种分配响应 */
|
||||||
|
export interface WorkTypeAssignmentResp {
|
||||||
|
workTypeId: string | number
|
||||||
|
workTypeName: string
|
||||||
|
workTypeCode: string
|
||||||
|
requiredCount: number
|
||||||
|
assignedCount: number
|
||||||
|
constructors: ConstructorAssignmentResp[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 施工人员分配响应 */
|
||||||
|
export interface ConstructorAssignmentResp {
|
||||||
|
constructorId: string | number
|
||||||
|
constructorName: string
|
||||||
|
phone: string
|
||||||
|
avatar?: string
|
||||||
|
workTypes: string[]
|
||||||
|
certifications: CertificationResp[]
|
||||||
|
experience: number
|
||||||
|
rating: number
|
||||||
|
assignmentDate: string
|
||||||
|
status: 'ASSIGNED' | 'WORKING' | 'COMPLETED'
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分配施工人员请求 */
|
||||||
|
export interface AssignConstructorReq {
|
||||||
|
projectId: string | number
|
||||||
|
workTypeId: string | number
|
||||||
|
constructorIds: (string | number)[]
|
||||||
|
assignmentDate?: string
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 移除施工人员请求 */
|
||||||
|
export interface RemoveConstructorReq {
|
||||||
|
projectId: string | number
|
||||||
|
constructorIds: (string | number)[]
|
||||||
|
reason?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新分配信息请求 */
|
||||||
|
export interface UpdateAssignmentReq {
|
||||||
|
projectId: string | number
|
||||||
|
constructorId: string | number
|
||||||
|
workTypeId?: string | number
|
||||||
|
status?: string
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员统计响应 */
|
||||||
|
export interface PersonnelStatsResp {
|
||||||
|
totalPersonnel: number
|
||||||
|
assignedPersonnel: number
|
||||||
|
availablePersonnel: number
|
||||||
|
workTypeStats: {
|
||||||
|
workTypeName: string
|
||||||
|
requiredCount: number
|
||||||
|
assignedCount: number
|
||||||
|
shortageCount: number
|
||||||
|
}[]
|
||||||
|
certificationStats: {
|
||||||
|
certificationType: string
|
||||||
|
count: number
|
||||||
|
}[]
|
||||||
|
experienceStats: {
|
||||||
|
range: string
|
||||||
|
count: number
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
/** 分页查询基础参数 */
|
/** 分页查询基础参数 */
|
||||||
export interface PageQuery {
|
export interface PageQuery {
|
||||||
|
|
|
@ -804,7 +804,17 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
hidden: false,
|
hidden: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/project-management/projects/personnel-organization',
|
||||||
|
name: 'PersonnelOrganization',
|
||||||
|
component: () => import('@/views/project-management/projects/personnel-organization/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '人员组织',
|
||||||
|
icon: 'user-group',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/project-management/projects/device',
|
path: '/project-management/projects/device',
|
||||||
name: 'DeviceManagement',
|
name: 'DeviceManagement',
|
||||||
|
|
|
@ -7,7 +7,70 @@ export {}
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
ApprovalAssistant: typeof import('./../components/ApprovalAssistant/index.vue')['default']
|
||||||
|
ApprovalMessageItem: typeof import('./../components/NotificationCenter/ApprovalMessageItem.vue')['default']
|
||||||
|
Avatar: typeof import('./../components/Avatar/index.vue')['default']
|
||||||
|
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default']
|
||||||
|
CellCopy: typeof import('./../components/CellCopy/index.vue')['default']
|
||||||
|
Chart: typeof import('./../components/Chart/index.vue')['default']
|
||||||
|
CircularProgress: typeof import('./../components/CircularProgress/index.vue')['default']
|
||||||
|
ColumnSetting: typeof import('./../components/GiTable/src/components/ColumnSetting.vue')['default']
|
||||||
|
CronForm: typeof import('./../components/GenCron/CronForm/index.vue')['default']
|
||||||
|
CronModal: typeof import('./../components/GenCron/CronModal/index.vue')['default']
|
||||||
|
DateRangePicker: typeof import('./../components/DateRangePicker/index.vue')['default']
|
||||||
|
DayForm: typeof import('./../components/GenCron/CronForm/component/day-form.vue')['default']
|
||||||
|
FilePreview: typeof import('./../components/FilePreview/index.vue')['default']
|
||||||
|
GiCellAvatar: typeof import('./../components/GiCell/GiCellAvatar.vue')['default']
|
||||||
|
GiCellGender: typeof import('./../components/GiCell/GiCellGender.vue')['default']
|
||||||
|
GiCellStatus: typeof import('./../components/GiCell/GiCellStatus.vue')['default']
|
||||||
|
GiCellTag: typeof import('./../components/GiCell/GiCellTag.vue')['default']
|
||||||
|
GiCellTags: typeof import('./../components/GiCell/GiCellTags.vue')['default']
|
||||||
|
GiCodeView: typeof import('./../components/GiCodeView/index.vue')['default']
|
||||||
|
GiDot: typeof import('./../components/GiDot/index.tsx')['default']
|
||||||
|
GiEditTable: typeof import('./../components/GiEditTable/GiEditTable.vue')['default']
|
||||||
|
GiFooter: typeof import('./../components/GiFooter/index.vue')['default']
|
||||||
|
GiForm: typeof import('./../components/GiForm/src/GiForm.vue')['default']
|
||||||
|
GiIconBox: typeof import('./../components/GiIconBox/index.vue')['default']
|
||||||
|
GiIconSelector: typeof import('./../components/GiIconSelector/index.vue')['default']
|
||||||
|
GiIframe: typeof import('./../components/GiIframe/index.vue')['default']
|
||||||
|
GiOption: typeof import('./../components/GiOption/index.vue')['default']
|
||||||
|
GiOptionItem: typeof import('./../components/GiOptionItem/index.vue')['default']
|
||||||
|
GiPageLayout: typeof import('./../components/GiPageLayout/index.vue')['default']
|
||||||
|
GiSpace: typeof import('./../components/GiSpace/index.vue')['default']
|
||||||
|
GiSplitButton: typeof import('./../components/GiSplitButton/index.vue')['default']
|
||||||
|
GiSplitPane: typeof import('./../components/GiSplitPane/index.vue')['default']
|
||||||
|
GiSplitPaneFlexibleBox: typeof import('./../components/GiSplitPane/components/GiSplitPaneFlexibleBox.vue')['default']
|
||||||
|
GiSvgIcon: typeof import('./../components/GiSvgIcon/index.vue')['default']
|
||||||
|
GiTable: typeof import('./../components/GiTable/src/GiTable.vue')['default']
|
||||||
|
GiTag: typeof import('./../components/GiTag/index.tsx')['default']
|
||||||
|
GiThemeBtn: typeof import('./../components/GiThemeBtn/index.vue')['default']
|
||||||
|
HourForm: typeof import('./../components/GenCron/CronForm/component/hour-form.vue')['default']
|
||||||
|
Icon403: typeof import('./../components/icons/Icon403.vue')['default']
|
||||||
|
Icon404: typeof import('./../components/icons/Icon404.vue')['default']
|
||||||
|
Icon500: typeof import('./../components/icons/Icon500.vue')['default']
|
||||||
|
IconBorders: typeof import('./../components/icons/IconBorders.vue')['default']
|
||||||
|
IconTableSize: typeof import('./../components/icons/IconTableSize.vue')['default']
|
||||||
|
IconTreeAdd: typeof import('./../components/icons/IconTreeAdd.vue')['default']
|
||||||
|
IconTreeReduce: typeof import('./../components/icons/IconTreeReduce.vue')['default']
|
||||||
|
ImageImport: typeof import('./../components/ImageImport/index.vue')['default']
|
||||||
|
ImageImportWizard: typeof import('./../components/ImageImportWizard/index.vue')['default']
|
||||||
|
IndustrialImageList: typeof import('./../components/IndustrialImageList/index.vue')['default']
|
||||||
|
JsonPretty: typeof import('./../components/JsonPretty/index.vue')['default']
|
||||||
|
MinuteForm: typeof import('./../components/GenCron/CronForm/component/minute-form.vue')['default']
|
||||||
|
MonthForm: typeof import('./../components/GenCron/CronForm/component/month-form.vue')['default']
|
||||||
|
NotificationCenter: typeof import('./../components/NotificationCenter/index.vue')['default']
|
||||||
|
ParentView: typeof import('./../components/ParentView/index.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
SecondForm: typeof import('./../components/GenCron/CronForm/component/second-form.vue')['default']
|
||||||
|
SplitPanel: typeof import('./../components/SplitPanel/index.vue')['default']
|
||||||
|
TextCopy: typeof import('./../components/TextCopy/index.vue')['default']
|
||||||
|
TurbineGrid: typeof import('./../components/TurbineGrid/index.vue')['default']
|
||||||
|
UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
|
||||||
|
Verify: typeof import('./../components/Verify/index.vue')['default']
|
||||||
|
VerifyPoints: typeof import('./../components/Verify/Verify/VerifyPoints.vue')['default']
|
||||||
|
VerifySlide: typeof import('./../components/Verify/Verify/VerifySlide.vue')['default']
|
||||||
|
WeekForm: typeof import('./../components/GenCron/CronForm/component/week-form.vue')['default']
|
||||||
|
YearForm: typeof import('./../components/GenCron/CronForm/component/year-form.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,9 +49,9 @@
|
||||||
<span class="date-item">
|
<span class="date-item">
|
||||||
📅 {{ formatShortDate(project.endDate) }}
|
📅 {{ formatShortDate(project.endDate) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="empty-status">
|
<div v-else class="empty-status">
|
||||||
|
@ -68,9 +68,9 @@
|
||||||
<div class="project-title">
|
<div class="project-title">
|
||||||
<h2>{{ selectedProject.projectName }}</h2>
|
<h2>{{ selectedProject.projectName }}</h2>
|
||||||
<div class="project-tags">
|
<div class="project-tags">
|
||||||
<a-tag :color="getStatusColor(selectedProject.status)">
|
<a-tag :color="getStatusColor(selectedProject.status)">
|
||||||
{{ getStatusText(selectedProject.status) }}
|
{{ getStatusText(selectedProject.status) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
<a-tag color="blue">{{ selectedProject.projectCode }}</a-tag>
|
<a-tag color="blue">{{ selectedProject.projectCode }}</a-tag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -626,37 +626,37 @@ const availableWeeks = ref([
|
||||||
// 时间轴周数 - 简化版本
|
// 时间轴周数 - 简化版本
|
||||||
const timelineWeeks = computed(() => {
|
const timelineWeeks = computed(() => {
|
||||||
try {
|
try {
|
||||||
const weeks = []
|
const weeks = []
|
||||||
const startDate = new Date('2025-01-06')
|
const startDate = new Date('2025-01-06')
|
||||||
|
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 4; i++) {
|
||||||
const weekStart = dayjs.add(startDate, i * 7, 'day')
|
const weekStart = dayjs.add(startDate, i * 7, 'day')
|
||||||
const days = []
|
const days = []
|
||||||
|
|
||||||
for (let j = 0; j < 7; j++) {
|
for (let j = 0; j < 7; j++) {
|
||||||
const currentDate = dayjs.add(weekStart, j, 'day')
|
const currentDate = dayjs.add(weekStart, j, 'day')
|
||||||
const dayNumber = currentDate.getDate()
|
const dayNumber = currentDate.getDate()
|
||||||
const weekday = ['日', '一', '二', '三', '四', '五', '六'][currentDate.getDay()]
|
const weekday = ['日', '一', '二', '三', '四', '五', '六'][currentDate.getDay()]
|
||||||
const isWeekend = currentDate.getDay() === 0 || currentDate.getDay() === 6
|
const isWeekend = currentDate.getDay() === 0 || currentDate.getDay() === 6
|
||||||
const isToday = dayjs.isSame(currentDate, new Date(), 'day')
|
const isToday = dayjs.isSame(currentDate, new Date(), 'day')
|
||||||
|
|
||||||
days.push({
|
|
||||||
date: dayjs.format(currentDate, 'YYYY-MM-DD'),
|
|
||||||
dayNumber,
|
|
||||||
weekday,
|
|
||||||
isWeekend,
|
|
||||||
isToday
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
weeks.push({
|
days.push({
|
||||||
value: `week${i + 1}`,
|
date: dayjs.format(currentDate, 'YYYY-MM-DD'),
|
||||||
label: `第${i + 1}周`,
|
dayNumber,
|
||||||
days
|
weekday,
|
||||||
|
isWeekend,
|
||||||
|
isToday
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return weeks
|
weeks.push({
|
||||||
|
value: `week${i + 1}`,
|
||||||
|
label: `第${i + 1}周`,
|
||||||
|
days
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return weeks
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('计算时间轴出错:', error)
|
console.error('计算时间轴出错:', error)
|
||||||
return []
|
return []
|
||||||
|
@ -666,7 +666,7 @@ const timelineWeeks = computed(() => {
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const getProjectCountByStatus = (status: string) => {
|
const getProjectCountByStatus = (status: string) => {
|
||||||
try {
|
try {
|
||||||
return projects.value.filter(p => getStatusKey(p.status) === status).length
|
return projects.value.filter(p => getStatusKey(p.status) === status).length
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('计算项目数量出错:', error)
|
console.error('计算项目数量出错:', error)
|
||||||
return 0
|
return 0
|
||||||
|
@ -675,7 +675,7 @@ const getProjectCountByStatus = (status: string) => {
|
||||||
|
|
||||||
const getProjectsByStatus = (status: string) => {
|
const getProjectsByStatus = (status: string) => {
|
||||||
try {
|
try {
|
||||||
return projects.value.filter(p => getStatusKey(p.status) === status)
|
return projects.value.filter(p => getStatusKey(p.status) === status)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('筛选项目出错:', error)
|
console.error('筛选项目出错:', error)
|
||||||
return []
|
return []
|
||||||
|
@ -684,10 +684,10 @@ const getProjectsByStatus = (status: string) => {
|
||||||
|
|
||||||
const getTotalWorkload = () => {
|
const getTotalWorkload = () => {
|
||||||
try {
|
try {
|
||||||
if (!selectedProject.value) return 0
|
if (!selectedProject.value) return 0
|
||||||
return projectTasks.value
|
return projectTasks.value
|
||||||
.filter(task => !task.isSubTask)
|
.filter(task => !task.isSubTask)
|
||||||
.reduce((total, task) => total + (task.workDays || 0), 0)
|
.reduce((total, task) => total + (task.workDays || 0), 0)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('计算工作量出错:', error)
|
console.error('计算工作量出错:', error)
|
||||||
return 0
|
return 0
|
||||||
|
@ -796,8 +796,8 @@ const isTaskActiveOnDay = (task: any, date: string) => {
|
||||||
|
|
||||||
const isTaskCompletedOnDay = (task: any, date: string) => {
|
const isTaskCompletedOnDay = (task: any, date: string) => {
|
||||||
try {
|
try {
|
||||||
if (task.progress >= 100) return true
|
if (task.progress >= 100) return true
|
||||||
|
|
||||||
const taskStart = new Date(task.startDate)
|
const taskStart = new Date(task.startDate)
|
||||||
const taskEnd = new Date(task.endDate)
|
const taskEnd = new Date(task.endDate)
|
||||||
const currentDate = new Date(date)
|
const currentDate = new Date(date)
|
||||||
|
@ -805,10 +805,10 @@ const isTaskCompletedOnDay = (task: any, date: string) => {
|
||||||
if (!dayjs.isBetween(currentDate, taskStart, taskEnd, 'day', '[]')) return false
|
if (!dayjs.isBetween(currentDate, taskStart, taskEnd, 'day', '[]')) return false
|
||||||
|
|
||||||
const totalDays = dayjs.diff(taskEnd, taskStart, 'day') + 1
|
const totalDays = dayjs.diff(taskEnd, taskStart, 'day') + 1
|
||||||
const completedDays = Math.floor((task.progress / 100) * totalDays)
|
const completedDays = Math.floor((task.progress / 100) * totalDays)
|
||||||
const daysFromStart = dayjs.diff(currentDate, taskStart, 'day') + 1
|
const daysFromStart = dayjs.diff(currentDate, taskStart, 'day') + 1
|
||||||
|
|
||||||
return daysFromStart <= completedDays
|
return daysFromStart <= completedDays
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('检查任务完成状态出错:', error)
|
console.error('检查任务完成状态出错:', error)
|
||||||
return false
|
return false
|
||||||
|
@ -820,10 +820,10 @@ const getTaskBarStyle = (task: any, date: string) => {
|
||||||
const taskStart = new Date(task.startDate)
|
const taskStart = new Date(task.startDate)
|
||||||
const currentDate = new Date(date)
|
const currentDate = new Date(date)
|
||||||
const daysFromStart = dayjs.diff(currentDate, taskStart, 'day')
|
const daysFromStart = dayjs.diff(currentDate, taskStart, 'day')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
left: `${daysFromStart * 40}px`,
|
left: `${daysFromStart * 40}px`,
|
||||||
width: '40px'
|
width: '40px'
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('计算任务条样式出错:', error)
|
console.error('计算任务条样式出错:', error)
|
||||||
|
@ -840,9 +840,9 @@ onMounted(() => {
|
||||||
console.log('项目数据:', projects.value)
|
console.log('项目数据:', projects.value)
|
||||||
console.log('任务数据:', projectTasks.value)
|
console.log('任务数据:', projectTasks.value)
|
||||||
|
|
||||||
// 默认选择第一个项目
|
// 默认选择第一个项目
|
||||||
if (projects.value.length > 0) {
|
if (projects.value.length > 0) {
|
||||||
selectProject(projects.value[0])
|
selectProject(projects.value[0])
|
||||||
console.log('已选择默认项目:', projects.value[0])
|
console.log('已选择默认项目:', projects.value[0])
|
||||||
} else {
|
} else {
|
||||||
console.warn('没有可用的项目数据')
|
console.warn('没有可用的项目数据')
|
||||||
|
@ -963,7 +963,7 @@ onMounted(() => {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-manager {
|
.project-manager {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #86909c;
|
color: #86909c;
|
||||||
|
|
Loading…
Reference in New Issue