feat(plan):优化计划保存与切换逻辑,提升性能与用户体验- 在计划组件中引入防抖机制,避免频繁保存操作
- 实现异步保存队列,确保计划切换时数据不丢失 - 优化计划切换逻辑,支持后台保存并提升响应速度 - 在组件卸载前确保所有 pending 保存操作完成 - 修复 MaaPlanTable 中响应式丢失问题,优化选项缓存逻辑 - 为 PlanSelector 添加点击防抖,防止重复触发计划切换- 重构数据同步逻辑,提高表格与计划数据的同步效率
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
:key="plan.id"
|
:key="plan.id"
|
||||||
:type="activePlanId === plan.id ? 'primary' : 'default'"
|
:type="activePlanId === plan.id ? 'primary' : 'default'"
|
||||||
size="large"
|
size="large"
|
||||||
@click="$emit('plan-change', plan.id)"
|
@click="handlePlanClick(plan.id)"
|
||||||
class="plan-button"
|
class="plan-button"
|
||||||
>
|
>
|
||||||
<span class="plan-name">{{ plan.name }}</span>
|
<span class="plan-name">{{ plan.name }}</span>
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
interface Plan {
|
interface Plan {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
@@ -48,8 +49,22 @@ interface Emits {
|
|||||||
(e: 'plan-change', planId: string): void
|
(e: 'plan-change', planId: string): void
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
defineEmits<Emits>()
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
|
// 防抖点击处理
|
||||||
|
const debounce = <T extends (...args: any[]) => any>(func: T, wait: number): T => {
|
||||||
|
let timeout: NodeJS.Timeout | null = null
|
||||||
|
return ((...args: any[]) => {
|
||||||
|
if (timeout) clearTimeout(timeout)
|
||||||
|
timeout = setTimeout(() => func(...args), wait)
|
||||||
|
}) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePlanClick = debounce((planId: string) => {
|
||||||
|
if (planId === props.activePlanId) return
|
||||||
|
emit('plan-change', planId)
|
||||||
|
}, 100)
|
||||||
|
|
||||||
const getPlanTypeLabel = (planType: string) => {
|
const getPlanTypeLabel = (planType: string) => {
|
||||||
const labelMap: Record<string, string> = {
|
const labelMap: Record<string, string> = {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { usePlanApi } from '@/composables/usePlanApi'
|
import { usePlanApi } from '@/composables/usePlanApi'
|
||||||
@@ -112,6 +112,15 @@ const currentTableComponent = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 添加防抖工具函数
|
||||||
|
const debounce = <T extends (...args: any[]) => any>(func: T, wait: number): T => {
|
||||||
|
let timeout: NodeJS.Timeout | null = null
|
||||||
|
return ((...args: any[]) => {
|
||||||
|
if (timeout) clearTimeout(timeout)
|
||||||
|
timeout = setTimeout(() => func(...args), wait)
|
||||||
|
}) as T
|
||||||
|
}
|
||||||
|
|
||||||
const handleAddPlan = async (planType: string = 'MaaPlan') => {
|
const handleAddPlan = async (planType: string = 'MaaPlan') => {
|
||||||
try {
|
try {
|
||||||
const response = await createPlan(planType)
|
const response = await createPlan(planType)
|
||||||
@@ -147,7 +156,72 @@ const handleRemovePlan = async (planId: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加异步保存队列和状态管理
|
||||||
|
const savingQueue = ref(new Set<string>())
|
||||||
|
const savePromises = ref(new Map<string, Promise<void>>())
|
||||||
|
|
||||||
|
// 异步保存函数
|
||||||
|
const saveInBackground = async (planId: string) => {
|
||||||
|
// 如果已经在保存队列中,等待现有的保存完成
|
||||||
|
if (savingQueue.value.has(planId)) {
|
||||||
|
const existingPromise = savePromises.value.get(planId)
|
||||||
|
if (existingPromise) {
|
||||||
|
await existingPromise
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
savingQueue.value.add(planId)
|
||||||
|
|
||||||
|
const savePromise = (async () => {
|
||||||
|
try {
|
||||||
|
const currentPlan = planList.value.find(plan => plan.id === planId)
|
||||||
|
const planType = currentPlan?.type || 'MaaPlan'
|
||||||
|
|
||||||
|
// Start from existing tableData, then overwrite Info explicitly
|
||||||
|
const planData: Record<string, any> = { ...(tableData.value || {}) }
|
||||||
|
planData.Info = { Mode: currentMode.value, Name: currentPlanName.value, Type: planType }
|
||||||
|
|
||||||
|
await updatePlan(planId, planData)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('后台保存计划数据失败:', error)
|
||||||
|
// 不显示错误消息,避免打断用户操作
|
||||||
|
} finally {
|
||||||
|
savingQueue.value.delete(planId)
|
||||||
|
savePromises.value.delete(planId)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
savePromises.value.set(planId, savePromise)
|
||||||
|
return savePromise
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防抖保存函数
|
||||||
|
const debouncedSave = debounce(async () => {
|
||||||
|
if (!activePlanId.value) return
|
||||||
|
await saveInBackground(activePlanId.value)
|
||||||
|
}, 300)
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
if (!activePlanId.value) {
|
||||||
|
message.warning('请先选择一个计划')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await debouncedSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优化计划切换逻辑
|
||||||
const onPlanChange = async (planId: string) => {
|
const onPlanChange = async (planId: string) => {
|
||||||
|
if (planId === activePlanId.value) return
|
||||||
|
|
||||||
|
// 触发当前计划的异步保存,但不等待完成
|
||||||
|
if (activePlanId.value) {
|
||||||
|
saveInBackground(activePlanId.value).catch(error => {
|
||||||
|
console.warn('切换时保存当前计划失败:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 立即切换到新计划
|
||||||
activePlanId.value = planId
|
activePlanId.value = planId
|
||||||
await loadPlanData(planId)
|
await loadPlanData(planId)
|
||||||
}
|
}
|
||||||
@@ -232,35 +306,24 @@ const initPlans = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const savePlanData = async () => {
|
const savePlanData = async (planId?: string) => {
|
||||||
if (!activePlanId.value) return
|
const targetPlanId = planId || activePlanId.value
|
||||||
|
if (!targetPlanId) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentPlan = planList.value.find(plan => plan.id === activePlanId.value)
|
const currentPlan = planList.value.find(plan => plan.id === targetPlanId)
|
||||||
const planType = currentPlan?.type || 'MaaPlan'
|
const planType = currentPlan?.type || 'MaaPlan'
|
||||||
|
|
||||||
// Start from existing tableData, then overwrite Info explicitly
|
|
||||||
const planData: Record<string, any> = { ...(tableData.value || {}) }
|
const planData: Record<string, any> = { ...(tableData.value || {}) }
|
||||||
planData.Info = { Mode: currentMode.value, Name: currentPlanName.value, Type: planType }
|
planData.Info = { Mode: currentMode.value, Name: currentPlanName.value, Type: planType }
|
||||||
|
|
||||||
await updatePlan(activePlanId.value, planData)
|
await updatePlan(targetPlanId, planData)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存计划数据失败:', error)
|
console.error('保存计划数据失败:', error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
if (!activePlanId.value) {
|
|
||||||
message.warning('请先选择一个计划')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await savePlanData()
|
|
||||||
} catch (error) {
|
|
||||||
message.error('保存失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDefaultPlanName = (planType: string) =>
|
const getDefaultPlanName = (planType: string) =>
|
||||||
(
|
(
|
||||||
({
|
({
|
||||||
@@ -282,7 +345,7 @@ watch(
|
|||||||
() => [currentPlanName.value, currentMode.value],
|
() => [currentPlanName.value, currentMode.value],
|
||||||
async () => {
|
async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
handleSave()
|
await debouncedSave()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -298,8 +361,24 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 在组件卸载前确保所有保存操作完成
|
||||||
|
const ensureAllSaved = async () => {
|
||||||
|
const pendingPromises = Array.from(savePromises.value.values())
|
||||||
|
if (pendingPromises.length > 0) {
|
||||||
|
await Promise.allSettled(pendingPromises)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initPlans()
|
initPlans()
|
||||||
|
|
||||||
|
// 监听页面卸载
|
||||||
|
window.addEventListener('beforeunload', ensureAllSaved)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('beforeunload', ensureAllSaved)
|
||||||
|
ensureAllSaved()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
import { computed, defineComponent, ref, watch } from 'vue'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { PlusOutlined } from '@ant-design/icons-vue'
|
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
@@ -219,6 +219,7 @@ const VNodeRenderer = defineComponent({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 改回使用普通的ref,确保响应式正常工作
|
||||||
const rows = ref<TableRow[]>([
|
const rows = ref<TableRow[]>([
|
||||||
{
|
{
|
||||||
key: 'MedicineNumb',
|
key: 'MedicineNumb',
|
||||||
@@ -411,38 +412,40 @@ const addCustomStage = (rowKey: string, columnKey: string) => {
|
|||||||
message.success('关卡添加成功')
|
message.success('关卡添加成功')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 缓存计算属性,避免重复计算
|
||||||
|
const stageOptionsCache = ref(new Map<string, any[]>())
|
||||||
|
|
||||||
const stageOptions = computed(() => {
|
const stageOptions = computed(() => {
|
||||||
const baseOptions = STAGE_DAILY_INFO.map(stage => ({
|
const cacheKey = 'base_stage_options'
|
||||||
label: stage.text,
|
if (!stageOptionsCache.value.has(cacheKey)) {
|
||||||
value: stage.value,
|
const baseOptions = STAGE_DAILY_INFO.map(stage => ({
|
||||||
isCustom: false,
|
label: stage.text,
|
||||||
}))
|
value: stage.value,
|
||||||
const customOptions = Object.keys(customStageNames.value).map(key => ({
|
isCustom: false,
|
||||||
label: customStageNames.value[key],
|
}))
|
||||||
value: key,
|
const customOptions = Object.keys(customStageNames.value).map(key => ({
|
||||||
isCustom: true,
|
label: customStageNames.value[key],
|
||||||
}))
|
value: key,
|
||||||
return [...baseOptions, ...customOptions]
|
isCustom: true,
|
||||||
|
}))
|
||||||
|
stageOptionsCache.value.set(cacheKey, [...baseOptions, ...customOptions])
|
||||||
|
}
|
||||||
|
return stageOptionsCache.value.get(cacheKey) || []
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCustomStage = (value: string, columnKey: string) => {
|
// 优化getSelectOptions函数,添加缓存
|
||||||
if (!value || value === '-') return false
|
|
||||||
const dayNumber = getDayNumber(columnKey)
|
|
||||||
let availableStages: string[]
|
|
||||||
if (dayNumber === 0) {
|
|
||||||
availableStages = STAGE_DAILY_INFO.map(stage => stage.value)
|
|
||||||
} else {
|
|
||||||
availableStages = STAGE_DAILY_INFO.filter(stage => stage.days.includes(dayNumber)).map(
|
|
||||||
stage => stage.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return !availableStages.includes(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSelectOptions = (columnKey: string, taskName: string, currentValue?: string) => {
|
const getSelectOptions = (columnKey: string, taskName: string, currentValue?: string) => {
|
||||||
|
const cacheKey = `${columnKey}_${taskName}_${currentValue || ''}`
|
||||||
|
|
||||||
|
if (stageOptionsCache.value.has(cacheKey)) {
|
||||||
|
return stageOptionsCache.value.get(cacheKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
let options: any[] = []
|
||||||
|
|
||||||
switch (taskName) {
|
switch (taskName) {
|
||||||
case '连战次数':
|
case '连战次数':
|
||||||
return [
|
options = [
|
||||||
{ label: 'AUTO', value: '0' },
|
{ label: 'AUTO', value: '0' },
|
||||||
{ label: '1', value: '1' },
|
{ label: '1', value: '1' },
|
||||||
{ label: '2', value: '2' },
|
{ label: '2', value: '2' },
|
||||||
@@ -452,6 +455,7 @@ const getSelectOptions = (columnKey: string, taskName: string, currentValue?: st
|
|||||||
{ label: '6', value: '6' },
|
{ label: '6', value: '6' },
|
||||||
{ label: '不切换', value: '-1' },
|
{ label: '不切换', value: '-1' },
|
||||||
]
|
]
|
||||||
|
break
|
||||||
case '关卡选择':
|
case '关卡选择':
|
||||||
case '备选关卡-1':
|
case '备选关卡-1':
|
||||||
case '备选关卡-2':
|
case '备选关卡-2':
|
||||||
@@ -486,11 +490,30 @@ const getSelectOptions = (columnKey: string, taskName: string, currentValue?: st
|
|||||||
value: customStageNames.value[key],
|
value: customStageNames.value[key],
|
||||||
isCustom: true,
|
isCustom: true,
|
||||||
}))
|
}))
|
||||||
return [...baseOptions, ...customOptions]
|
options = [...baseOptions, ...customOptions]
|
||||||
|
break
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return []
|
options = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 缓存结果
|
||||||
|
stageOptionsCache.value.set(cacheKey, options)
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
const isCustomStage = (value: string, columnKey: string) => {
|
||||||
|
if (!value || value === '-') return false
|
||||||
|
const dayNumber = getDayNumber(columnKey)
|
||||||
|
let availableStages: string[]
|
||||||
|
if (dayNumber === 0) {
|
||||||
|
availableStages = STAGE_DAILY_INFO.map(stage => stage.value)
|
||||||
|
} else {
|
||||||
|
availableStages = STAGE_DAILY_INFO.filter(stage => stage.days.includes(dayNumber)).map(
|
||||||
|
stage => stage.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return !availableStages.includes(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPlaceholder = (taskName: string) => {
|
const getPlaceholder = (taskName: string) => {
|
||||||
@@ -549,9 +572,11 @@ const isStageEnabled = (stageValue: string, columnKey: string) => {
|
|||||||
|
|
||||||
const toggleStage = (stageValue: string, columnKey: string, checked: boolean) => {
|
const toggleStage = (stageValue: string, columnKey: string, checked: boolean) => {
|
||||||
const stageSlots = ['Stage', 'Stage_1', 'Stage_2', 'Stage_3']
|
const stageSlots = ['Stage', 'Stage_1', 'Stage_2', 'Stage_3']
|
||||||
|
const newRows = [...rows.value]
|
||||||
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
for (const slot of stageSlots) {
|
for (const slot of stageSlots) {
|
||||||
const row = rows.value.find(r => r.key === slot) as TableRow | undefined
|
const row = newRows.find(r => r.key === slot) as TableRow | undefined
|
||||||
if (row && ((row as any)[columnKey] === '-' || (row as any)[columnKey] === '')) {
|
if (row && ((row as any)[columnKey] === '-' || (row as any)[columnKey] === '')) {
|
||||||
;(row as any)[columnKey] = stageValue
|
;(row as any)[columnKey] = stageValue
|
||||||
break
|
break
|
||||||
@@ -559,12 +584,14 @@ const toggleStage = (stageValue: string, columnKey: string, checked: boolean) =>
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const slot of stageSlots) {
|
for (const slot of stageSlots) {
|
||||||
const row = rows.value.find(r => r.key === slot) as TableRow | undefined
|
const row = newRows.find(r => r.key === slot) as TableRow | undefined
|
||||||
if (row && (row as any)[columnKey] === stageValue) {
|
if (row && (row as any)[columnKey] === stageValue) {
|
||||||
;(row as any)[columnKey] = '-'
|
;(row as any)[columnKey] = '-'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rows.value = newRows
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSimpleTaskTagColor = (taskName: string) => {
|
const getSimpleTaskTagColor = (taskName: string) => {
|
||||||
@@ -626,29 +653,6 @@ const disableAllStages = (stageValue: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 props.tableData 映射到 rows
|
|
||||||
const applyPlanDataToRows = (plan: Record<string, any> | null | undefined) => {
|
|
||||||
if (!plan) return
|
|
||||||
const timeKeys = [
|
|
||||||
'ALL',
|
|
||||||
'Monday',
|
|
||||||
'Tuesday',
|
|
||||||
'Wednesday',
|
|
||||||
'Thursday',
|
|
||||||
'Friday',
|
|
||||||
'Saturday',
|
|
||||||
'Sunday',
|
|
||||||
]
|
|
||||||
rows.value.forEach(row => {
|
|
||||||
const fieldKey = row.key
|
|
||||||
timeKeys.forEach(timeKey => {
|
|
||||||
if (plan[timeKey] && plan[timeKey][fieldKey] !== undefined) {
|
|
||||||
;(row as any)[timeKey] = plan[timeKey][fieldKey]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 rows 组装为 API 所需结构
|
// 从 rows 组装为 API 所需结构
|
||||||
const buildPlanDataFromRows = (): Record<string, any> => {
|
const buildPlanDataFromRows = (): Record<string, any> => {
|
||||||
const planData: Record<string, any> = {}
|
const planData: Record<string, any> = {}
|
||||||
@@ -671,6 +675,48 @@ const buildPlanDataFromRows = (): Record<string, any> => {
|
|||||||
return planData
|
return planData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 优化数据同步,但保持响应式
|
||||||
|
const applyPlanDataToRows = (plan: Record<string, any> | null | undefined) => {
|
||||||
|
if (!plan) return
|
||||||
|
|
||||||
|
const timeKeys = [
|
||||||
|
'ALL',
|
||||||
|
'Monday',
|
||||||
|
'Tuesday',
|
||||||
|
'Wednesday',
|
||||||
|
'Thursday',
|
||||||
|
'Friday',
|
||||||
|
'Saturday',
|
||||||
|
'Sunday',
|
||||||
|
]
|
||||||
|
|
||||||
|
rows.value.forEach(row => {
|
||||||
|
const fieldKey = row.key
|
||||||
|
timeKeys.forEach(timeKey => {
|
||||||
|
if (plan[timeKey] && plan[timeKey][fieldKey] !== undefined) {
|
||||||
|
;(row as any)[timeKey] = plan[timeKey][fieldKey]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 清除缓存以重新计算选项
|
||||||
|
stageOptionsCache.value.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简化的防抖函数
|
||||||
|
const debounce = <T extends (...args: any[]) => any>(func: T, wait: number): T => {
|
||||||
|
let timeout: NodeJS.Timeout | null = null
|
||||||
|
return ((...args: any[]) => {
|
||||||
|
if (timeout) clearTimeout(timeout)
|
||||||
|
timeout = setTimeout(() => func(...args), wait)
|
||||||
|
}) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
const debouncedEmitUpdate = debounce(() => {
|
||||||
|
emit('update-table-data', buildPlanDataFromRows())
|
||||||
|
}, 150)
|
||||||
|
|
||||||
|
// 恢复正常的watch监听
|
||||||
watch(
|
watch(
|
||||||
() => props.tableData,
|
() => props.tableData,
|
||||||
newVal => {
|
newVal => {
|
||||||
@@ -679,28 +725,14 @@ watch(
|
|||||||
{ immediate: true, deep: true }
|
{ immediate: true, deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 监听rows变化并触发更新
|
||||||
watch(
|
watch(
|
||||||
() =>
|
rows,
|
||||||
rows.value.map(r => ({
|
|
||||||
key: r.key,
|
|
||||||
ALL: r.ALL,
|
|
||||||
Monday: r.Monday,
|
|
||||||
Tuesday: r.Tuesday,
|
|
||||||
Wednesday: r.Wednesday,
|
|
||||||
Thursday: r.Thursday,
|
|
||||||
Friday: r.Friday,
|
|
||||||
Saturday: r.Saturday,
|
|
||||||
Sunday: r.Sunday,
|
|
||||||
})),
|
|
||||||
() => {
|
() => {
|
||||||
emit('update-table-data', buildPlanDataFromRows())
|
debouncedEmitUpdate()
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
applyPlanDataToRows(props.tableData || {})
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user