260 lines
8.1 KiB
Vue
260 lines
8.1 KiB
Vue
<template>
|
||
<div class="layout-padding">
|
||
<div class="layout-padding-auto layout-padding-view">
|
||
<el-card shadow="never" class="mb-4 overflow-auto">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<div class="flex items-center">
|
||
<el-button type="primary" icon="plus" @click="handleAddRow">
|
||
{{ $t('projectReviewPolicy.addRow') }}
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<el-table
|
||
:data="state.dataList"
|
||
style="width: 100%"
|
||
v-loading="state.loading"
|
||
border
|
||
row-key="id"
|
||
>
|
||
<el-table-column type="index" :label="$t('projectReviewPolicy.index')" width="60" />
|
||
|
||
<el-table-column prop="projectType" label="投资类别">
|
||
<template #default="{ row, $index }">
|
||
<el-select
|
||
v-model="row.projectType"
|
||
:placeholder="$t('projectReviewPolicy.selectProjectType')"
|
||
@change="handleFieldChange($index)"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="item in investmentCategoryOptions"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column :label="$t('projectReviewPolicy.finalReminderPeriod')">
|
||
<template #default="{ row, $index }">
|
||
<el-select
|
||
v-model="row.finalReminderPeriod"
|
||
@change="handleFieldChange($index)"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="item in finalReminderPeriodOptions"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column :label="$t('projectReviewPolicy.advanceReminder')">
|
||
<template #default="{ row, $index }">
|
||
<el-select
|
||
v-model="row.advanceReminderPeriod"
|
||
@change="handleFieldChange($index)"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="item in advanceReminderPeriodOptions"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column :label="$t('projectReviewPolicy.action')" width="120">
|
||
<template #default="{ row, $index }">
|
||
<el-button
|
||
text
|
||
size="small"
|
||
type="danger"
|
||
icon="delete"
|
||
@click="handleDeleteRow($index, row)"
|
||
>
|
||
{{ $t('common.delBtn') }}
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="mt-4 flex justify-end">
|
||
<el-button type="primary" @click="handleSaveAll" :loading="saving">
|
||
{{ $t('projectReviewPolicy.saveAll') }}
|
||
</el-button>
|
||
</div>
|
||
</el-card>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, reactive, onMounted } from 'vue';
|
||
import { useI18n } from 'vue-i18n';
|
||
import { useMessage } from '/@/hooks/message';
|
||
import {
|
||
fetchProjectReviewPolicyPage,
|
||
addProjectReviewPolicy,
|
||
updateProjectReviewPolicy,
|
||
deleteProjectReviewPolicy
|
||
} from '/@/api/config/projectReviewPolicy';
|
||
import { debounce } from 'lodash';
|
||
import { investmentCategoryOptions } from '/@/hooks/enums';
|
||
|
||
const { t } = useI18n();
|
||
const message = useMessage();
|
||
|
||
// 定义项目类型选项
|
||
const projectTypeOptions = ref([
|
||
{ value: '1', label: t('projectReviewPolicy.infrastructure') },
|
||
{ value: '2', label: t('projectReviewPolicy.industrial') },
|
||
{ value: '3', label: t('projectReviewPolicy.civilEngineering') },
|
||
{ value: '4', label: t('projectReviewPolicy.other') }
|
||
]);
|
||
|
||
// 最后提醒期限选项 (1-9年)
|
||
const finalReminderPeriodOptions = ref([
|
||
{ value: 1, label: '1' + t('projectReviewPolicy.year') },
|
||
{ value: 2, label: '2' + t('projectReviewPolicy.year') },
|
||
{ value: 3, label: '3' + t('projectReviewPolicy.year') },
|
||
{ value: 4, label: '4' + t('projectReviewPolicy.year') },
|
||
{ value: 5, label: '5' + t('projectReviewPolicy.year') },
|
||
{ value: 6, label: '6' + t('projectReviewPolicy.year') },
|
||
{ value: 7, label: '7' + t('projectReviewPolicy.year') },
|
||
{ value: 8, label: '8' + t('projectReviewPolicy.year') },
|
||
{ value: 9, label: '9' + t('projectReviewPolicy.year') }
|
||
]);
|
||
|
||
// 提前提醒选项 (无、提前3、15、30、60、90天)
|
||
const advanceReminderPeriodOptions = ref([
|
||
{ value: 0, label: t('projectReviewPolicy.none') },
|
||
{ value: 3, label: t('projectReviewPolicy.advance') + '3' + t('projectReviewPolicy.day') },
|
||
{ value: 15, label: t('projectReviewPolicy.advance') + '15' + t('projectReviewPolicy.day') },
|
||
{ value: 30, label: t('projectReviewPolicy.advance') + '30' + t('projectReviewPolicy.day') },
|
||
{ value: 60, label: t('projectReviewPolicy.advance') + '60' + t('projectReviewPolicy.day') },
|
||
{ value: 90, label: t('projectReviewPolicy.advance') + '90' + t('projectReviewPolicy.day') }
|
||
]);
|
||
|
||
// 表格状态
|
||
const state = reactive({
|
||
dataList: [] as any[],
|
||
loading: false,
|
||
});
|
||
|
||
// 保存状态
|
||
const saving = ref(false);
|
||
|
||
// 防抖保存函数
|
||
const debouncedSave = debounce(async (row, type) => {
|
||
try {
|
||
if (type === 'add') {
|
||
const res = await addProjectReviewPolicy(row);
|
||
// 更新ID
|
||
row.id = res.data?.id || row.id;
|
||
message.success(t('projectReviewPolicy.saveSuccess'));
|
||
} else if (type === 'update') {
|
||
await updateProjectReviewPolicy(row);
|
||
message.success(t('projectReviewPolicy.updateSuccess'));
|
||
}
|
||
} catch (err: any) {
|
||
message.error(err?.msg || err?.message || t('common.operateFail'));
|
||
}
|
||
}, 800);
|
||
|
||
// 字段变更处理
|
||
const handleFieldChange = (index: number) => {
|
||
const row = state.dataList[index];
|
||
if (!row) return;
|
||
|
||
// 如果是新行且没有ID,则添加
|
||
if (!row.id || row.id === '') {
|
||
debouncedSave(row, 'add');
|
||
} else {
|
||
// 否则更新现有行
|
||
debouncedSave(row, 'update');
|
||
}
|
||
};
|
||
|
||
// 添加行
|
||
const handleAddRow = () => {
|
||
state.dataList.push({
|
||
id: '',
|
||
projectType: '',
|
||
finalReminderPeriod: 1,
|
||
finalReminderUnit: '年',
|
||
advanceReminderPeriod: 30,
|
||
advanceReminderUnit: '天',
|
||
createTime: ''
|
||
});
|
||
};
|
||
|
||
// 删除行
|
||
const handleDeleteRow = async (index: number, row: any) => {
|
||
try {
|
||
if (row.id) {
|
||
// 如果有ID,从服务器删除
|
||
await deleteProjectReviewPolicy(row.id);
|
||
}
|
||
|
||
// 从前端列表中移除
|
||
state.dataList.splice(index, 1);
|
||
message.success(t('projectReviewPolicy.deleteSuccess'));
|
||
} catch (err: any) {
|
||
message.error(err?.msg || err?.message || t('common.operateFail'));
|
||
}
|
||
};
|
||
|
||
// 保存所有数据
|
||
const handleSaveAll = async () => {
|
||
saving.value = true;
|
||
try {
|
||
// 取消所有待处理的防抖调用
|
||
debouncedSave.cancel();
|
||
|
||
// 处理所有未保存的数据
|
||
const promises = state.dataList.map(item => {
|
||
if (!item.id || item.id === '') {
|
||
return addProjectReviewPolicy(item);
|
||
} else {
|
||
return updateProjectReviewPolicy(item);
|
||
}
|
||
});
|
||
|
||
await Promise.all(promises);
|
||
message.success(t('projectReviewPolicy.saveAllSuccess'));
|
||
await getDataList();
|
||
} catch (err: any) {
|
||
message.error(err?.msg || err?.message || t('common.operateFail'));
|
||
} finally {
|
||
saving.value = false;
|
||
}
|
||
};
|
||
|
||
// 获取数据列表
|
||
const getDataList = async () => {
|
||
try {
|
||
state.loading = true;
|
||
const res = await fetchProjectReviewPolicyPage({ page: 1, size: 1000 });
|
||
state.dataList = res.data?.records || [];
|
||
} catch (err: any) {
|
||
message.error(err?.msg || err?.message || t('common.operateFail'));
|
||
} finally {
|
||
state.loading = false;
|
||
}
|
||
};
|
||
|
||
// 初始化加载数据
|
||
onMounted(() => {
|
||
getDataList();
|
||
});
|
||
</script> |