日志基本完成
parent
b5f23e89d8
commit
29a27ab0aa
|
@ -1,5 +1,6 @@
|
|||
VITE_BASE_URL = '/pms-front-test'
|
||||
VITE_BASE_NAME = "pms-front-test"
|
||||
VITE_BASE_URL = "./"
|
||||
VITE_BASE_NAME = "dev"
|
||||
VITE_APP_PROXYURL = 'http://192.168.124.202:8080'
|
||||
VITE_APP_REQUESTURL = '/pms-front-test'
|
||||
VITE_APP_ROUTERURL = '/pms-front-test/'
|
||||
VITE_APP_REQUESTURL = '/prod-api'
|
||||
VITE_APP_ROUTERURL = '/dev/'
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ lerna-debug.log*
|
|||
|
||||
node_modules
|
||||
pms-front
|
||||
pms-front-test
|
||||
dev
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 556 B |
|
@ -7,6 +7,7 @@
|
|||
v-bind="$attrs"
|
||||
@selection-change="handleSelectionChange"
|
||||
:border="border"
|
||||
:highlight-current-row="highligt"
|
||||
>
|
||||
<el-table-column v-if="showSelection" type="selection" width="55" />
|
||||
<el-table-column v-if="showIndex" type="index" width="50" label="序号" />
|
||||
|
@ -28,8 +29,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.type === 'status'">
|
||||
<span v-if="column.callback" v-html="column.callback(scope.row[column.prop], scope.row)">
|
||||
</span>
|
||||
<span v-if="column.callback" v-html="column.callback(scope.row[column.prop], scope.row)"></span>
|
||||
<span v-else>
|
||||
{{ scope.row[column.prop] }}
|
||||
</span>
|
||||
|
@ -90,8 +90,8 @@ const props = defineProps({
|
|||
default: () => [10, 20, 30, 50],
|
||||
},
|
||||
maxHeight: {
|
||||
type: Number,
|
||||
default: null,
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
offsetHeight: {
|
||||
type: Number,
|
||||
|
@ -101,6 +101,14 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
multiSelect: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
highligt: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['selection-change', 'size-change', 'current-change', 'button-click'])
|
||||
|
@ -128,7 +136,7 @@ const handleCurrentChange = val => {
|
|||
|
||||
const updateTableHeight = () => {
|
||||
nextTick(() => {
|
||||
if (tableContainer.value && paginationContainer.value) {
|
||||
if (tableContainer.value) {
|
||||
const parentElement = tableContainer.value.parentElement
|
||||
const parentHeight = parentElement.clientHeight
|
||||
const tableTop = tableContainer.value.getBoundingClientRect().top - parentElement.getBoundingClientRect().top
|
||||
|
@ -161,36 +169,38 @@ onUnmounted(() => {
|
|||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
.pagination-container {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
:deep(.el-scrollbar__wrap--hidden-default){
|
||||
:deep(.el-scrollbar__wrap--hidden-default) {
|
||||
min-height: 100px;
|
||||
}
|
||||
:deep(.el-table) {
|
||||
:deep(.el-table) {
|
||||
--el-table-text-align: center;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
:deep(.el-table th) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.el-table .cell) {
|
||||
:deep(.el-table .cell) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 如果操作列需要特殊处理,可以添加以下样式 */
|
||||
:deep(.operation-column .cell) {
|
||||
:deep(.operation-column .cell) {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
:deep(.el-table__inner-wrapper::before){
|
||||
|
||||
display: none;
|
||||
|
||||
:deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.el-table-column--selection) {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
|
@ -13,6 +13,7 @@
|
|||
:show-selection="true"
|
||||
:show-index="true"
|
||||
:table-height="tableHeight"
|
||||
:multiSelect="multiSelect"
|
||||
@selection-change="handleSelectionChange"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
|
@ -38,7 +39,8 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch, onMounted, nextTick } from 'vue'
|
||||
import CustomTable from '@/components/table.vue'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
import { systemApi } from '@/utils/api'
|
||||
|
||||
const props = defineProps({
|
||||
multiSelect: {
|
||||
|
@ -59,18 +61,13 @@ const emit = defineEmits(['update:dialogVisible', 'close', 'confirm'])
|
|||
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(100)
|
||||
const total = ref(0)
|
||||
const selectedUsers = ref([])
|
||||
const currentDepartment = ref('')
|
||||
const tableHeight = ref(350) // 设置一个合适的高度
|
||||
|
||||
// 组织树假数据
|
||||
const treeData = [
|
||||
{
|
||||
label: '运维团队',
|
||||
children: [{ label: '外场人员' }, { label: '内场人员' }, { label: '外场临时人员' }],
|
||||
},
|
||||
]
|
||||
const treeData = ref([])
|
||||
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
|
@ -79,35 +76,16 @@ const defaultProps = {
|
|||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{ prop: 'name', label: '姓名' },
|
||||
{ prop: 'department', label: '部门' },
|
||||
{ prop: 'role', label: '角色' },
|
||||
{ prop: 'nickName', label: '姓名' },
|
||||
{ prop: 'dept', label: '部门', type: 'status', callback: (data, row) => data?.deptName },
|
||||
{ prop: 'roles', label: '角色', type: 'status', callback: (data, row) => data.map(ele => ele.roleName).join(',') },
|
||||
]
|
||||
|
||||
// 用户列表假数据
|
||||
const allUserData = reactive(
|
||||
Array(100)
|
||||
.fill(null)
|
||||
.map((_, index) => ({
|
||||
id: index + 1,
|
||||
name: `张三${index + 1}`,
|
||||
department: ['外场人员', '内场人员', '外场临时人员'][index % 3],
|
||||
role: '客户经理',
|
||||
})),
|
||||
)
|
||||
|
||||
const userData = computed(() => {
|
||||
let filteredData = allUserData
|
||||
if (currentDepartment.value) {
|
||||
filteredData = allUserData.filter(user => user.department === currentDepartment.value)
|
||||
}
|
||||
const start = (currentPage.value - 1) * pageSize.value
|
||||
const end = start + pageSize.value
|
||||
return filteredData.slice(start, end)
|
||||
})
|
||||
const userData = ref([])
|
||||
|
||||
const handleNodeClick = data => {
|
||||
currentDepartment.value = data.label
|
||||
currentDepartment.value = data.id
|
||||
currentPage.value = 1
|
||||
fetchUserList()
|
||||
}
|
||||
|
@ -165,7 +143,7 @@ watch(
|
|||
if (customTableRef.value) {
|
||||
customTableRef.value.clearSelection()
|
||||
newVal.forEach(user => {
|
||||
const row = allUserData.find(item => item.id === user.id)
|
||||
const row = userData.value.find(item => item.userId === user.userId)
|
||||
if (row) {
|
||||
customTableRef.value.toggleRowSelection(row, true)
|
||||
}
|
||||
|
@ -183,7 +161,7 @@ onMounted(() => {
|
|||
if (customTableRef.value && props.currentSelectedUser.length > 0) {
|
||||
customTableRef.value.clearSelection()
|
||||
props.currentSelectedUser.forEach(user => {
|
||||
const row = allUserData.find(item => item.id === user.id)
|
||||
const row = userData.value.find(item => item.userId === user.userId)
|
||||
if (row) {
|
||||
customTableRef.value.toggleRowSelection(row, true)
|
||||
}
|
||||
|
@ -194,24 +172,23 @@ onMounted(() => {
|
|||
|
||||
const fetchUserList = async () => {
|
||||
// 在实际应用中,这里应该调用后端 API
|
||||
// const response = await api.getUserList({
|
||||
// page: currentPage.value,
|
||||
// pageSize: pageSize.value,
|
||||
// department: currentDepartment.value
|
||||
// })
|
||||
// allUserData = response.data.list
|
||||
// total.value = response.data.total
|
||||
|
||||
// 使用假数据模拟
|
||||
total.value = allUserData.filter(
|
||||
user => !currentDepartment.value || user.department === currentDepartment.value,
|
||||
).length
|
||||
const response = await systemApi.getUserList({
|
||||
pageNum: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
deptId: currentDepartment.value,
|
||||
})
|
||||
userData.value = response.rows
|
||||
total.value = response.total
|
||||
}
|
||||
const fetchTreeData = async () => {
|
||||
const response = await systemApi.getDeptTree()
|
||||
treeData.value = response.data
|
||||
}
|
||||
|
||||
// 可以在组件挂载时调用这个方法获取初始数据
|
||||
// onMounted(() => {
|
||||
// fetchUserList()
|
||||
// })
|
||||
onMounted(() => {
|
||||
fetchTreeData()
|
||||
fetchUserList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -251,4 +228,4 @@ const fetchUserList = async () => {
|
|||
.dialog-footer .el-button:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -4,9 +4,9 @@ export const loginApi = {
|
|||
// 登录
|
||||
login: data => request('/login', 'json', data),
|
||||
// 退出登录
|
||||
loginOut: () => request('/aiops-api/logout', 'get'),
|
||||
loginOut: () => request('/logout', 'get'),
|
||||
//修改密码
|
||||
editPassword: data => request('/aiops-api/auth/user/updatePwd', 'post', data),
|
||||
editPassword: data => request('/auth/user/updatePwd', 'post', data),
|
||||
// 获取验证码
|
||||
getCode: () => request('/captchaImage', 'captchaImage', {}, {
|
||||
SHOW_LOADING: false, headers: {
|
||||
|
@ -30,7 +30,13 @@ export const projectApi = {
|
|||
updateProjectUser: data => request('/business/project/team', 'json', data),
|
||||
deleteProjectUser: id => request(`/business/project/team/${id}`, 'delete'),
|
||||
}
|
||||
|
||||
// 工作日志
|
||||
export const workLogApi = {
|
||||
userProject: id => request(`/business/work/hour/project/${id}`, 'get'),
|
||||
getLogData: data => request('/business/work/hour/calendar', 'json', data, { SHOW_LOADING: false }),
|
||||
getLogDataDetail: data => request('/business/work/hour/getInfo', 'json', data, { SHOW_LOADING: false }),
|
||||
addLog: data => request('/business/work/hour/add', 'json', data),
|
||||
}
|
||||
// 用户板块
|
||||
export const useUserApi = () => {
|
||||
|
||||
|
@ -38,8 +44,9 @@ export const useUserApi = () => {
|
|||
}
|
||||
// 系统板块
|
||||
export const systemApi = {
|
||||
getUserList: data => request('/aiops-api/auth/user/list', 'post', data),
|
||||
getUserList: data => request('/system/user/list', 'get', data),
|
||||
getDictData: dictCode => request('/system/dict/data/type/' + dictCode, 'get'),
|
||||
getDeptTree: () => request('/system/user/deptTree', 'get'),
|
||||
}
|
||||
// 系统定时任务
|
||||
export const systemJobApi = {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目编码" prop="projectCode">
|
||||
<el-input v-model="formData.projectCode" class="full-width" disabled />
|
||||
<el-input v-model="formData.projectCode" class="full-width" :disabled="isEditing" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
|
@ -158,7 +158,7 @@
|
|||
<!-- 删除确认对话框 -->
|
||||
<el-dialog v-model="deleteDialogVisible" title="确认删除" width="30%">
|
||||
<div class="delete-confirm">
|
||||
<img src="@/assets/warning.png" alt="警告" class="warning-icon" />
|
||||
<el-icon class="warning-icon"><WarningFilled /></el-icon>
|
||||
<p>确定要删除该成员吗?此操作不可逆。</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
|
@ -174,8 +174,8 @@
|
|||
<script setup>
|
||||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import CustomTable from '@/components/table.vue'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
import { Plus,WarningFilled } from '@element-plus/icons-vue'
|
||||
import SelectUser from '@/components/SelectUser.vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { projectApi, systemApi } from '@/utils/api'
|
||||
|
@ -382,8 +382,8 @@ const handleUserConfirm = selectedUsers => {
|
|||
|
||||
if (selectedUsers.length > 0) {
|
||||
const selectedUser = selectedUsers[0]
|
||||
currentEditingRow.value.userName = selectedUser.name
|
||||
currentEditingRow.value.userId = selectedUser.id
|
||||
currentEditingRow.value.userName = selectedUser.nickName
|
||||
currentEditingRow.value.userId = selectedUser.userId
|
||||
} else {
|
||||
currentEditingRow.value.name = ''
|
||||
currentEditingRow.value.userId = null
|
||||
|
@ -407,8 +407,8 @@ const openProjectManagerSelect = () => {
|
|||
const handleProjectManagerConfirm = users => {
|
||||
if (users.length > 0) {
|
||||
const selectedUser = users[0]
|
||||
formData.projectLeaderName = selectedUser.name
|
||||
formData.projectLeader = selectedUser.id
|
||||
formData.projectLeaderName = selectedUser.nickName
|
||||
formData.projectLeader = selectedUser.userId
|
||||
} else {
|
||||
formData.projectLeaderName = ''
|
||||
formData.projectLeader = null
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import CustomTable from '@/components/table.vue'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
import SelectUser from '@/components/selectUser.vue'
|
||||
import { WarningFilled } from '@element-plus/icons-vue'
|
||||
import { projectApi } from '@/utils/api'
|
||||
|
@ -177,8 +177,8 @@ const handleUserSelectClose = () => {
|
|||
const handleUserConfirm = (selectedUsers) => {
|
||||
if (selectedUsers.length > 0) {
|
||||
const selectedUser = selectedUsers[0]
|
||||
searchForm.projectLeaderName = selectedUser.name
|
||||
searchForm.projectLeader = selectedUser.id
|
||||
searchForm.projectLeaderName = selectedUser.nickName
|
||||
searchForm.projectLeader = selectedUser.userId
|
||||
currentSelectedUser.value = [selectedUser]
|
||||
} else {
|
||||
searchForm.projectLeaderName = ''
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import CustomTable from '@/components/table.vue'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
|
@ -60,9 +60,9 @@ function getDefaultDateRange() {
|
|||
}
|
||||
|
||||
const fixedColumns = [
|
||||
{ prop: 'name', label: '项目', width: 200, slot: 'name' },
|
||||
{ prop: 'presetDays', label: '预计工时\n(天)', width: 150 },
|
||||
{ prop: 'actualDays', label: '累计工时\n(天)', width: 150 },
|
||||
{ prop: 'name', label: '项目', slot: 'name' },
|
||||
{ prop: 'presetDays', label: '预计工时\n(天)', width: 100 },
|
||||
{ prop: 'actualDays', label: '累计工时\n(天)', width: 100 },
|
||||
]
|
||||
|
||||
const scrollableColumns = computed(() => {
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import CustomTable from '@/components/table.vue'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import CustomTable from '@/components/table.vue'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
import SelectUser from '@/components/selectUser.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
|
|
@ -289,7 +289,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
|||
import { Search } from '@element-plus/icons-vue'
|
||||
import { systemJobApi } from '@/utils/api.js'
|
||||
import Crontab from '@/components/Crontab'
|
||||
import Table from '@/components/table.vue'
|
||||
import Table from '@/components/CustomTable.vue'
|
||||
import Card from '@/components/Card.vue'
|
||||
|
||||
const dict = ref({
|
||||
|
|
|
@ -72,7 +72,7 @@ import EditPerson from './compontents/EditPerson.vue'
|
|||
import { Search } from '@element-plus/icons-vue'
|
||||
import { systemApi } from '@/utils/api.js'
|
||||
import { listTotree } from '@/utils/tree.js'
|
||||
import Table from '@/components/table.vue'
|
||||
import Table from '@/components/CustomTable.vue'
|
||||
import Card from '@/components/Card.vue'
|
||||
|
||||
const handleCheckChange = (data, checked, indeterminate) => {
|
||||
|
|
|
@ -13,38 +13,40 @@
|
|||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
<CustomTable
|
||||
v-show="!isCollapsed"
|
||||
:data="projectList"
|
||||
style="width: 100%"
|
||||
:columns="[
|
||||
{ prop: 'name', label: '项目', align: 'center' },
|
||||
{ prop: 'workDay', label: '工时(天)', align: 'center' },
|
||||
]"
|
||||
:tableData="projectList"
|
||||
@row-click="handleProjectClick"
|
||||
highlight-current-row
|
||||
:show-summary="true"
|
||||
:summary-method="getSummaries"
|
||||
sum-text="合计工时(h)"
|
||||
>
|
||||
<el-table-column prop="name" label="项目" align="center"></el-table-column>
|
||||
<el-table-column prop="workHours" label="工时(小时)" align="center"></el-table-column>
|
||||
</el-table>
|
||||
:showPagination="false"
|
||||
:highligt="true"
|
||||
ref="projectRef"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 右侧项目信息和日历 -->
|
||||
<div class="project-info-calendar">
|
||||
<h2 class="mb20 textC">工作日志</h2>
|
||||
<!-- 项目信息表单 -->
|
||||
<el-form :model="projectInfo" label-width="100px" disabled class="project-info-form">
|
||||
<el-form :model="projectInfo" label-width="100px" disabled class="project-info-form log-form">
|
||||
<el-form-item label="项目名称">
|
||||
<el-input v-model="projectInfo.name"></el-input>
|
||||
<el-input v-model="projectInfo.projectName"></el-input>
|
||||
</el-form-item>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目编号">
|
||||
<el-input v-model="projectInfo.code"></el-input>
|
||||
<el-input v-model="projectInfo.projectCode"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工时填报人">
|
||||
<el-input v-model="projectInfo.reporter"></el-input>
|
||||
<el-input v-model="projectInfo.nickName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
@ -62,11 +64,11 @@
|
|||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 日历选择器 -->
|
||||
<!-- 日<EFBFBD><EFBFBD><EFBFBD>选择器 -->
|
||||
|
||||
<!-- 日历视图 -->
|
||||
<div class="calendar-view" v-if="currentProject">
|
||||
<el-calendar v-model="selectedDate" @input="handleMonthChange">
|
||||
<div class="calendar-view" v-if="projectInfo">
|
||||
<el-calendar v-model="selectedDate" @input="updateDateColors">
|
||||
<template #header="{ date }">
|
||||
<div class="calendar-header">
|
||||
<el-date-picker v-model="selectedDate" type="month" format="YYYY年MM月" :clearable="false" />
|
||||
|
@ -74,6 +76,8 @@
|
|||
</template>
|
||||
<template #dateCell="{ data }">
|
||||
<div
|
||||
:key="data.day"
|
||||
:id="data.day"
|
||||
@click="openLogDialog(data)"
|
||||
:class="{
|
||||
'date-cell': true,
|
||||
|
@ -91,16 +95,16 @@
|
|||
|
||||
<!-- 工作日志对话框 -->
|
||||
<el-dialog v-model="logDialogVisible" title="工作日志" width="30%">
|
||||
<el-form :model="logForm" label-width="100px" class="log-form">
|
||||
<el-form-item label="日期">
|
||||
<el-input v-model="logForm.date" disabled></el-input>
|
||||
<el-form :model="logForm" label-width="120px" class="log-form">
|
||||
<el-form-item label="工作时长(小时)">
|
||||
<el-input v-model.number="logForm.workTime"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="工作内容">
|
||||
<el-input v-model="logForm.content" type="textarea" :rows="4"></el-input>
|
||||
<el-input v-model="logForm.workContent" type="textarea" :rows="4"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<span class="dialog-footer" v-if="logForm.status == -1">
|
||||
<el-button @click="logDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="saveWorkLog">确定</el-button>
|
||||
</span>
|
||||
|
@ -110,39 +114,67 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { ref, computed, watch, onMounted, nextTick } from 'vue'
|
||||
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { workLogApi, projectApi } from '@/utils/api'
|
||||
import CustomTable from '@/components/CustomTable.vue'
|
||||
|
||||
const isCollapsed = ref(false)
|
||||
const selectedDate = ref(new Date())
|
||||
const currentMonth = ref(new Date())
|
||||
|
||||
// 更新项目列表,包含工时数据
|
||||
const projectList = ref([
|
||||
{ id: 1, name: '项目1', startDate: '2023-01-01', endDate: '2023-06-30', workHours: 120 },
|
||||
{ id: 2, name: '项目2', startDate: '2023-03-15', endDate: '2023-12-31', workHours: 80 },
|
||||
{ id: 3, name: '项目3', startDate: '2023-02-01', endDate: '2023-08-31', workHours: 160 },
|
||||
])
|
||||
const projectList = ref([])
|
||||
|
||||
// 当前选中的项目
|
||||
const currentProject = ref(null)
|
||||
const toggleCollapse = () => {
|
||||
isCollapsed.value = !isCollapsed.value
|
||||
}
|
||||
|
||||
const handleProjectClick = row => {
|
||||
currentProject.value = row
|
||||
// 可能需要重置选中的日期或执行其他操作
|
||||
}
|
||||
const logData = ref([])
|
||||
const handleProjectClick = async row => {
|
||||
const res = await projectApi.getProjectDetail(row.projectId)
|
||||
projectInfo.value.projectName = res.data.projectName
|
||||
projectInfo.value.projectId = res.data.projectId
|
||||
projectInfo.value.projectCode = res.data.projectCode
|
||||
projectInfo.value.startDate = res.data.startDate
|
||||
projectInfo.value.endDate = res.data.endDate.split(' ')[0] + ' 23:59:59'
|
||||
|
||||
const openLogDialog = data => {
|
||||
if (!currentProject.value) {
|
||||
// 更新日历的选中日期和当前月份
|
||||
selectedDate.value = new Date(projectInfo.value.startDate) // 设置为项目开始时间
|
||||
// 获取日历日志数据
|
||||
|
||||
const res2 = await workLogApi.getLogData({
|
||||
projectId: projectInfo.value.projectId,
|
||||
startDate: projectInfo.value.startDate,
|
||||
endDate: projectInfo.value.endDate,
|
||||
userId: projectInfo.value.userId,
|
||||
})
|
||||
logData.value = res2.data
|
||||
initDateColor()
|
||||
}
|
||||
// 渲染日期颜色
|
||||
const initDateColor = () => {
|
||||
logData.value.map(item => {
|
||||
var ele = document.getElementById(item.date.split(' ')[0])
|
||||
if (ele) {
|
||||
if (item.state == -1) {
|
||||
ele.style = 'background:#ecf5ff'
|
||||
} else if (item.state == 0) {
|
||||
ele.style = 'background:#409eff;color:#fff'
|
||||
} else if (item.state == 1) {
|
||||
ele.style = 'background:#f5dc58;color:#fff'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
const openLogDialog = async data => {
|
||||
if (!projectInfo.value) {
|
||||
ElMessage.warning('请先选择一个项目')
|
||||
return
|
||||
}
|
||||
|
||||
handleProjectClick(projectInfo.value)
|
||||
// 使用 data.day 而不是 data.date
|
||||
const clickedDate = new Date(data.day)
|
||||
const currentDate = new Date()
|
||||
|
@ -151,31 +183,48 @@ const openLogDialog = data => {
|
|||
clickedDate.setUTCHours(0, 0, 0, 0)
|
||||
currentDate.setUTCHours(0, 0, 0, 0)
|
||||
|
||||
if (clickedDate.getTime() > currentDate.getTime()) {
|
||||
if (
|
||||
clickedDate.getTime() > currentDate.getTime() &&
|
||||
clickedDate.getTime() < new Date(projectInfo.value.endDate).getTime()
|
||||
) {
|
||||
ElMessage.warning('不可编辑未来日期')
|
||||
return
|
||||
}
|
||||
|
||||
const date = new Date(data.day)
|
||||
const start = new Date(currentProject.value.startDate)
|
||||
const end = new Date(currentProject.value.endDate)
|
||||
const start = new Date(projectInfo.value.startDate)
|
||||
const end = new Date(projectInfo.value.endDate)
|
||||
// 使用 getTime() 进行比较,这样可以准确比较日期
|
||||
let flag = date.getTime() >= start.getTime() && date.getTime() <= end.getTime()
|
||||
console.log(currentProject.value.endDate, currentProject.value.startDate, data.day)
|
||||
|
||||
if (!flag) {
|
||||
ElMessage.warning('该日期不在项目范围内')
|
||||
return
|
||||
}
|
||||
// 这里可以添加打开日志对话框的逻辑
|
||||
logForm.value.loggerDate = data.day + ' 00:00:00'
|
||||
let logTime = logData.value.find(ele => ele.date == logForm.value.loggerDate) || {}
|
||||
logForm.value.status = logTime.state
|
||||
if (logForm.value.status != -1) {
|
||||
const res = await workLogApi.getLogDataDetail({
|
||||
userId: projectInfo.value.userId,
|
||||
projectId: projectInfo.value.projectId,
|
||||
loggerDate: logForm.value.loggerDate,
|
||||
})
|
||||
logForm.value.workTime = res.data.workTime
|
||||
logForm.value.workContent = res.data.workContent
|
||||
} else {
|
||||
logForm.value.workTime = ''
|
||||
logForm.value.workContent = ''
|
||||
}
|
||||
logDialogVisible.value = true
|
||||
}
|
||||
|
||||
const isInProjectRange = data => {
|
||||
if (!currentProject.value) return fals
|
||||
if (!projectInfo.value) return false
|
||||
const date = new Date(data.day)
|
||||
const start = new Date(currentProject.value.startDate)
|
||||
const end = new Date(currentProject.value.endDate)
|
||||
const start = new Date(projectInfo.value.startDate)
|
||||
const end = new Date(projectInfo.value.endDate)
|
||||
// 使用 getTime() 进行比较,这样可以准确比较日期
|
||||
return date.getTime() >= start.getTime() && date.getTime() <= end.getTime()
|
||||
}
|
||||
|
@ -199,7 +248,7 @@ const getSummaries = param => {
|
|||
sums[index] = values.reduce((prev, curr) => {
|
||||
const value = Number(curr)
|
||||
if (!isNaN(value)) {
|
||||
return prev + curr
|
||||
return prev + curr * 24
|
||||
} else {
|
||||
return prev
|
||||
}
|
||||
|
@ -208,21 +257,18 @@ const getSummaries = param => {
|
|||
sums[index] = 'N/A'
|
||||
}
|
||||
})
|
||||
if (sums[1] != 'N/A') sums[1] = Number(sums[1]).toFixed(2)
|
||||
return sums
|
||||
}
|
||||
|
||||
const logForm = ref({
|
||||
date: '',
|
||||
content: '',
|
||||
loggerDate: '',
|
||||
workContent: '',
|
||||
workTime: '',
|
||||
status: -1,
|
||||
})
|
||||
// 项目信息
|
||||
const projectInfo = ref({
|
||||
name: '项目1',
|
||||
code: 'XM5836383',
|
||||
reporter: '张三',
|
||||
startDate: '2024-6-15',
|
||||
endDate: '2024-8-29',
|
||||
})
|
||||
const projectInfo = ref({})
|
||||
|
||||
// 工作日志对话框
|
||||
const logDialogVisible = ref(false)
|
||||
|
@ -232,53 +278,52 @@ const workLog = ref({
|
|||
})
|
||||
|
||||
// 保存工作日志
|
||||
const saveWorkLog = () => {
|
||||
const saveWorkLog = async () => {
|
||||
// 这里添加保存工作日志的逻辑
|
||||
console.log('保存工作日志', workLog.value)
|
||||
// 判断是否为补填
|
||||
let state = new Date(logForm.value.loggerDate).getTime() == $moment().startOf('day').valueOf() ? 0 : 1
|
||||
await workLogApi.addLog({
|
||||
...logForm.value,
|
||||
projectId: projectInfo.value.projectId,
|
||||
state,
|
||||
userId: projectInfo.value.userId,
|
||||
})
|
||||
logDialogVisible.value = false
|
||||
ElMessage.success('添加成功')
|
||||
handleProjectClick(projectInfo.value)
|
||||
}
|
||||
|
||||
const handleMonthChange = date => {
|
||||
currentMonth.value = date
|
||||
}
|
||||
|
||||
const selectDate = type => {
|
||||
const date = new Date(currentMonth.value)
|
||||
switch (type) {
|
||||
case 'prev-month':
|
||||
date.setMonth(date.getMonth() - 1)
|
||||
break
|
||||
case 'today':
|
||||
date = new Date()
|
||||
break
|
||||
case 'next-month':
|
||||
date.setMonth(date.getMonth() + 1)
|
||||
break
|
||||
}
|
||||
currentMonth.value = date
|
||||
selectedDate.value = date
|
||||
}
|
||||
|
||||
// 监听当前项目的变化,重置选中的日期
|
||||
watch(currentProject, newProject => {
|
||||
if (newProject) {
|
||||
selectedDate.value = new Date(newProject.startDate)
|
||||
currentMonth.value = new Date(newProject.startDate)
|
||||
}
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// 获取用户项目
|
||||
const projectRef = ref(null)
|
||||
const fetchUserProjects = async () => {
|
||||
try {
|
||||
const response = await workLogApi.userProject(projectInfo.value.userId)
|
||||
projectList.value = response.data // 假设返回的数<EFBFBD><EFBFBD><EFBFBD>结构中有 projects 数组
|
||||
if (projectList.value.length) {
|
||||
handleProjectClick(projectList.value[0])
|
||||
projectRef.value.setCurrentRow(projectList.value[0])
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
const updateDateColors = () => {
|
||||
initDateColor() // 重新渲染日期颜色
|
||||
}
|
||||
onMounted(() => {
|
||||
const userId = route.params.userId
|
||||
const userName = route.query.userName
|
||||
|
||||
if (userId && userName) {
|
||||
console.log(`加载用户 ${userName}(ID: ${userId})的工作日志`)
|
||||
// 这里可以添加加载特定用户工作日志的逻辑
|
||||
if (route.params.userId) {
|
||||
projectInfo.value.userId = route.params.userId
|
||||
projectInfo.value.nickName = route.params.nickName
|
||||
} else {
|
||||
let userInfo =
|
||||
sessionStorage.getItem('userInfo') !== 'undefined' && sessionStorage.getItem('userInfo')
|
||||
? JSON.parse($utils.decryptByDES.CBC(sessionStorage.getItem('userInfo'))).user
|
||||
: {}
|
||||
projectInfo.value.userId = userInfo.userId
|
||||
projectInfo.value.nickName = userInfo.nickName
|
||||
}
|
||||
|
||||
// ... 其他初始化代码 ...
|
||||
//获取项目列表
|
||||
fetchUserProjects()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -295,6 +340,7 @@ onMounted(() => {
|
|||
transition: all 0.3s;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.project-list.collapsed {
|
||||
|
@ -311,6 +357,7 @@ onMounted(() => {
|
|||
border-bottom: 1px solid #dcdfe6;
|
||||
position: relative;
|
||||
height: 40px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.collapse-button-wrapper {
|
||||
|
@ -347,30 +394,6 @@ onMounted(() => {
|
|||
color: #606266;
|
||||
}
|
||||
|
||||
.project-list :deep(.el-table__body-wrapper) {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.project-list :deep(.el-table__footer-wrapper) {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.project-list :deep(.el-table__footer) {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.project-list :deep(.el-table__footer td) {
|
||||
background-color: white !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.project-list :deep(.el-table__body td),
|
||||
.project-list :deep(.el-table__footer td) {
|
||||
height: 60px; /* 增加单格度 */
|
||||
}
|
||||
|
||||
.project-info-calendar {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
|
@ -402,11 +425,11 @@ onMounted(() => {
|
|||
background-color: #ecf5ff;
|
||||
}
|
||||
.calendar-view :deep(.out-range) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
background-color: rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
.calendar-view :deep(.disabled) {
|
||||
background-color: #fff;
|
||||
background-color: #fff !important;
|
||||
color: #c0c4cc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -469,6 +492,10 @@ onMounted(() => {
|
|||
|
||||
.log-form :deep(.el-input__wrapper) {
|
||||
height: 50px;
|
||||
width: 100% !important;
|
||||
}
|
||||
:deep(.el-date-editor--date) {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.log-form :deep(.el-input__inner) {
|
||||
|
@ -486,7 +513,7 @@ onMounted(() => {
|
|||
|
||||
/* 增加 el-form-item__label 的高度和行高 */
|
||||
:deep(.el-form-item__label) {
|
||||
height: 42px; /* 默认通常是 32px,所以增加 10px 后变为 42px */
|
||||
height: 42px; /* 默认通常是 32px,所以增加 10px <EFBFBD><EFBFBD>变为 42px */
|
||||
line-height: 42px; /* 行高与高度相同,确保文字垂直居中 */
|
||||
}
|
||||
|
||||
|
@ -573,4 +600,24 @@ onMounted(() => {
|
|||
.date-cell.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
:deep(.el-table__footer-wrapper) {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
:deep(.el-table__footer td) {
|
||||
background-color: #f5f7fa !important;
|
||||
font-weight: bold;
|
||||
color: #606266;
|
||||
}
|
||||
:deep(.el-table__row) {
|
||||
cursor: pointer;
|
||||
}
|
||||
:deep(tr.el-table__row:hover .el-table__cell) {
|
||||
background: #409eff !important;
|
||||
color: #fff;
|
||||
}
|
||||
:deep(tr.el-table__row.current-row .el-table__cell) {
|
||||
background-color: #409eff !important;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,8 +6,6 @@ import AutoImport from 'unplugin-auto-import/vite'
|
|||
import Components from 'unplugin-vue-components/vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import myPlugin from './public/js/zip'
|
||||
// console.log(env.VITE_BASE_URL, 'env.VITE_BASE_URL')
|
||||
// https://vitejs.dev/config/
|
||||
|
||||
export default ({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
|
|
Loading…
Reference in New Issue