677 lines
20 KiB
Vue
677 lines
20 KiB
Vue
<template>
|
||
<div class="gantt-schedule-page">
|
||
<div class="gantt-header">
|
||
<div class="gantt-header-left">
|
||
<h1 class="page-title">甘特图排产</h1>
|
||
<p class="page-desc">拖拽工序条块调整计划时间,完成后请保存排产草稿</p>
|
||
</div>
|
||
<n-space>
|
||
<n-button type="primary" :loading="saving" @click="handleSaveDraft">保存排产草稿</n-button>
|
||
<n-button @click="handleBack">返回</n-button>
|
||
</n-space>
|
||
</div>
|
||
|
||
<div class="gantt-meta">
|
||
<span>生产订单 {{ scheduleStats.moCount }} 条</span>
|
||
<span class="meta-divider">|</span>
|
||
<span>工序 {{ scheduleStats.routeCount }} 道</span>
|
||
<span class="meta-divider">|</span>
|
||
<span>今日 {{ todayLabel }}</span>
|
||
<span class="meta-divider">|</span>
|
||
<span class="meta-legend"><i class="legend-today-line" />今日时间轴</span>
|
||
</div>
|
||
|
||
<div class="gantt-panel">
|
||
<div class="gantt-panel-head">
|
||
<span class="panel-title">排产明细</span>
|
||
<span class="panel-tip">主产品行展示物料编码与名称,子行展示工序号与工序名称</span>
|
||
</div>
|
||
<div class="gantt-container" ref="ganttContainer" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted, onUnmounted, toRaw, computed } from 'vue'
|
||
import { useMessage } from 'naive-ui'
|
||
import { useRouter } from 'vue-router'
|
||
import { gantt } from 'dhtmlx-gantt'
|
||
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
|
||
import { orderProjectApi, normalizeKingdeeProcessRoute, resolveProcessName, type KingdeePrdMo } from '@/api/orderProject'
|
||
|
||
const router = useRouter()
|
||
const ganttContainer = ref<HTMLElement | null>(null)
|
||
const message = useMessage()
|
||
let ganttEventIds: string[] = []
|
||
|
||
const tableData = ref<any[]>([])
|
||
const projectId = ref<number | null>(null)
|
||
const saving = ref(false)
|
||
|
||
const PROCESS_COLORS = [
|
||
'#409eff', '#67c23a', '#e6a23c', '#909399', '#f56c6c',
|
||
'#36cfc9', '#597ef7', '#9254de', '#73d13d',
|
||
]
|
||
|
||
const WEEKDAY_LABELS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||
|
||
function getRouteColorIndex(index: number) {
|
||
return index % PROCESS_COLORS.length
|
||
}
|
||
|
||
function getRouteColor(index: number) {
|
||
return PROCESS_COLORS[getRouteColorIndex(index)]
|
||
}
|
||
|
||
function formatDayScale(date: Date) {
|
||
return `${date.getDate()}日 ${WEEKDAY_LABELS[date.getDay()]}`
|
||
}
|
||
|
||
const scheduleStats = computed(() => {
|
||
let routeCount = 0
|
||
tableData.value.forEach((mo) => {
|
||
routeCount += mo.processRoutes?.length ?? 0
|
||
})
|
||
return {
|
||
moCount: tableData.value.length,
|
||
routeCount,
|
||
}
|
||
})
|
||
|
||
const todayLabel = computed(() => {
|
||
const d = new Date()
|
||
const pad = (n: number) => String(n).padStart(2, '0')
|
||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`
|
||
})
|
||
|
||
function handleBack() {
|
||
router.back()
|
||
}
|
||
|
||
async function handleSaveDraft() {
|
||
if (!projectId.value) {
|
||
message.warning('缺少项目ID,无法保存')
|
||
return
|
||
}
|
||
|
||
saving.value = true
|
||
try {
|
||
const draftData = tableData.value.map(mo => {
|
||
const { processRoutes, ...rest } = mo
|
||
return { ...rest, children: processRoutes } as KingdeePrdMo
|
||
})
|
||
|
||
await orderProjectApi.saveKingdeeOrderDraft(projectId.value, draftData)
|
||
message.success('排产草稿保存成功')
|
||
sessionStorage.setItem('gantt_schedule_data', JSON.stringify(tableData.value))
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
try {
|
||
initGantt()
|
||
|
||
const stateStr = sessionStorage.getItem('gantt_schedule_data')
|
||
const idStr = sessionStorage.getItem('gantt_project_id')
|
||
|
||
if (idStr) {
|
||
projectId.value = Number(idStr)
|
||
}
|
||
|
||
if (stateStr) {
|
||
const parsedData = JSON.parse(stateStr)
|
||
tableData.value = (Array.isArray(parsedData) ? parsedData : []).map((mo: any) => ({
|
||
...mo,
|
||
processRoutes: (mo.processRoutes ?? []).map(normalizeKingdeeProcessRoute),
|
||
}))
|
||
renderGanttData()
|
||
} else {
|
||
message.warning('未获取到排产数据')
|
||
}
|
||
} catch {
|
||
message.error('加载排产数据失败')
|
||
}
|
||
})
|
||
|
||
function formatGanttDate(date: Date) {
|
||
const pad = (n: number) => String(n).padStart(2, '0')
|
||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
|
||
}
|
||
|
||
function formatGridDate(value: Date | string | undefined) {
|
||
if (!value) return ''
|
||
const date = value instanceof Date ? value : new Date(String(value).replace(' ', 'T'))
|
||
if (isNaN(date.getTime())) return ''
|
||
const pad = (n: number) => String(n).padStart(2, '0')
|
||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
|
||
}
|
||
|
||
function formatMoMaterialLabel(mo: any) {
|
||
const code = mo.materialCode?.trim() || ''
|
||
const name = mo.materialName?.trim() || ''
|
||
if (code && name) return `${code} ${name}`
|
||
return code || name
|
||
}
|
||
|
||
function initGantt() {
|
||
if (!ganttContainer.value) return
|
||
|
||
ganttEventIds.forEach(id => gantt.detachEvent(id))
|
||
ganttEventIds = []
|
||
gantt.clearAll()
|
||
|
||
gantt.config.date_format = '%Y-%m-%d %H:%i:%s'
|
||
gantt.config.scale_height = 60
|
||
gantt.config.row_height = 40
|
||
gantt.config.bar_height = 26
|
||
gantt.config.scales = [
|
||
{ unit: 'month', step: 1, format: '%Y年 %m月' },
|
||
{ unit: 'day', step: 1, format: formatDayScale },
|
||
]
|
||
gantt.config.columns = [
|
||
{
|
||
name: 'text',
|
||
label: '工序号 / 物料编码',
|
||
tree: true,
|
||
width: 200,
|
||
resize: true,
|
||
template(task: any) {
|
||
if (task._type === 'route') return task.operNumber ?? ''
|
||
return task.materialCode ?? ''
|
||
},
|
||
},
|
||
{
|
||
name: 'routeProcessName',
|
||
label: '工序名称 / 物料名称',
|
||
align: 'center',
|
||
width: 168,
|
||
resize: true,
|
||
template(task: any) {
|
||
if (task._type === 'route') {
|
||
return task.routeProcessName ?? resolveProcessName(task._raw ?? {}) ?? ''
|
||
}
|
||
return task.materialName ?? ''
|
||
},
|
||
},
|
||
{
|
||
name: 'start_date',
|
||
label: '计划开始',
|
||
align: 'center',
|
||
width: 118,
|
||
template(task: any) {
|
||
return formatGridDate(task.start_date)
|
||
},
|
||
},
|
||
{
|
||
name: 'end_date',
|
||
label: '计划结束',
|
||
align: 'center',
|
||
width: 118,
|
||
template(task: any) {
|
||
return formatGridDate(task.end_date)
|
||
},
|
||
},
|
||
]
|
||
|
||
gantt.config.layout = {
|
||
css: 'gantt_container',
|
||
cols: [
|
||
{
|
||
width: 620,
|
||
minWidth: 420,
|
||
maxWidth: 680,
|
||
rows: [
|
||
{ view: 'grid', scrollX: 'gridScroll', scrollable: true, scrollY: 'scrollVer' },
|
||
{ view: 'scrollbar', id: 'gridScroll', group: 'horizontal' },
|
||
],
|
||
},
|
||
{ resizer: true, width: 1 },
|
||
{
|
||
rows: [
|
||
{ view: 'timeline', scrollX: 'scrollHor', scrollY: 'scrollVer' },
|
||
{ view: 'scrollbar', id: 'scrollHor', group: 'horizontal' },
|
||
],
|
||
},
|
||
{ view: 'scrollbar', id: 'scrollVer' },
|
||
],
|
||
}
|
||
|
||
gantt.config.drag_progress = false
|
||
gantt.config.drag_links = false
|
||
// 使用自然日历(含周六日),不按工作日历自动顺延
|
||
gantt.config.work_time = false
|
||
gantt.config.correct_work_time = false
|
||
gantt.config.skip_off_time = false
|
||
gantt.config.duration_unit = 'day'
|
||
gantt.config.smart_rendering = true
|
||
|
||
gantt.i18n.setLocale('cn')
|
||
gantt.plugins({ marker: true })
|
||
|
||
gantt.templates.task_text = function(_start, _end, task) {
|
||
if (task._type === 'route') {
|
||
return task.routeProcessName || resolveProcessName(task._raw ?? {}) || ''
|
||
}
|
||
return task.materialName || task.materialLabel || ''
|
||
}
|
||
|
||
gantt.templates.task_class = function(_start, _end, task) {
|
||
if (task._type === 'mo') return 'gantt-task-mo'
|
||
if (task._type === 'route') {
|
||
return `gantt-task-route gantt-route-c-${task.colorIndex ?? 0}`
|
||
}
|
||
return ''
|
||
}
|
||
|
||
gantt.templates.grid_row_class = function(_start, _end, task) {
|
||
if (task._type === 'mo') return 'gantt-row-mo'
|
||
if (task._type === 'route') {
|
||
return `gantt-row-route gantt-route-c-${task.colorIndex ?? 0}`
|
||
}
|
||
return ''
|
||
}
|
||
|
||
gantt.templates.timeline_cell_class = function(_task, date) {
|
||
const day = date.getDay()
|
||
if (day === 0 || day === 6) return 'gantt-weekend'
|
||
return ''
|
||
}
|
||
|
||
gantt.init(ganttContainer.value)
|
||
}
|
||
|
||
/** 今日时间轴标记(数据刷新后需重新添加) */
|
||
function addTodayMarker() {
|
||
const now = new Date()
|
||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 12, 0, 0)
|
||
gantt.addMarker({
|
||
start_date: today,
|
||
css: 'today-marker',
|
||
text: '今日',
|
||
title: `今日: ${formatGanttDate(now)}`,
|
||
})
|
||
gantt.showDate(today)
|
||
}
|
||
|
||
function getRouteProcessName(route: any) {
|
||
return resolveProcessName(route)
|
||
}
|
||
|
||
function renderGanttData() {
|
||
gantt.clearAll()
|
||
const tasks: any[] = []
|
||
const rawData = toRaw(tableData.value) || []
|
||
|
||
rawData.forEach((mo: any, moIndex: number) => {
|
||
const moId = `mo_${moIndex}_${mo.productionOrderNo}_${mo.billNo}`
|
||
let minDate: Date | null = mo.planStartTime ? new Date(mo.planStartTime.replace(' ', 'T')) : null
|
||
let maxDate: Date | null = mo.planFinishTime ? new Date(mo.planFinishTime.replace(' ', 'T')) : null
|
||
if (!minDate || isNaN(minDate.getTime())) minDate = new Date()
|
||
if (!maxDate || isNaN(maxDate.getTime())) maxDate = new Date(minDate.getTime() + 86400000)
|
||
if (maxDate <= minDate) maxDate = new Date(minDate.getTime() + 86400000)
|
||
|
||
const materialLabel = formatMoMaterialLabel(mo)
|
||
tasks.push({
|
||
id: moId,
|
||
text: materialLabel,
|
||
materialLabel,
|
||
materialCode: mo.materialCode || '',
|
||
materialName: mo.materialName || '',
|
||
operNumber: '',
|
||
processName: '',
|
||
start_date: formatGanttDate(minDate),
|
||
end_date: formatGanttDate(maxDate),
|
||
open: true,
|
||
type: gantt.config.types.project,
|
||
_type: 'mo',
|
||
progress: 0,
|
||
_raw: mo,
|
||
})
|
||
|
||
if (mo.processRoutes?.length > 0) {
|
||
mo.processRoutes.forEach((route: any, index: number) => {
|
||
const routeId = `route_${moId}_${index}`
|
||
let rStart = route.planStartTime ? new Date(route.planStartTime.replace(' ', 'T')) : null
|
||
let rEnd = route.planFinishTime ? new Date(route.planFinishTime.replace(' ', 'T')) : null
|
||
|
||
if (!rStart || isNaN(rStart.getTime())) rStart = minDate
|
||
if (!rEnd || isNaN(rEnd.getTime())) rEnd = maxDate
|
||
if (rEnd <= rStart) rEnd = new Date(rStart!.getTime() + 3600000)
|
||
|
||
const operNumber = route.operNumber != null ? String(route.operNumber) : String(index + 1)
|
||
const routeProcessName = getRouteProcessName(route)
|
||
const colorIndex = getRouteColorIndex(index)
|
||
const routeColor = getRouteColor(index)
|
||
|
||
tasks.push({
|
||
id: routeId,
|
||
text: operNumber,
|
||
operNumber,
|
||
routeProcessName,
|
||
colorIndex,
|
||
routeColor,
|
||
color: routeColor,
|
||
start_date: formatGanttDate(rStart!),
|
||
end_date: formatGanttDate(rEnd),
|
||
parent: moId,
|
||
_type: 'route',
|
||
progress: 0,
|
||
_raw: route,
|
||
})
|
||
})
|
||
}
|
||
})
|
||
|
||
gantt.parse({ data: tasks, links: [] })
|
||
addTodayMarker()
|
||
|
||
const evDragId = gantt.attachEvent('onBeforeTaskDrag', (id) => {
|
||
const task = gantt.getTask(id)
|
||
return task.type !== gantt.config.types.project
|
||
})
|
||
ganttEventIds.push(evDragId)
|
||
|
||
const evId = gantt.attachEvent('onAfterTaskDrag', (id, mode) => {
|
||
const task = gantt.getTask(id)
|
||
if (mode === 'move' || mode === 'resize') {
|
||
const start = gantt.date.date_to_str(gantt.config.date_format)(task.start_date)
|
||
const end = gantt.date.date_to_str(gantt.config.date_format)(task.end_date)
|
||
|
||
if (task._type === 'mo') {
|
||
task._raw.planStartTime = start
|
||
task._raw.planFinishTime = end
|
||
} else if (task._type === 'route') {
|
||
task._raw.planStartTime = start
|
||
task._raw.planFinishTime = end
|
||
|
||
const parentId = task.parent
|
||
if (parentId) {
|
||
const parentTask = gantt.getTask(parentId)
|
||
const children = gantt.getChildren(parentId)
|
||
let minD: Date | null = null
|
||
let maxD: Date | null = null
|
||
|
||
children.forEach((childId: string | number) => {
|
||
const childTask = gantt.getTask(childId)
|
||
const cs = childTask.start_date
|
||
const ce = childTask.end_date
|
||
if (cs && (!minD || cs < minD)) minD = cs
|
||
if (ce && (!maxD || ce > maxD)) maxD = ce
|
||
})
|
||
|
||
if (minD && maxD) {
|
||
parentTask.start_date = new Date(minD)
|
||
parentTask.end_date = new Date(maxD)
|
||
parentTask._raw.planStartTime = gantt.date.date_to_str(gantt.config.date_format)(minD)
|
||
parentTask._raw.planFinishTime = gantt.date.date_to_str(gantt.config.date_format)(maxD)
|
||
gantt.updateTask(parentId)
|
||
}
|
||
}
|
||
}
|
||
|
||
const label = task._type === 'route'
|
||
? (task.routeProcessName || task.operNumber)
|
||
: (task.materialLabel || task.materialName)
|
||
message.success(`任务 [${label}] 计划时间已更新`)
|
||
}
|
||
})
|
||
ganttEventIds.push(evId)
|
||
}
|
||
|
||
onUnmounted(() => {
|
||
ganttEventIds.forEach(id => gantt.detachEvent(id))
|
||
gantt.clearAll()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.gantt-schedule-page {
|
||
--gs-font: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', sans-serif;
|
||
--gs-title: #333333;
|
||
--gs-text: #606266;
|
||
--gs-border: #e4e7ed;
|
||
--gs-bg: #f5f7fa;
|
||
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: calc(100vh - 120px);
|
||
padding: 16px;
|
||
box-sizing: border-box;
|
||
font-family: var(--gs-font);
|
||
font-weight: 400;
|
||
color: var(--gs-text);
|
||
background: var(--gs-bg);
|
||
}
|
||
|
||
.gantt-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
flex-shrink: 0;
|
||
margin-bottom: 12px;
|
||
padding: 14px 16px;
|
||
background: #fff;
|
||
border: 1px solid var(--gs-border);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.gantt-header-left {
|
||
min-width: 0;
|
||
}
|
||
|
||
.page-title {
|
||
margin: 0;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: var(--gs-title);
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.page-desc {
|
||
margin: 4px 0 0;
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
color: var(--gs-text);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.gantt-meta {
|
||
flex-shrink: 0;
|
||
margin-bottom: 12px;
|
||
padding: 0 4px;
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
color: var(--gs-text);
|
||
}
|
||
|
||
.meta-divider {
|
||
margin: 0 10px;
|
||
color: #dcdfe6;
|
||
}
|
||
|
||
.meta-legend {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.legend-today-line {
|
||
display: inline-block;
|
||
width: 2px;
|
||
height: 14px;
|
||
background: #f56c6c;
|
||
border-radius: 1px;
|
||
}
|
||
|
||
.gantt-panel {
|
||
flex: 1;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #fff;
|
||
border: 1px solid var(--gs-border);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.gantt-panel-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
padding: 10px 16px;
|
||
background: #fafafa;
|
||
border-bottom: 1px solid var(--gs-border);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.panel-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: var(--gs-title);
|
||
}
|
||
|
||
.panel-tip {
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
color: #909399;
|
||
}
|
||
|
||
.gantt-container {
|
||
flex: 1;
|
||
width: 100%;
|
||
min-height: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* dhtmlx-gantt:仅表头标题加粗,其余正常字重 */
|
||
.gantt-container :deep(.gantt_container) {
|
||
font-family: var(--gs-font);
|
||
font-weight: 400;
|
||
border: none !important;
|
||
background: #fff;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_grid_scale),
|
||
.gantt-container :deep(.gantt_task_scale) {
|
||
background: #fafafa;
|
||
border-bottom: 1px solid var(--gs-border) !important;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_task_scale .gantt_scale_cell) {
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
color: var(--gs-text);
|
||
border-color: var(--gs-border) !important;
|
||
line-height: 1.3;
|
||
white-space: normal;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_grid_scale .gantt_grid_head_cell) {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--gs-title);
|
||
border-color: var(--gs-border) !important;
|
||
}
|
||
|
||
/* 工序号文字与进度条同色(无圆点) */
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-0 .gantt_cell:first-child) { color: #409eff; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-1 .gantt_cell:first-child) { color: #67c23a; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-2 .gantt_cell:first-child) { color: #e6a23c; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-3 .gantt_cell:first-child) { color: #909399; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-4 .gantt_cell:first-child) { color: #f56c6c; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-5 .gantt_cell:first-child) { color: #36cfc9; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-6 .gantt_cell:first-child) { color: #597ef7; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-7 .gantt_cell:first-child) { color: #9254de; }
|
||
.gantt-container :deep(.gantt_row.gantt-row-route.gantt-route-c-8 .gantt_cell:first-child) { color: #73d13d; }
|
||
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-0) { background-color: #409eff !important; border-color: #409eff !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-1) { background-color: #67c23a !important; border-color: #67c23a !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-2) { background-color: #e6a23c !important; border-color: #e6a23c !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-3) { background-color: #909399 !important; border-color: #909399 !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-4) { background-color: #f56c6c !important; border-color: #f56c6c !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-5) { background-color: #36cfc9 !important; border-color: #36cfc9 !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-6) { background-color: #597ef7 !important; border-color: #597ef7 !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-7) { background-color: #9254de !important; border-color: #9254de !important; }
|
||
.gantt-container :deep(.gantt_task_line.gantt-route-c-8) { background-color: #73d13d !important; border-color: #73d13d !important; }
|
||
|
||
.gantt-container :deep(.gantt_task_line.gantt-task-route .gantt_task_progress) {
|
||
background-color: rgba(0, 0, 0, 0.18) !important;
|
||
opacity: 1;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_task_line.gantt-task-route) {
|
||
border: none !important;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_grid_data .gantt_cell) {
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
color: var(--gs-text);
|
||
border-color: #f0f2f5 !important;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_row.gantt-row-mo) {
|
||
background: #fafafa;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_row.gantt-row-mo .gantt_cell) {
|
||
font-weight: 400;
|
||
color: var(--gs-title);
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_row:hover) {
|
||
background: #f5f7fa !important;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_task_row.gantt_selected),
|
||
.gantt-container :deep(.gantt_row.gantt_selected) {
|
||
background: #ecf5ff !important;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_task_line.gantt-task-route .gantt_task_content) {
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
color: #fff;
|
||
padding: 0 6px;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_task_line.gantt_project) {
|
||
display: none;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_weekend) {
|
||
background: #fafafa;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_marker.today-marker) {
|
||
background: #f56c6c;
|
||
width: 2px;
|
||
z-index: 4;
|
||
opacity: 1;
|
||
}
|
||
|
||
.gantt-container :deep(.today-marker .gantt_marker_content) {
|
||
background: #f56c6c;
|
||
color: #fff;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
border-radius: 2px;
|
||
padding: 2px 8px;
|
||
box-shadow: 0 1px 4px rgba(245, 108, 108, 0.35);
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_layout_content) {
|
||
border-color: var(--gs-border) !important;
|
||
}
|
||
|
||
.gantt-container :deep(.gantt_hor_scroll),
|
||
.gantt-container :deep(.gantt_ver_scroll) {
|
||
background: #fafafa;
|
||
}
|
||
</style>
|