<template>
|
<div class="main-layout" ref="mainLayout">
|
<div class="header" ref="headerLayout">
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
<el-tab-pane label="项目部分" name="project"></el-tab-pane>
|
<el-tab-pane label="商务部分" name="business"></el-tab-pane>
|
</el-tabs>
|
|
<div class="search-section">
|
<el-form
|
:model="formData"
|
:inline="true"
|
label-width="auto"
|
ref="form"
|
@submit.prevent
|
:rules="rules"
|
size="small"
|
>
|
<el-form-item label="所属项目" prop="projectList">
|
<el-select
|
v-model="formData.projectList"
|
placeholder="所属项目"
|
clearable
|
filterable
|
class="selectClass"
|
multiple
|
>
|
<el-option v-for="item in projectInfoArr" :key="item.id" :label="item.project_name" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="阶段">
|
<el-select v-model="formData.stage" placeholder="阶段" clearable filterable>
|
<el-option v-for="item in projectStageArr" :key="item.value" :label="item.label" :value="item.value" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="状态">
|
<el-select v-model="formData.statusList" placeholder="类型" clearable filterable multiple>
|
<el-option v-for="item in projectStatusArr" :key="item.value" :label="item.label" :value="item.value" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item class="submit">
|
<el-button type="primary" @click="search">查询</el-button>
|
<el-button @click="resetForm">重 置</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
</div>
|
|
<!-- :cell-class-name="handleTableCellClass" -->
|
<el-table
|
:data="boardList"
|
:height="tableHeight"
|
style="margin-right: 10px"
|
:cell-style="handleCellStyle"
|
:span-method="spanMethod"
|
>
|
<el-table-column prop="no" label="序号" width="100" />
|
<el-table-column prop="project_name" label="项目名称" width="150">
|
<template #default="{ row }">
|
<!-- {{ row[day] }} -->
|
<el-link @click="handleProjectClick(row)">{{ row.project_name }}</el-link>
|
</template>
|
</el-table-column>
|
|
<el-table-column prop="project" label="项目" width="150" />
|
<el-table-column prop="start_date" label="开始日期" width="150" />
|
<el-table-column prop="end_date" label="结束日期" width="150" />
|
<el-table-column prop="total_days" label="总天数" width="150" />
|
<el-table-column prop="project_status" label="当前状态" width="150" />
|
|
<!-- 动态多级表头 -->
|
<!-- <el-table-column v-for="(months, year) in groupedColumns" :key="year" :label="year" align="center" >
|
<el-table-column v-for="(days, month) in months" :key="month" :label="month" align="center ">
|
<el-table-column v-for="day in days" :key="day" :prop="day" :label="day.split('-')[2]" align="center">
|
<template #header="scope" >
|
<div>
|
<div>{{ day.split('-')[2] }}</div>
|
<div style="font-size: 12px">{{ formatWeekday(day) }}</div>
|
</div>
|
</template>
|
<template #default="{ row }">
|
{{ row[day] }}
|
{{}}
|
</template>
|
</el-table-column>
|
</el-table-column>
|
</el-table-column> -->
|
<!-- 动态多级表头 -->
|
<el-table-column v-for="{ year, months } in groupedColumns" :key="year" :label="year" align="center">
|
<el-table-column v-for="{ month, days } in months" :key="month" :label="month" align="center">
|
<el-table-column v-for="day in days" :key="day" :prop="day" :label="day.split('-')[2]" align="center">
|
<template #header="scope">
|
<div>
|
<div>{{ day.split('-')[2] }}</div>
|
<div style="font-size: 12px">{{ formatWeekday(day) }}</div>
|
</div>
|
</template>
|
<template #default="{ row }">
|
<!-- {{ row[day] }} -->
|
{{}}
|
</template>
|
</el-table-column>
|
</el-table-column>
|
</el-table-column>
|
</el-table>
|
|
<el-drawer v-model="addDrawer" :before-close="handleItemClose">
|
<project-pro-bus-edit
|
@editClose="handleProjectProBusClose"
|
:editId="project.id"
|
:key="uniKey"
|
:showBack="false"
|
:projectType="activeTab"
|
></project-pro-bus-edit>
|
</el-drawer>
|
</div>
|
</template>
|
|
<script>
|
import { reactive, ref, onMounted, onUnmounted, nextTick } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import ProjectInfo from '@/model/projectInfo'
|
|
import { getDefaultDate, getYesterdayDate, getStartAndEndOfWeek, getPreviousWeekDates } from '@/utils/dateUtils'
|
import { debounce } from 'lodash'
|
import ProjectDaily from '@/model/projectDaily'
|
import SysDictItemModel from '@/model/sysDictItem'
|
import ProjectProBusEdit from '@/view/project/project-pro-bus-edit'
|
|
export default {
|
components: {
|
ProjectProBusEdit,
|
},
|
props: {},
|
setup(props, context) {
|
// 防抖函数,避免动态表格数据变化时产生的抖动
|
const resizeObserver = window.ResizeObserver
|
|
window.ResizeObserver = class extends resizeObserver {
|
constructor(callback) {
|
const debouncedCallback = debounce(callback, 100)
|
super(debouncedCallback)
|
}
|
}
|
|
const windowWidth = ref(window.innerWidth)
|
const mainLayout = ref(null)
|
const headerLayout = ref(null)
|
const tableHeight = ref(null)
|
const tableKey = ref(0)
|
|
const handleResize = () => {
|
nextTick(() => {
|
if (mainLayout.value && headerLayout.value) {
|
tableHeight.value = window.innerHeight - headerLayout.value.clientHeight - 100
|
tableKey.value++
|
}
|
})
|
}
|
|
onUnmounted(() => {
|
window.removeEventListener('resize', handleResize)
|
})
|
|
const loading = ref(false)
|
const form = ref({})
|
|
const activeTab = ref('project')
|
const userList = ref([])
|
const firstColumnWidth = '80px'
|
const minColumnWidth = '350px'
|
const projectInfoArr = ref([])
|
const projectStatusArr = ref([])
|
const projectStageArr = ref([])
|
|
const formData = reactive({
|
project_board_type: 'project',
|
startDate: '',
|
endDate: '',
|
create_user_id: '',
|
projectList: [],
|
statusList: [],
|
stage: '',
|
})
|
|
const tableColumns = ref([
|
{ label: '姓名', prop: 'name' },
|
{ label: '年龄', prop: 'age' },
|
// 其他列信息
|
])
|
|
const tableRows = ref([
|
{ name: 'Alice', age: 25 },
|
{ name: 'Bob', age: 30 },
|
// 其他行信息
|
])
|
|
const listAssign = (a, b) => Object.keys(a).forEach(key => {
|
a[key] = b[key] || a[key]
|
})
|
|
onMounted(() => {
|
// 列出所有项目信息
|
// getDiaryPage()
|
loadDictDitems()
|
// 默认设置当前为项目
|
formData.project_board_type = 'project'
|
// 当为项目的时候,只看开发阶段的项目
|
formData.stage = '2'
|
getProjectBoardList()
|
|
handleResize()
|
window.addEventListener('resize', handleResize)
|
})
|
|
/**
|
* 表格内容自动换行
|
*/
|
const formatColumnContent = (row, content) => {
|
if (content) {
|
return content.replace(/\n/g, '<br>')
|
}
|
return content
|
}
|
|
/**
|
* 表单规则验证
|
*/
|
const { rules } = getRules()
|
|
const boardList = ref(null)
|
const dyColumns = ref(null)
|
const groupedColumns = ref(null)
|
const getProjectBoardList = async () => {
|
try {
|
tableColumns.value = []
|
tableRows.value = []
|
|
const params = {
|
project_board_type: formData.project_board_type,
|
projecdt_list: formData.projectList,
|
status_list: formData.statusList,
|
stage: formData.stage,
|
}
|
loading.value = true
|
|
boardList.value = []
|
dyColumns.value = []
|
groupedColumns.value = []
|
|
const result = await ProjectInfo.getProjectBoard(params)
|
|
boardList.value = result.result_list
|
dyColumns.value = result.columns
|
groupedColumns.value = getGroupedColumns()
|
|
loading.value = false
|
} catch (error) {
|
console.log(error)
|
loading.value = false
|
if (error.code === 10020) {
|
tableData.value = []
|
}
|
}
|
}
|
|
const getGroupedColumns2 = columns => {
|
const groups = {}
|
dyColumns.value.forEach(column => {
|
const [year, month, day] = column.split('-')
|
if (!groups[year]) {
|
groups[year] = {}
|
}
|
if (!groups[year][month]) {
|
groups[year][month] = []
|
}
|
groups[year][month].push(column)
|
})
|
console.log(groups)
|
return groups
|
}
|
const getGroupedColumns = () => {
|
const groups = {}
|
dyColumns.value.forEach(column => {
|
const [year, month, day] = column.split('-')
|
if (!groups[year]) {
|
groups[year] = {}
|
}
|
if (!groups[year][month]) {
|
groups[year][month] = []
|
}
|
groups[year][month].push(column)
|
})
|
|
// 对每年的月份进行排序
|
const sortedGroups = []
|
Object.keys(groups)
|
.sort((a, b) => parseInt(a) - parseInt(b))
|
.forEach(year => {
|
const months = []
|
Object.keys(groups[year])
|
.sort((a, b) => parseInt(a) - parseInt(b))
|
.forEach(month => {
|
const days = groups[year][month].sort((a, b) => parseInt(a.split('-')[2]) - parseInt(b.split('-')[2]))
|
months.push({ month, days })
|
})
|
sortedGroups.push({ year, months })
|
})
|
|
return sortedGroups
|
}
|
|
const formatWeekday = dateString => {
|
const date = new Date(dateString)
|
const weekdays = ['日', '一', '二', '三', '四', '五', '六']
|
return `周${weekdays[date.getDay()]}`
|
}
|
|
const handleTabClick = tab => {
|
formData.project_board_type = tab.props.name
|
switch (tab.props.name) {
|
case 'project':
|
formData.stage = '2'
|
break
|
case 'business':
|
formData.stage = '0'
|
break
|
}
|
getProjectBoardList()
|
}
|
|
const startPickerOptions = {
|
disabledDate: time => {
|
if (formData.endDate) {
|
return time.getTime() > formData.endDate
|
}
|
return false
|
},
|
}
|
|
const endPickerOptions = {
|
disabledDate: time => {
|
if (formData.startDate) {
|
return time.getTime() < formData.startDate
|
}
|
return false
|
},
|
}
|
|
// 重置表单
|
const resetForm = () => {
|
form.value.resetFields()
|
formData.project_board_type = 'project'
|
formData.projectList - []
|
formData.statusList = []
|
formData.stage = '2'
|
}
|
|
const search = formName => {
|
form.value.validate(valid => {
|
if (valid) {
|
if (formData.startDate > formData.endDate) {
|
ElMessage.error('开始时间不能大于结束时间')
|
return
|
}
|
let res = {}
|
res = getProjectBoardList()
|
if (res.code < window.MAX_SUCCESS_CODE) {
|
ElMessage.success(`${res.message}`)
|
}
|
} else {
|
console.error('error submit!!')
|
ElMessage.error('请将信息填写完整')
|
}
|
})
|
}
|
|
// 根据字典类型查询字典
|
const loadDictDitems = async () => {
|
// userList.value = await ProjectDaily.getAllUsers()
|
projectInfoArr.value = await ProjectInfo.getProjectInfoList('')
|
projectStatusArr.value = await SysDictItemModel.getSysDictItemListByType('project_status')
|
projectStageArr.value = await SysDictItemModel.getSysDictItemListByType('project_stage')
|
}
|
|
const handleCellClassName = ({ row, column, rowIndex, columnIndex }) => 'wrap-text'
|
|
// span-method 实现单元格合并逻辑
|
const spanMethod = ({ row, column, rowIndex, columnIndex }) => {
|
// 当前行的 id
|
const currentId = row.id
|
// 上一行的 id
|
const previousId = rowIndex > 0 ? boardList.value[rowIndex - 1].id : null
|
|
// if (columnIndex === 0 || columnIndex === 1 || columnIndex === 5 || columnIndex === 6) {
|
if (columnIndex === 0 || columnIndex === 1 || columnIndex === 6) {
|
if (currentId === previousId) {
|
// 如果 id 相同,合并当前单元格与上一行的单元格
|
return {
|
rowspan: 0,
|
colspan: 0,
|
}
|
}
|
// 如果 id 不同,保留当前单元格,并合并
|
return {
|
rowspan: 2,
|
colspan: 1,
|
}
|
}
|
return {
|
rowspan: 1,
|
colspan: 1,
|
}
|
}
|
|
const handleTableCellClass = ({ row, column, rowIndex, columnIndex }) => 'planActualClass'
|
|
const handleCellStyle = ({ row, column, rowIndex, columnIndex }) => {
|
if (columnIndex >= 7) {
|
// console.log("column")
|
// console.log(column)
|
// console.log("值")
|
// console.log(row[column.property])
|
if (row.project == '实际' && row[column.property] == 1) {
|
return { backgroundColor: '#575280', border: 'none' }
|
}
|
if (row.project == '计划' && row[column.property] == 1) {
|
return { backgroundColor: '#7c9ac0', border: 'none' }
|
}
|
}
|
}
|
|
const addDrawer = ref(false)
|
const uniKey = ref(0)
|
const project = ref({
|
id: '',
|
})
|
const handleProjectClick = row => {
|
project.value = row
|
uniKey.value++
|
addDrawer.value = true
|
}
|
|
const handleProjectProBusClose = () => {
|
uniKey.value++
|
addDrawer.value = false
|
project.value = {}
|
getProjectBoardList()
|
}
|
|
const handleItemClose = () => {
|
uniKey.value++
|
addDrawer.value = false
|
project.value = {}
|
getProjectBoardList()
|
}
|
|
return {
|
activeTab,
|
formData,
|
form,
|
rules,
|
tableColumns,
|
tableRows,
|
|
handleTabClick,
|
search,
|
resetForm,
|
userList,
|
|
startPickerOptions,
|
endPickerOptions,
|
|
formatColumnContent,
|
handleCellClassName,
|
|
firstColumnWidth,
|
minColumnWidth,
|
|
projectInfoArr,
|
projectStatusArr,
|
projectStageArr,
|
|
windowWidth,
|
|
mainLayout,
|
headerLayout,
|
tableHeight,
|
tableKey,
|
|
boardList,
|
dyColumns,
|
groupedColumns,
|
formatWeekday,
|
spanMethod,
|
handleTableCellClass,
|
handleCellStyle,
|
handleProjectClick,
|
|
addDrawer,
|
uniKey,
|
project,
|
handleProjectProBusClose,
|
handleItemClose,
|
}
|
},
|
}
|
|
/**
|
* 表单验证规则
|
*/
|
function getRules() {
|
/**
|
* 验证回调函数
|
*/
|
const checkInfo = (rule, value, callback) => {
|
if (!value) {
|
callback(new Error('信息不能为空'))
|
}
|
callback()
|
}
|
|
const checkDate = (rule, value, callback) => {
|
if (!value) {
|
callback(new Error('信息不能为空'))
|
}
|
|
callback()
|
}
|
|
const rules = {
|
startDate: [{ validator: checkDate, trigger: 'blur', required: true }],
|
endDate: [{ validator: checkDate, trigger: 'blur', required: true }],
|
}
|
return { rules }
|
}
|
</script>
|
|
<style scoped>
|
.main-layout {
|
display: flex;
|
flex-direction: column;
|
padding: 10px;
|
height: 100%;
|
/* height: 100vh; */
|
}
|
|
.header {
|
/* padding-left: 10px; */
|
/* background-color: #f0f0f0; */
|
text-align: center;
|
}
|
|
.flex-container {
|
flex: 1;
|
display: flex;
|
overflow: hidden;
|
}
|
|
.sidebar {
|
flex: 0 0 300px;
|
/* 左侧宽度固定为300px */
|
background-color: #f7f7f7;
|
overflow-y: auto;
|
padding: 20px;
|
}
|
|
.main-content {
|
flex: 1;
|
background-color: #ffffff;
|
overflow-x: auto;
|
padding: 10px;
|
overflow-y: hidden;
|
}
|
|
.dynamic_table {
|
overflow-x: auto;
|
width: 100%;
|
}
|
|
.wrap-text {
|
white-space: pre-line !important;
|
/* 使用 pre-line 属性实现自动换行 */
|
}
|
|
.search-section {
|
/* margin-bottom: 10px; */
|
padding: 10px;
|
/* background-color: #f5f5f5; */
|
border-radius: 4px;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
display: flex;
|
justify-content: flex-start;
|
height: 60px;
|
overflow-y: scroll;
|
}
|
|
.selectClass {
|
width: 220px;
|
}
|
|
.el-table .plan-row {
|
background: #7c9ac0;
|
}
|
.el-table .actual-row {
|
background: #575280;
|
}
|
|
.planActualClass {
|
width: 100%;
|
height: 100%;
|
background: #7c9ac0;
|
}
|
|
.el-table .planActualClass {
|
width: 100%;
|
height: 100%;
|
background: #7c9ac0;
|
}
|
|
.el-table .cell {
|
border: none !important;
|
}
|
|
.el-form-item {
|
width: 260px !important;
|
}
|
</style>
|