diff --git a/api/oa/projectSchedule.js b/api/oa/projectSchedule.js new file mode 100644 index 0000000..03117a5 --- /dev/null +++ b/api/oa/projectSchedule.js @@ -0,0 +1,61 @@ +import request from "@/util/oaRequest" + +// 查询项目进度列表 +export function listProjectSchedule (query) { + return request({ + url: '/oa/projectSchedule/list', + method: 'get', + params: query + }) +} + +// 查询项目进度详细 +export function getProjectSchedule (scheduleId) { + return request({ + url: '/oa/projectSchedule/' + scheduleId, + method: 'get' + }) +} + +// 新增项目进度 +export function addProjectSchedule (data) { + return request({ + url: '/oa/projectSchedule', + method: 'post', + data: data + }) +} + +// 修改项目进度 +export function updateProjectSchedule (data) { + return request({ + url: '/oa/projectSchedule', + method: 'put', + data: data + }) +} + +// 修改项目进度 +export function completeSchedule (data) { + return request({ + url: '/oa/projectSchedule/complete', + method: 'put', + data: data + }) +} + +// 删除项目进度 +export function delProjectSchedule (scheduleId) { + return request({ + url: '/oa/projectSchedule/' + scheduleId, + method: 'delete' + }) +} + +export function addByProjectId (data) { + return request({ + url: '/oa/projectSchedule/addByProjectId', + method: 'post', + data + }) +} diff --git a/api/oa/projectScheduleStep.js b/api/oa/projectScheduleStep.js new file mode 100644 index 0000000..d707b95 --- /dev/null +++ b/api/oa/projectScheduleStep.js @@ -0,0 +1,61 @@ +import request from "@/util/oaRequest" + +// 查询项目进度步骤跟踪列表 +export function listProjectScheduleStep (query) { + return request({ + url: '/oa/projectScheduleStep/list', + method: 'get', + params: query + }) +} + +// 查询项目进度步骤跟踪详细 +export function getProjectScheduleStep (trackId) { + return request({ + url: '/oa/projectScheduleStep/' + trackId, + method: 'get' + }) +} + +// 新增项目进度步骤跟踪 +export function addProjectScheduleStep (data) { + return request({ + url: '/oa/projectScheduleStep', + method: 'post', + data: data + }) +} + +// 修改项目进度步骤跟踪 +export function updateProjectScheduleStep (data) { + return request({ + url: '/oa/projectScheduleStep', + method: 'put', + data: data + }) +} + +// 修改项目进度步骤跟踪 +export function changeBatch (data) { + return request({ + url: '/oa/projectScheduleStep/change-batch', + method: 'put', + data: data + }) +} + +// 删除项目进度步骤跟踪 +export function delProjectScheduleStep (trackId) { + return request({ + url: '/oa/projectScheduleStep/' + trackId, + method: 'delete' + }) +} + +export function listPage (query) { + return request({ + url: '/oa/projectScheduleStep/listPage', + method: 'get', + params: query + }) +} diff --git a/components/oa/oa-remind-time/index.vue b/components/oa/oa-remind-time/index.vue index 0d76dde..3dc9cb5 100644 --- a/components/oa/oa-remind-time/index.vue +++ b/components/oa/oa-remind-time/index.vue @@ -1,10 +1,5 @@ @@ -13,53 +8,83 @@ export default { name: 'RemainingTime', props: { - // 截至日期(ISO格式,如:'2025-12-31T23:59:59') + // 截至日期(支持多种格式或null) expireDate: { - type: String, - required: true, + type: [String, null], // 允许字符串或null + default: null, // 默认null validator(value) { - // 验证日期格式有效性 + // 允许null,非null时检查是否能解析为有效日期 + if (value === null) return true; return !isNaN(Date.parse(value)); } }, - // 阈值天数(超过此值为绿色,否则红色) + // 阈值天数 thresholdDays: { type: Number, - required: true, - default: 3, + default: 3, validator(value) { return value >= 0; } + }, + // 是否已完成 + finished: { + type: Boolean, + default: false } }, computed: { - // 计算剩余天数(负数表示逾期) + // 计算剩余天数(处理null和无效日期) remainingDays() { + // 如果无截止日期或日期无效,返回null + if (!this.expireDate) return null; const now = new Date(); const expire = new Date(this.expireDate); + // 无效日期处理 + if (isNaN(expire.getTime())) return null; const diffTime = expire - now; - // 转换为天数并四舍五入 return Math.round(diffTime / (1000 * 60 * 60 * 24)); }, - // 是否已逾期 + // 是否已逾期(仅在有有效日期时判断) isExpired() { - return this.remainingDays < 0; + return this.remainingDays !== null && this.remainingDays < 0; }, - // 显示文本 + // 显示文本(优先级:完成 > 无日期 > 逾期 > 剩余时间) displayText() { + if (this.finished) { + return '已完成'; + } + // 无截止日期的情况 + if (this.remainingDays === null) { + return '无截止日期'; + } if (this.isExpired) { return `已逾期 ${Math.abs(this.remainingDays)} 天`; } return `剩余 ${this.remainingDays} 天`; }, - // 计算样式类 - computedClass() { - if (this.isExpired) { - return 'expired'; // 逾期状态 + // 图标类型 + getIconType() { + if (this.finished) { + return 'checkmark'; } - return this.remainingDays > this.thresholdDays - ? 'normal' // 正常状态(超过阈值) - : 'warning'; // 警告状态(低于阈值) + if (this.remainingDays === null) { + return 'help'; // 无日期时显示帮助图标 + } + return this.isExpired ? 'clock' : 'time'; + }, + // 样式类 + computedClass() { + if (this.finished) { + return 'finished'; + } + // 无截止日期的样式 + if (this.remainingDays === null) { + return 'no-date'; + } + if (this.isExpired) { + return 'expired'; + } + return this.remainingDays > this.thresholdDays ? 'normal' : 'warning'; } } }; @@ -83,19 +108,30 @@ export default { font-weight: 500; } -/* 正常状态(超过阈值) */ +/* 正常状态 */ .normal { - color: #00b42a; /* 绿色 */ + color: #00b42a; } -/* 警告状态(低于阈值) */ +/* 警告状态 */ .warning { - color: #f53f3f; /* 红色 */ + color: #f53f3f; } /* 逾期状态 */ .expired { background-color: #fef0f0; - color: #f53f3f; /* 红色背景+红色文字 */ + color: #f53f3f; +} + +/* 完成状态 */ +.finished { + background-color: #00b42a; + color: #ffffff; +} + +/* 无截止日期状态 */ +.no-date { + color: #888888; /* 灰色文字 */ } \ No newline at end of file diff --git a/pages/workbench/article/article.vue b/pages/workbench/article/article.vue index 92bdcc3..7a2e0ba 100644 --- a/pages/workbench/article/article.vue +++ b/pages/workbench/article/article.vue @@ -77,12 +77,10 @@ this.loading = true; switch (type) { case 'notice': - getNotice(id) + getFeedback(id) .then(res => { this.article = { ...res.data, - title: res.data.noticeTitle, - content: res.data.noticeContent, }; uni.setNavigationBarTitle({ title: '通知详情' @@ -107,8 +105,10 @@ uni.setNavigationBarTitle({ title: '反馈详情' }) - // 标记为已读 - toRead(this.article); + if (this.article.state == 0) { + // 标记为已读 + toRead(this.article); + } } else { uni.showToast({ title: '未找到消息', diff --git a/pages/workbench/feedback/feedback.vue b/pages/workbench/feedback/feedback.vue index fda74e2..ad0b5e5 100644 --- a/pages/workbench/feedback/feedback.vue +++ b/pages/workbench/feedback/feedback.vue @@ -70,7 +70,8 @@ title: '', projectId: '', startTime: '', - endTime: '' + endTime: '', + type: 'feedback' }, total: 0, // 总条数 loading: false, // 加载状态 diff --git a/pages/workbench/index/index.vue b/pages/workbench/index/index.vue index cd72cc9..9fb0bbf 100644 --- a/pages/workbench/index/index.vue +++ b/pages/workbench/index/index.vue @@ -58,7 +58,7 @@ export default { text: '任务中心', icon: '/static/images/task.png', url: '/pages/workbench/task/task', - category: "信息中心" + category: "项目中心" }, { text: '项目排产', diff --git a/pages/workbench/notice/notice.vue b/pages/workbench/notice/notice.vue index 4c8ab00..55532f9 100644 --- a/pages/workbench/notice/notice.vue +++ b/pages/workbench/notice/notice.vue @@ -8,8 +8,13 @@
-
-
{{ notice.noticeTitle }}
+
+
+ {{ notice.title }} + + + +
{{ notice.createBy || '未知发布人' }} {{ notice.createTime || '未知时间' }} @@ -20,7 +25,7 @@ - + .search-bar { + padding: 20rpx; + position: sticky; + top: 0; + z-index: 100; + background: #fff; + } + + .search-container { + display: flex; + align-items: center; + gap: 20rpx; + } + + .task-type-button-container { + display: flex; + gap: 12rpx; + } + + .task-type-button { + width: 60rpx; + height: 60rpx; + background-color: transparent; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + } + + .search-input { + flex: 1; + position: relative; + display: flex; + align-items: center; + background: #f5f5f5; + border-radius: 100rpx; + padding: 0 24rpx; + height: 60rpx; + } + + .input { + flex: 1; + border: none; + background: transparent; + font-size: 30rpx; + outline: none; + height: 60rpx; + line-height: 60rpx; + } + + .search-icon { + margin-left: 8rpx; + display: flex; + align-items: center; + } + + .clear-icon { + margin-left: 8rpx; + display: flex; + align-items: center; + } + + .drawer-content { + padding: 32rpx 24rpx 24rpx 24rpx; + } + + .drawer-title { + font-size: 32rpx; + font-weight: bold; + margin-bottom: 24rpx; + } + + .drawer-form { + margin-bottom: 32rpx; + } + + .drawer-form-item { + margin-bottom: 24rpx; + } + + .drawer-label { + display: block; + font-size: 28rpx; + color: #333; + margin-bottom: 8rpx; + } + + .drawer-btns { + display: flex; + gap: 16rpx; + margin-top: 24rpx; + } + + .drawer-btn-primary { + flex: 1; + background: #2979ff; + color: #fff; + border: none; + border-radius: 8rpx; + padding: 16rpx 0; + font-size: 28rpx; + } + + .drawer-btn { + flex: 1; + background: #f5f5f5; + color: #333; + border: none; + border-radius: 8rpx; + padding: 16rpx 0; + font-size: 28rpx; + } + + .card { + background: #fff; + border-radius: 16rpx; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); + padding: 24rpx; + } + + .card-title { + display: flex; + justify-content: space-between; + align-items: center; + font-weight: bold; + margin-bottom: 12rpx; + } + + .project { + color: #2979ff; + } + + .status { + font-size: 24rpx; + padding: 0 12rpx; + border-radius: 8rpx; + } + + .status-1 { + background: #e0f7fa; + color: #009688; + } + + .status-0, + .status-undefined { + background: #fffbe6; + color: #faad14; + } + + .status-other { + background: #fbeff2; + color: #e91e63; + } + + .card-content view { + margin-bottom: 8rpx; + color: #666; + font-size: 26rpx; + } + + .empty { + text-align: center; + color: #bbb; + margin: 40rpx 0; + } + + .popup-content { + padding: 24rpx; + background: #fff; + border-radius: 16rpx 16rpx 0 0; + } + + .uni-form { + margin-bottom: 32rpx; + max-height: 50vh; + min-height: 40vh; + overflow-y: scroll; + } + + .uni-form-item { + margin-bottom: 32rpx; + } + + .uni-form-label { + display: block; + font-size: 28rpx; + color: #333; + margin-bottom: 8rpx; + } + + .load-more-tips { + text-align: center; + color: #bbb; + padding: 24rpx 0 32rpx 0; + font-size: 28rpx; + } + + .card-ops { + margin-top: 16rpx; + display: flex; + gap: 16rpx; + } + + .gantt-toggle-bar { + display: flex; + gap: 16rpx; + padding: 16rpx 0 8rpx 0; + background: #fff; + justify-content: flex-end; + } + \ No newline at end of file diff --git a/pages/workbench/project/step.vue b/pages/workbench/project/step.vue index 8183fd0..d904cd3 100644 --- a/pages/workbench/project/step.vue +++ b/pages/workbench/project/step.vue @@ -1,22 +1,333 @@ - +/* 横向滚动Tab样式 */ +.tab-container { + background-color: #fff; + padding: 8rpx 0; + margin-bottom: 16rpx; + border-radius: 8rpx; +} + +.second-tab { + margin-bottom: 24rpx; +} + +.tab-scroll { + width: 100%; + white-space: nowrap; + padding: 8rpx 16rpx; +} + +.tab-wrapper { + display: inline-flex; + gap: 24rpx; +} + +.tab-item { + padding: 12rpx 24rpx; + font-size: 28rpx; + border-radius: 30rpx; + background-color: #f0f0f0; + color: #333; + white-space: nowrap; + transition: all 0.2s ease; + display: inline-flex; + align-items: center; + gap: 8rpx; /* 文字和清除图标间距 */ +} + +.tab-item.tab-active { + background-color: #007aff; + color: #fff; + font-weight: 500; +} + +.tab-item.tab-disabled { + color: #ccc; + background-color: #f9f9f9; +} + +/* 清除图标样式 */ +.clear-icon { + font-size: 24rpx; + width: 24rpx; + height: 24rpx; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background-color: rgba(255,255,255,0.3); + cursor: pointer; +} + +/* 列表样式 */ +.list-container { + background-color: #fff; + border-radius: 8rpx; + padding: 16rpx; +} + +.summary { + font-size: 28rpx; + color: #666; + padding: 16rpx 0; + border-bottom: 1px solid #eee; + margin-bottom: 16rpx; +} + +.loading, .empty { + text-align: center; + padding: 60rpx 0; + color: #999; + font-size: 28rpx; +} + +.list-item { + padding: 20rpx 0; + border-bottom: 1px solid #eee; +} + +.list-item:last-child { + border-bottom: none; +} + +.item-name { + font-size: 32rpx; + font-weight: 500; + margin-bottom: 12rpx; + color: #333; +} + +.item-info { + font-size: 26rpx; + color: #666; + margin-bottom: 8rpx; +} + \ No newline at end of file