开始开发功能实现

This commit is contained in:
WindowBird 2025-11-18 17:10:08 +08:00
parent 4bf4371fcb
commit 08cebe614b
2 changed files with 262 additions and 4 deletions

View File

@ -142,3 +142,18 @@ export const deleteProject = (ids) => {
});
};
/**
* 开始项目开发
* @param {Object} data
* @param {string} data.id 项目ID
* @param {string} data.expectedCompleteDate 预计完成日期YYYY-MM-DD
* @returns {Promise} 操作结果
*/
export const startProjectDevelopment = (data) => {
return uni.$uv.http.put('bst/project/start', data, {
custom: {
auth: true
}
});
};

View File

@ -201,13 +201,54 @@
</view>
</view>
</view>
<!-- 开始开发弹窗 -->
<view v-if="showStartModal" class="start-modal">
<view class="modal-mask" @click="closeStartModal"></view>
<view class="modal-panel">
<view class="modal-header">
<text class="modal-title">开始开发</text>
<text class="modal-close" @click="closeStartModal"></text>
</view>
<view class="modal-body">
<text class="modal-subtitle" v-if="currentStartProjectName">项目{{ currentStartProjectName }}</text>
<view class="field">
<text class="field-label">预计完成日期</text>
<view class="date-input" @click="openStartDatePicker">
<text class="placeholder" v-if="!startProjectForm.expectedCompleteDate">请选择预计完成日期</text>
<text class="value" v-else>{{ startProjectForm.expectedCompleteDate }}</text>
<text class="date-icon">📅</text>
</view>
</view>
</view>
<view class="modal-actions">
<uv-button size="small" @click="closeStartModal" :disabled="startingProject">取消</uv-button>
<uv-button
type="primary"
size="small"
@click="submitStartDevelopment"
:loading="startingProject"
:disabled="startingProject"
>
确定
</uv-button>
</view>
</view>
</view>
<uv-datetime-picker
ref="startDatePickerRef"
v-model="startDatePickerValue"
mode="date"
@confirm="onStartDateConfirm"
></uv-datetime-picker>
</view>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick, onUnmounted } from 'vue';
import { ref, reactive, computed, watch, onMounted, nextTick, onUnmounted } from 'vue';
import { onLoad, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app';
import { getProjectList, getUserList, deleteProject } from '@/api';
import { getProjectList, getUserList, deleteProject, startProjectDevelopment } from '@/api';
import { usePagination } from '@/composables';
import { useDictStore } from '@/store/dict';
import { useUserStore } from '@/store/user';
@ -414,9 +455,35 @@ const getStatusType = (status) => {
//
const formatDate = (dateStr) => {
if (!dateStr) return '未知';
if (typeof dateStr === 'number') {
return formatDateValue(dateStr);
}
return dateStr.split(' ')[0];
};
const formatDateValue = (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const extractDateOnly = (value) => {
if (!value) return '';
if (typeof value === 'string') {
const trimmed = value.trim();
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
return trimmed;
}
if (trimmed.includes(' ')) {
return trimmed.split(' ')[0];
}
}
return formatDateValue(value);
};
//
const getOwnerNames = (memberList) => {
if (!Array.isArray(memberList) || memberList.length === 0) return '未分配';
@ -518,6 +585,15 @@ const getAvatarText = (member) => {
};
const deletingProjectId = ref('');
const showStartModal = ref(false);
const startingProject = ref(false);
const startProjectForm = reactive({
id: '',
expectedCompleteDate: ''
});
const currentStartProjectName = ref('');
const startDatePickerRef = ref(null);
const startDatePickerValue = ref(Date.now());
//
const handleCardMenu = (project) => {
@ -532,13 +608,86 @@ const handleCardMenu = (project) => {
//
uni.showToast({ title: '新增任务功能开发中', icon: 'none' });
} else if (res.tapIndex === 3) {
//
uni.showToast({ title: '开始开发功能开发中', icon: 'none' });
handleStartDevelopment(project);
}
}
});
};
const handleStartDevelopment = (project) => {
if (!project?.id) {
uni.showToast({
title: '缺少项目ID',
icon: 'none'
});
return;
}
startProjectForm.id = project.id;
startProjectForm.expectedCompleteDate = extractDateOnly(project.expectedCompleteDate || project.expireTime || '');
currentStartProjectName.value = project.name || project.projectName || '';
showStartModal.value = true;
};
const closeStartModal = () => {
resetStartForm();
showStartModal.value = false;
};
const resetStartForm = () => {
startProjectForm.id = '';
startProjectForm.expectedCompleteDate = '';
currentStartProjectName.value = '';
};
const submitStartDevelopment = async () => {
if (!startProjectForm.id) {
uni.showToast({
title: '缺少项目ID',
icon: 'none'
});
return;
}
if (!startProjectForm.expectedCompleteDate) {
uni.showToast({
title: '请选择预计完成日期',
icon: 'none'
});
return;
}
try {
startingProject.value = true;
await startProjectDevelopment({
id: startProjectForm.id,
expectedCompleteDate: startProjectForm.expectedCompleteDate
});
uni.showToast({ title: '已开始开发', icon: 'success' });
closeStartModal();
await refresh();
} catch (err) {
console.error('开始开发失败:', err);
uni.showToast({
title: err?.message || '操作失败,请稍后重试',
icon: 'none'
});
} finally {
startingProject.value = false;
}
};
const openStartDatePicker = () => {
startDatePickerValue.value = startProjectForm.expectedCompleteDate
? new Date(startProjectForm.expectedCompleteDate.replace(/-/g, '/')).getTime()
: Date.now();
if (startDatePickerRef.value?.open) {
startDatePickerRef.value.open();
}
};
const onStartDateConfirm = (event) => {
if (!event?.value) return;
startProjectForm.expectedCompleteDate = formatDateValue(event.value);
};
const handleDeleteProject = (project) => {
if (!project?.id) {
uni.showToast({
@ -1078,5 +1227,99 @@ onLoad(() => {
font-size: 12px;
color: #999;
}
.start-modal {
position: fixed;
inset: 0;
z-index: 999;
}
.modal-mask {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.4);
}
.modal-panel {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 86%;
max-width: 360px;
background: #fff;
border-radius: 12px;
padding: 16px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: #333;
}
.modal-close {
font-size: 18px;
color: #999;
padding: 4px;
}
.modal-body {
display: flex;
flex-direction: column;
gap: 12px;
margin-bottom: 16px;
}
.modal-subtitle {
font-size: 14px;
color: #666;
}
.field {
display: flex;
flex-direction: column;
gap: 8px;
}
.field-label {
font-size: 14px;
color: #333;
}
.date-input {
height: 40px;
border-radius: 8px;
background: #f5f6f7;
padding: 0 12px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: #333;
}
.date-input .placeholder {
color: #999;
}
.date-icon {
font-size: 16px;
margin-left: 8px;
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
}
</style>