2026-05-22 13:27:17 +08:00

248 lines
6.0 KiB
Vue

<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue';
import { Page } from '@vben/common-ui';
import { useAccessStore } from '@vben/stores';
import {
getResidentCpConfig,
saveResidentCpConfig,
} from '#/api/legacy/resident-activity';
import { getAllowedSysOrigins } from '#/views/system/shared';
import {
Button,
Card,
Input,
InputNumber,
Modal,
Select,
Space,
Spin,
Table,
Tag,
message,
} from 'antdv-next';
defineOptions({ name: 'ResidentCpConfigPage' });
interface CpLevelConfig {
cabinConfigId?: null | string;
level: number;
levelName: string;
requiredIntimacyValue: number;
}
function defaultLevel(level: number): CpLevelConfig {
return {
cabinConfigId: null,
level,
levelName: `CP ${level}`,
requiredIntimacyValue: 0,
};
}
function defaultLevels() {
return Array.from({ length: 5 }, (_, index) => defaultLevel(index + 1));
}
const accessStore = useAccessStore();
const sysOriginOptions = computed(() => {
const options = getAllowedSysOrigins(accessStore.accessCodes || []);
return options.length > 0 ? options : getAllowedSysOrigins([]);
});
const loading = ref(false);
const saving = ref(false);
const columns = [
{ dataIndex: 'level', key: 'level', title: '等级', width: 100 },
{ dataIndex: 'levelName', key: 'levelName', title: '等级文案', width: 260 },
{
dataIndex: 'requiredIntimacyValue',
key: 'requiredIntimacyValue',
title: '所需亲密值',
width: 220,
},
];
const form = reactive({
configured: false,
sysOrigin: '',
levels: defaultLevels(),
});
function normalizeLevels(levels: Array<Record<string, any>> | undefined) {
const levelMap = new Map<number, Record<string, any>>();
for (const item of levels || []) {
const level = Number(item.level || 0);
if (level >= 1 && level <= 5) {
levelMap.set(level, item);
}
}
return defaultLevels().map((fallback) => {
const item = levelMap.get(fallback.level);
if (!item) {
return fallback;
}
return {
cabinConfigId: item.cabinConfigId ? String(item.cabinConfigId) : null,
level: fallback.level,
levelName: String(item.levelName || fallback.levelName),
requiredIntimacyValue: Number(item.requiredIntimacyValue || 0),
};
});
}
function applyConfig(result: Record<string, any> | null | undefined) {
const value = result ?? {};
form.configured = Boolean(value.configured);
form.sysOrigin = String(
value.sysOrigin || form.sysOrigin || sysOriginOptions.value[0]?.value || '',
);
form.levels = normalizeLevels(value.levels);
}
async function loadConfig() {
if (!form.sysOrigin) {
return;
}
loading.value = true;
try {
const result = await getResidentCpConfig(form.sysOrigin);
applyConfig(result);
} finally {
loading.value = false;
}
}
function validateLevels() {
let previous = -1;
for (const item of form.levels) {
const requiredValue = Number(item.requiredIntimacyValue || 0);
if (requiredValue < 0) {
message.error('所需亲密值不能小于 0');
return false;
}
if (requiredValue < previous) {
message.error('所需亲密值需要按等级递增');
return false;
}
previous = requiredValue;
}
return true;
}
async function submitForm() {
if (!validateLevels()) {
return;
}
saving.value = true;
try {
await saveResidentCpConfig({
sysOrigin: form.sysOrigin,
levels: form.levels.map((item) => ({
cabinConfigId: item.cabinConfigId || null,
level: item.level,
levelName: String(item.levelName || `CP ${item.level}`).trim(),
requiredIntimacyValue: Number(item.requiredIntimacyValue || 0),
})),
});
message.success('保存成功');
await loadConfig();
} finally {
saving.value = false;
}
}
function handleSave() {
Modal.confirm({
async onOk() {
await submitForm();
},
title: '确认保存 CP 等级积分配置?',
content: '保存后 Flutter 端 CP 权益配置接口会读取新的 5 级亲密值。',
});
}
watch(
sysOriginOptions,
(options) => {
if (!form.sysOrigin) {
form.sysOrigin = String(options[0]?.value || '');
}
},
{ immediate: true },
);
watch(
() => form.sysOrigin,
(value) => {
if (value) {
void loadConfig();
}
},
{ immediate: true },
);
</script>
<template>
<Page auto-content-height>
<Spin :spinning="loading">
<Card :bordered="false" title="CP 等级积分配置">
<Space class="toolbar" wrap>
<Select
v-model:value="form.sysOrigin"
:options="sysOriginOptions"
option-filter-prop="label"
option-label-prop="label"
placeholder="请选择系统"
show-search
style="width: 180px"
/>
<Tag :color="form.configured ? 'success' : 'processing'">
{{ form.configured ? '已配置' : '未配置' }}
</Tag>
<Button :loading="saving" type="primary" @click="handleSave">
保存
</Button>
</Space>
<Table
:columns="columns"
:data-source="form.levels"
:pagination="false"
row-key="level"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'level'">
{{ record.level }}
</template>
<template v-else-if="column.key === 'levelName'">
<Input
v-model:value="record.levelName"
:maxlength="30"
placeholder="请输入等级文案"
/>
</template>
<template v-else-if="column.key === 'requiredIntimacyValue'">
<InputNumber
v-model:value="record.requiredIntimacyValue"
:min="0"
:precision="0"
style="width: 180px"
/>
</template>
</template>
</Table>
</Card>
</Spin>
</Page>
</template>
<style scoped>
.toolbar {
margin-bottom: 16px;
}
</style>