feat: OKR模板库改造 — 弹窗模板库联动+时间分解落库+制造业包6个

This commit is contained in:
Hermes CI Fix
2026-08-11 00:11:25 +08:00
parent 32fe3e4d50
commit 0b191d278e
7 changed files with 413 additions and 8 deletions
@@ -48,6 +48,14 @@
</div>
<div v-if="kr.milestones.length === 0" class="no-milestones">
暂无里程碑
<el-button size="small" text type="primary" :loading="generatingKrId === kr.kr_id" @click="autoGenerate(kr)">
一键生成
</el-button>
</div>
<div v-else class="milestone-actions">
<el-button size="small" text type="primary" :loading="generatingKrId === kr.kr_id" @click="autoGenerate(kr)">
重新生成
</el-button>
</div>
</div>
</div>
@@ -119,6 +127,7 @@ const editingKr = ref<any>(null)
const editingMsIdx = ref(-1)
const editingMs = ref<any>(null)
const saving = ref(false)
const generatingKrId = ref<number | null>(null)
function formatMonth(m: string) {
if (!m) return ''
@@ -163,21 +172,44 @@ async function saveMilestone() {
if (!editingKr.value || !editingMs.value) return
saving.value = true
try {
// Update in local data first
const kr = data.value.krs.find((k: any) => k.kr_id === editingKr.value.kr_id)
if (kr && kr.milestones[editingMsIdx.value]) {
kr.milestones[editingMsIdx.value] = { ...editingMs.value }
}
ElMessage.success('里程碑已更新')
// 持久化到后端(里程碑完成时KR进度同步更新)
if (kr) {
const res: any = await okrApi.saveMilestones(props.okrId, kr.kr_id, kr.milestones)
if (res && res.progress != null) {
kr.progress = res.progress
}
}
ElMessage.success('里程碑已保存')
showEditDialog.value = false
emit('refresh')
} catch (e: any) {
ElMessage.error('保存失败: ' + (e?.message || ''))
ElMessage.error('保存失败: ' + (e?.response?.data?.detail || e?.message || ''))
} finally {
saving.value = false
}
}
async function autoGenerate(kr: any) {
if (!kr) return
generatingKrId.value = kr.kr_id
try {
const res: any = await okrApi.generateMilestones(props.okrId, kr.kr_id)
if (res?.milestones) {
kr.milestones = res.milestones
}
ElMessage.success('已自动生成月度里程碑')
emit('refresh')
} catch (e: any) {
ElMessage.error('生成失败: ' + (e?.response?.data?.detail || e?.message || ''))
} finally {
generatingKrId.value = null
}
}
async function loadData() {
if (!props.okrId) return
loading.value = true
@@ -319,6 +351,14 @@ onMounted(() => {
font-size: 12px;
padding: 10px 0;
}
.milestone-actions {
display: flex;
align-items: center;
justify-content: center;
min-width: 90px;
padding: 4px 0;
border-left: 1px dashed #EBEEF5;
}
@keyframes pulse {
0%, 100% { opacity: 1; }