This commit is contained in:
zlwu committed 2026-08-11 11:13:01 +08:00
1 parent 80138c6388
commit 693e8a678e
682 files changed
+211375 -5306

No files matched your search

@@ -25,6 +25,12 @@
恢复转正日期自动计算
</el-button>
</p>
<p v-if="overtimeDurationManualFields.length" class="oa-start__tip">
<el-button link type="primary" @click="restoreOvertimeAuto">
<el-icon><RefreshRight /></el-icon>
恢复加班时长自动计算
</el-button>
</p>
<p v-else-if="!formRule.length && !detailLoading" class="oa-start__tip">
该模板暂无表单字段,仍可直接提交。
</p>
@@ -58,9 +64,10 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { Check, Close, Document } from '@element-plus/icons-vue'
import { Check, Close, Document, RefreshRight } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { fetchUserList } from '@/api/admin'
import { fetchCnHolidayRange } from '@/api/cnHoliday'
import {
fetchCreateOaInstanceDraft,
fetchOaFlowPreview,
@@ -84,7 +91,11 @@
} from '@/utils/oa-leave-kit-runtime'
import {
applyOvertimeKitDefaults,
ensureOvertimeKitRuleProps
applyOvertimeKitDurationsToFormData,
ensureOvertimeKitRuleProps,
listOvertimeKitBindings,
markOvertimeDurationManual,
OVERTIME_MANUAL_PREFIX
} from '@/utils/oa-overtime-kit-runtime'
import { applyResignationKitDefaults } from '@/utils/oa-resignation-kit-runtime'
import {
@@ -146,11 +157,24 @@
let tripKitPrevSnapshot: Record<string, unknown> = {}
let confirmationKitSyncing = false
let confirmationKitPrevSnapshot: Record<string, unknown> = {}
let overtimeKitSyncing = false
let overtimeKitPrevSnapshot: Record<string, unknown> = {}
const overtimeRestMap: Record<string, boolean> = {}
const confirmationDateManualFields = computed(() =>
listManualConfirmationDateFields({ rule: formRule.value }, formData.value)
)
const overtimeDurationManualFields = computed(() => {
const fields: string[] = []
for (const kit of listOvertimeKitBindings({ rule: formRule.value })) {
if (formData.value[OVERTIME_MANUAL_PREFIX + kit.durationField]) {
fields.push(kit.durationField)
}
}
return fields
})
function flowNeedsInitiatorSelect(node: any): boolean {
if (!node || typeof node !== 'object') return false
const cfg = node.approverConfig || {}
@@ -219,6 +243,7 @@
leaveKitPrevSnapshot = {}
tripKitPrevSnapshot = {}
confirmationKitPrevSnapshot = {}
overtimeKitPrevSnapshot = {}
needInitiatorSelect.value = false
initiatorSelectByNode.value = {}
flowSteps.value = []
@@ -274,6 +299,8 @@
const linked = applyConfirmationKitDateLinkage({ rule: formRule.value }, data)
formData.value = linked.data
confirmationKitPrevSnapshot = { ...linked.data }
overtimeKitPrevSnapshot = { ...linked.data }
void syncOvertimeKitDurations()
const flow = detail?.flowTreeJson || {}
const root = flow.root || flow
needInitiatorSelect.value = flowNeedsInitiatorSelect(root)
@@ -338,6 +365,8 @@
confirmationKitPrevSnapshot = { ...linked.data }
leaveKitPrevSnapshot = { ...formData.value }
tripKitPrevSnapshot = { ...formData.value }
overtimeKitPrevSnapshot = { ...formData.value }
void syncOvertimeKitDurations()
const sel = detail?.initiatorSelectByNode
initiatorSelectByNode.value =
sel && typeof sel === 'object' && !Array.isArray(sel) ? { ...sel } : {}
@@ -360,6 +389,8 @@
formData.value,
(userStore.info || userStore.getUserInfo) as any
)
overtimeKitPrevSnapshot = { ...formData.value }
void syncOvertimeKitDurations()
} catch {
/* 预填失败仍可手工填 */
}
@@ -530,12 +561,137 @@
})
}
async function ensureOvertimeHolidayRange(startYmd: string, endYmd: string) {
const start = String(startYmd || '').trim().slice(0, 10)
const end = String(endYmd || '').trim().slice(0, 10)
if (!start || !end) return
let lo = start
let hi = end
if (lo > hi) {
const t = lo
lo = hi
hi = t
}
const begin = new Date(lo + 'T00:00:00')
const finish = new Date(hi + 'T00:00:00')
if (Number.isNaN(begin.getTime()) || Number.isNaN(finish.getTime())) return
let allPresent = true
for (let d = new Date(begin); d <= finish; d.setDate(d.getDate() + 1)) {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const key = `${y}-${m}-${day}`
if (!(key in overtimeRestMap)) {
allPresent = false
break
}
}
if (allPresent) return
try {
const res = await fetchCnHolidayRange(lo, hi)
const days = res?.days || []
for (const day of days) {
const key = String(day?.dayDate || '').trim().slice(0, 10)
if (!key) continue
overtimeRestMap[key] = !!day.isRestDay
}
} catch {
/* 失败保留已有 map,计算回退周末规则 */
}
}
function isRestDayResolver(ymd: string): boolean {
if (ymd in overtimeRestMap) return overtimeRestMap[ymd]
const d = new Date(ymd + 'T00:00:00')
const w = d.getDay()
return w === 0 || w === 6
}
async function syncOvertimeKitDurations() {
if (overtimeKitSyncing) return
if (!formRule.value.length) return
const schema = { rule: formRule.value }
const bindings = listOvertimeKitBindings(schema)
if (!bindings.length) return
overtimeKitSyncing = true
try {
let minYmd = ''
let maxYmd = ''
for (const kit of bindings) {
for (const field of [kit.startField, kit.endField]) {
const ymd = String(formData.value[field] || '')
.trim()
.slice(0, 10)
if (ymd.length < 10) continue
if (!minYmd || ymd < minYmd) minYmd = ymd
if (!maxYmd || ymd > maxYmd) maxYmd = ymd
}
}
if (minYmd && maxYmd) {
await ensureOvertimeHolidayRange(minYmd, maxYmd)
}
const curr = { ...formData.value }
for (const kit of bindings) {
const prevDur = overtimeKitPrevSnapshot[kit.durationField]
const currDur = curr[kit.durationField]
const startChanged = overtimeKitPrevSnapshot[kit.startField] !== curr[kit.startField]
const endChanged = overtimeKitPrevSnapshot[kit.endField] !== curr[kit.endField]
const durChanged = prevDur !== currDur
if (
durChanged &&
!startChanged &&
!endChanged &&
currDur !== undefined &&
currDur !== ''
) {
Object.assign(curr, markOvertimeDurationManual(curr, kit.durationField, true))
}
}
const { data, changed } = applyOvertimeKitDurationsToFormData(
schema,
curr,
isRestDayResolver
)
overtimeKitPrevSnapshot = { ...data }
const manualKeysChanged = bindings.some(
(k) =>
!!data[OVERTIME_MANUAL_PREFIX + k.durationField] !==
!!formData.value[OVERTIME_MANUAL_PREFIX + k.durationField]
)
const durationChanged = bindings.some(
(k) => data[k.durationField] !== formData.value[k.durationField]
)
if (changed || manualKeysChanged || durationChanged) {
formData.value = data
}
} finally {
queueMicrotask(() => {
overtimeKitSyncing = false
})
}
}
function restoreOvertimeAuto() {
let data = { ...formData.value }
for (const kit of listOvertimeKitBindings({ rule: formRule.value })) {
data = markOvertimeDurationManual(data, kit.durationField, false)
}
formData.value = data
void syncOvertimeKitDurations()
}
watch(
formData,
() => {
syncLeaveKitDurations()
syncTripKitDurations()
syncConfirmationKitDates()
void syncOvertimeKitDurations()
scheduleFlowPreview()
},
{ deep: true }