fix(web): 系统设置 CRUD 修复 — version 乐观锁 + 语言字段映射 + JSON 显示
- API 层所有 Info/Request 接口添加 version 字段,update 函数传递 version
- delete 函数改为 client.delete(url, { data: { version } }) 发送 JSON body
- LanguageInfo.enabled → is_active,匹配后端 LanguageResp 字段名
- LanguageManager 编辑弹窗简化为只读详情(后端仅支持 is_active 切换)
- SystemSettings 设置值显示改用 JSON.stringify 而非 String()
- SystemSettings updateSetting 发送解析后的 JSON 对象而非字符串
This commit is contained in:
@@ -8,6 +8,7 @@ export interface DictionaryItemInfo {
|
|||||||
value: string;
|
value: string;
|
||||||
sort_order: number;
|
sort_order: number;
|
||||||
color?: string;
|
color?: string;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DictionaryInfo {
|
export interface DictionaryInfo {
|
||||||
@@ -16,6 +17,7 @@ export interface DictionaryInfo {
|
|||||||
code: string;
|
code: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
items: DictionaryItemInfo[];
|
items: DictionaryItemInfo[];
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateDictionaryRequest {
|
export interface CreateDictionaryRequest {
|
||||||
@@ -27,6 +29,7 @@ export interface CreateDictionaryRequest {
|
|||||||
export interface UpdateDictionaryRequest {
|
export interface UpdateDictionaryRequest {
|
||||||
name?: string;
|
name?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listDictionaries(page = 1, pageSize = 20) {
|
export async function listDictionaries(page = 1, pageSize = 20) {
|
||||||
@@ -53,8 +56,8 @@ export async function updateDictionary(id: string, req: UpdateDictionaryRequest)
|
|||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteDictionary(id: string) {
|
export async function deleteDictionary(id: string, version: number) {
|
||||||
await client.delete(`/config/dictionaries/${id}`);
|
await client.delete(`/config/dictionaries/${id}`, { data: { version } });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listItemsByCode(code: string) {
|
export async function listItemsByCode(code: string) {
|
||||||
@@ -77,6 +80,7 @@ export interface UpdateDictionaryItemRequest {
|
|||||||
value?: string;
|
value?: string;
|
||||||
sort_order?: number;
|
sort_order?: number;
|
||||||
color?: string;
|
color?: string;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createDictionaryItem(
|
export async function createDictionaryItem(
|
||||||
@@ -102,6 +106,6 @@ export async function updateDictionaryItem(
|
|||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteDictionaryItem(dictionaryId: string, itemId: string) {
|
export async function deleteDictionaryItem(dictionaryId: string, itemId: string, version: number) {
|
||||||
await client.delete(`/config/dictionaries/${dictionaryId}/items/${itemId}`);
|
await client.delete(`/config/dictionaries/${dictionaryId}/items/${itemId}`, { data: { version } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,11 @@ import client from './client';
|
|||||||
export interface LanguageInfo {
|
export interface LanguageInfo {
|
||||||
code: string;
|
code: string;
|
||||||
name: string;
|
name: string;
|
||||||
enabled: boolean;
|
is_active: boolean;
|
||||||
translations?: Record<string, string>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateLanguageRequest {
|
export interface UpdateLanguageRequest {
|
||||||
name?: string;
|
is_active: boolean;
|
||||||
enabled?: boolean;
|
|
||||||
translations?: Record<string, string>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- API Functions ---
|
// --- API Functions ---
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface MenuInfo {
|
|||||||
menu_type: string;
|
menu_type: string;
|
||||||
permission?: string;
|
permission?: string;
|
||||||
children: MenuInfo[];
|
children: MenuInfo[];
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MenuItemReq {
|
export interface MenuItemReq {
|
||||||
@@ -24,6 +25,7 @@ export interface MenuItemReq {
|
|||||||
menu_type?: string;
|
menu_type?: string;
|
||||||
permission?: string;
|
permission?: string;
|
||||||
role_ids?: string[];
|
role_ids?: string[];
|
||||||
|
version?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMenus() {
|
export async function getMenus() {
|
||||||
@@ -51,6 +53,6 @@ export async function updateMenu(id: string, req: MenuItemReq) {
|
|||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteMenu(id: string) {
|
export async function deleteMenu(id: string, version: number) {
|
||||||
await client.delete(`/config/menus/${id}`);
|
await client.delete(`/config/menus/${id}`, { data: { version } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface NumberingRuleInfo {
|
|||||||
separator: string;
|
separator: string;
|
||||||
reset_cycle: string;
|
reset_cycle: string;
|
||||||
last_reset_date?: string;
|
last_reset_date?: string;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateNumberingRuleRequest {
|
export interface CreateNumberingRuleRequest {
|
||||||
@@ -33,6 +34,7 @@ export interface UpdateNumberingRuleRequest {
|
|||||||
seq_length?: number;
|
seq_length?: number;
|
||||||
separator?: string;
|
separator?: string;
|
||||||
reset_cycle?: string;
|
reset_cycle?: string;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listNumberingRules(page = 1, pageSize = 20) {
|
export async function listNumberingRules(page = 1, pageSize = 20) {
|
||||||
@@ -66,6 +68,6 @@ export async function generateNumber(id: string) {
|
|||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteNumberingRule(id: string) {
|
export async function deleteNumberingRule(id: string, version: number) {
|
||||||
await client.delete(`/config/numbering-rules/${id}`);
|
await client.delete(`/config/numbering-rules/${id}`, { data: { version } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface SettingInfo {
|
|||||||
scope_id?: string;
|
scope_id?: string;
|
||||||
setting_key: string;
|
setting_key: string;
|
||||||
setting_value: unknown;
|
setting_value: unknown;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSetting(key: string, scope?: string, scopeId?: string) {
|
export async function getSetting(key: string, scope?: string, scopeId?: string) {
|
||||||
@@ -16,14 +17,14 @@ export async function getSetting(key: string, scope?: string, scopeId?: string)
|
|||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateSetting(key: string, settingValue: unknown) {
|
export async function updateSetting(key: string, settingValue: unknown, version?: number) {
|
||||||
const { data } = await client.put<{ success: boolean; data: SettingInfo }>(
|
const { data } = await client.put<{ success: boolean; data: SettingInfo }>(
|
||||||
`/config/settings/${key}`,
|
`/config/settings/${key}`,
|
||||||
{ setting_value: settingValue },
|
{ setting_value: settingValue, version },
|
||||||
);
|
);
|
||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteSetting(key: string) {
|
export async function deleteSetting(key: string, version: number) {
|
||||||
await client.delete(`/config/settings/${encodeURIComponent(key)}`);
|
await client.delete(`/config/settings/${encodeURIComponent(key)}`, { data: { version } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default function DictionaryManager() {
|
|||||||
const handleDictSubmit = async (values: CreateDictionaryRequest) => {
|
const handleDictSubmit = async (values: CreateDictionaryRequest) => {
|
||||||
try {
|
try {
|
||||||
if (editDict) {
|
if (editDict) {
|
||||||
await updateDictionary(editDict.id, values);
|
await updateDictionary(editDict.id, { ...values, version: editDict.version });
|
||||||
message.success('字典更新成功');
|
message.success('字典更新成功');
|
||||||
} else {
|
} else {
|
||||||
await createDictionary(values);
|
await createDictionary(values);
|
||||||
@@ -82,9 +82,9 @@ export default function DictionaryManager() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteDict = async (id: string) => {
|
const handleDeleteDict = async (id: string, version: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteDictionary(id);
|
await deleteDictionary(id, version);
|
||||||
message.success('字典已删除');
|
message.success('字典已删除');
|
||||||
fetchDictionaries();
|
fetchDictionaries();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -139,7 +139,7 @@ export default function DictionaryManager() {
|
|||||||
if (!activeDictId) return;
|
if (!activeDictId) return;
|
||||||
try {
|
try {
|
||||||
if (editItem) {
|
if (editItem) {
|
||||||
await updateDictionaryItem(activeDictId, editItem.id, values as UpdateDictionaryItemRequest);
|
await updateDictionaryItem(activeDictId, editItem.id, { ...values, version: editItem.version } as UpdateDictionaryItemRequest);
|
||||||
message.success('字典项更新成功');
|
message.success('字典项更新成功');
|
||||||
} else {
|
} else {
|
||||||
await createDictionaryItem(activeDictId, values);
|
await createDictionaryItem(activeDictId, values);
|
||||||
@@ -155,9 +155,9 @@ export default function DictionaryManager() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteItem = async (dictId: string, itemId: string) => {
|
const handleDeleteItem = async (dictId: string, itemId: string, version: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteDictionaryItem(dictId, itemId);
|
await deleteDictionaryItem(dictId, itemId, version);
|
||||||
message.success('字典项已删除');
|
message.success('字典项已删除');
|
||||||
fetchDictionaries();
|
fetchDictionaries();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -196,7 +196,7 @@ export default function DictionaryManager() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除此字典?"
|
title="确定删除此字典?"
|
||||||
onConfirm={() => handleDeleteDict(record.id)}
|
onConfirm={() => handleDeleteDict(record.id, record.version)}
|
||||||
>
|
>
|
||||||
<Button size="small" danger>
|
<Button size="small" danger>
|
||||||
删除
|
删除
|
||||||
@@ -232,7 +232,7 @@ export default function DictionaryManager() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除此字典项?"
|
title="确定删除此字典项?"
|
||||||
onConfirm={() => handleDeleteItem(dictId, record.id)}
|
onConfirm={() => handleDeleteItem(dictId, record.id, record.version)}
|
||||||
>
|
>
|
||||||
<Button size="small" danger>
|
<Button size="small" danger>
|
||||||
删除
|
删除
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import {
|
|||||||
Table,
|
Table,
|
||||||
Switch,
|
Switch,
|
||||||
Modal,
|
Modal,
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
Button,
|
Button,
|
||||||
Space,
|
Space,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -25,7 +23,6 @@ export default function LanguageManager() {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [editModalOpen, setEditModalOpen] = useState(false);
|
const [editModalOpen, setEditModalOpen] = useState(false);
|
||||||
const [editingLang, setEditingLang] = useState<LanguageInfo | null>(null);
|
const [editingLang, setEditingLang] = useState<LanguageInfo | null>(null);
|
||||||
const [editForm] = Form.useForm();
|
|
||||||
|
|
||||||
const fetchLanguages = useCallback(async () => {
|
const fetchLanguages = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -44,15 +41,15 @@ export default function LanguageManager() {
|
|||||||
|
|
||||||
// --- Enable / Disable Toggle ---
|
// --- Enable / Disable Toggle ---
|
||||||
|
|
||||||
const handleToggle = async (record: LanguageInfo, enabled: boolean) => {
|
const handleToggle = async (record: LanguageInfo, checked: boolean) => {
|
||||||
try {
|
try {
|
||||||
await updateLanguage(record.code, { enabled });
|
await updateLanguage(record.code, { is_active: checked });
|
||||||
setLanguages((prev) =>
|
setLanguages((prev) =>
|
||||||
prev.map((lang) =>
|
prev.map((lang) =>
|
||||||
lang.code === record.code ? { ...lang, enabled } : lang,
|
lang.code === record.code ? { ...lang, is_active: checked } : lang,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
message.success(enabled ? '已启用' : '已禁用');
|
message.success(checked ? '已启用' : '已禁用');
|
||||||
} catch {
|
} catch {
|
||||||
message.error('操作失败');
|
message.error('操作失败');
|
||||||
}
|
}
|
||||||
@@ -62,45 +59,20 @@ export default function LanguageManager() {
|
|||||||
|
|
||||||
const openEdit = (lang: LanguageInfo) => {
|
const openEdit = (lang: LanguageInfo) => {
|
||||||
setEditingLang(lang);
|
setEditingLang(lang);
|
||||||
editForm.setFieldsValue({
|
|
||||||
name: lang.name,
|
|
||||||
translations: lang.translations
|
|
||||||
? Object.entries(lang.translations)
|
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
|
||||||
.join('\n')
|
|
||||||
: '',
|
|
||||||
});
|
|
||||||
setEditModalOpen(true);
|
setEditModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeEdit = () => {
|
const closeEdit = () => {
|
||||||
setEditModalOpen(false);
|
setEditModalOpen(false);
|
||||||
setEditingLang(null);
|
setEditingLang(null);
|
||||||
editForm.resetFields();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditSubmit = async (values: { name: string; translations: string }) => {
|
const handleEditSubmit = async () => {
|
||||||
if (!editingLang) return;
|
if (!editingLang) return;
|
||||||
|
|
||||||
const translations: Record<string, string> = {};
|
|
||||||
if (values.translations?.trim()) {
|
|
||||||
for (const line of values.translations.split('\n')) {
|
|
||||||
const trimmed = line.trim();
|
|
||||||
if (!trimmed) continue;
|
|
||||||
const eqIndex = trimmed.indexOf('=');
|
|
||||||
if (eqIndex === -1) continue;
|
|
||||||
const key = trimmed.slice(0, eqIndex).trim();
|
|
||||||
const val = trimmed.slice(eqIndex + 1).trim();
|
|
||||||
if (key) {
|
|
||||||
translations[key] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updated = await updateLanguage(editingLang.code, {
|
const updated = await updateLanguage(editingLang.code, {
|
||||||
name: values.name,
|
is_active: editingLang.is_active,
|
||||||
translations,
|
|
||||||
});
|
});
|
||||||
setLanguages((prev) =>
|
setLanguages((prev) =>
|
||||||
prev.map((lang) =>
|
prev.map((lang) =>
|
||||||
@@ -134,19 +106,19 @@ export default function LanguageManager() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
dataIndex: 'enabled',
|
dataIndex: 'is_active',
|
||||||
key: 'enabled',
|
key: 'is_active',
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (enabled: boolean, record: LanguageInfo) => (
|
render: (is_active: boolean, record: LanguageInfo) => (
|
||||||
<Switch checked={enabled} onChange={(checked) => handleToggle(record, checked)} />
|
<Switch checked={is_active} onChange={(checked) => handleToggle(record, checked)} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '翻译条目数',
|
title: '状态标签',
|
||||||
key: 'translationCount',
|
key: 'statusLabel',
|
||||||
width: 140,
|
width: 140,
|
||||||
render: (_: unknown, record: LanguageInfo) =>
|
render: (_: unknown, record: LanguageInfo) =>
|
||||||
record.translations ? Object.keys(record.translations).length : 0,
|
record.is_active ? '已启用' : '已禁用',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
@@ -183,27 +155,20 @@ export default function LanguageManager() {
|
|||||||
|
|
||||||
{/* Edit Modal */}
|
{/* Edit Modal */}
|
||||||
<Modal
|
<Modal
|
||||||
title={`编辑语言 - ${editingLang?.name ?? ''}`}
|
title={`语言详情 - ${editingLang?.name ?? ''}`}
|
||||||
open={editModalOpen}
|
open={editModalOpen}
|
||||||
onCancel={closeEdit}
|
onCancel={closeEdit}
|
||||||
onOk={() => editForm.submit()}
|
onOk={() => handleEditSubmit()}
|
||||||
>
|
>
|
||||||
<Form form={editForm} onFinish={handleEditSubmit} layout="vertical">
|
<div style={{ marginBottom: 12 }}>
|
||||||
<Form.Item
|
<strong>语言代码:</strong>{editingLang?.code}
|
||||||
name="name"
|
</div>
|
||||||
label="语言名称"
|
<div style={{ marginBottom: 12 }}>
|
||||||
rules={[{ required: true, message: '请输入语言名称' }]}
|
<strong>语言名称:</strong>{editingLang?.name}
|
||||||
>
|
</div>
|
||||||
<Input />
|
<div>
|
||||||
</Form.Item>
|
<strong>状态:</strong>{editingLang?.is_active ? '已启用' : '已禁用'}
|
||||||
<Form.Item
|
</div>
|
||||||
name="translations"
|
|
||||||
label="翻译内容"
|
|
||||||
extra="每行一条,格式:key=value"
|
|
||||||
>
|
|
||||||
<Input.TextArea rows={10} placeholder={'common.save=保存\ncommon.cancel=取消'} />
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export default function MenuConfig() {
|
|||||||
const handleSubmit = async (values: MenuItemReq) => {
|
const handleSubmit = async (values: MenuItemReq) => {
|
||||||
try {
|
try {
|
||||||
if (editMenu) {
|
if (editMenu) {
|
||||||
await updateMenu(editMenu.id, values);
|
await updateMenu(editMenu.id, { ...values, version: editMenu.version });
|
||||||
message.success('菜单更新成功');
|
message.success('菜单更新成功');
|
||||||
} else {
|
} else {
|
||||||
await createMenu(values);
|
await createMenu(values);
|
||||||
@@ -110,9 +110,9 @@ export default function MenuConfig() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (id: string) => {
|
const handleDelete = async (id: string, version: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteMenu(id);
|
await deleteMenu(id, version);
|
||||||
message.success('菜单已删除');
|
message.success('菜单已删除');
|
||||||
fetchMenus();
|
fetchMenus();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -203,7 +203,7 @@ export default function MenuConfig() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除此菜单?"
|
title="确定删除此菜单?"
|
||||||
onConfirm={() => handleDelete(record.id)}
|
onConfirm={() => handleDelete(record.id, record.version)}
|
||||||
>
|
>
|
||||||
<Button size="small" danger>
|
<Button size="small" danger>
|
||||||
删除
|
删除
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export default function NumberingRules() {
|
|||||||
const handleSubmit = async (values: CreateNumberingRuleRequest) => {
|
const handleSubmit = async (values: CreateNumberingRuleRequest) => {
|
||||||
try {
|
try {
|
||||||
if (editRule) {
|
if (editRule) {
|
||||||
await updateNumberingRule(editRule.id, values as UpdateNumberingRuleRequest);
|
await updateNumberingRule(editRule.id, { ...values, version: editRule.version } as UpdateNumberingRuleRequest);
|
||||||
message.success('编号规则更新成功');
|
message.success('编号规则更新成功');
|
||||||
} else {
|
} else {
|
||||||
await createNumberingRule(values);
|
await createNumberingRule(values);
|
||||||
@@ -87,9 +87,9 @@ export default function NumberingRules() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (id: string) => {
|
const handleDelete = async (id: string, version: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteNumberingRule(id);
|
await deleteNumberingRule(id, version);
|
||||||
message.success('编号规则已删除');
|
message.success('编号规则已删除');
|
||||||
fetchRules();
|
fetchRules();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -193,7 +193,7 @@ export default function NumberingRules() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除此编号规则?"
|
title="确定删除此编号规则?"
|
||||||
onConfirm={() => handleDelete(record.id)}
|
onConfirm={() => handleDelete(record.id, record.version)}
|
||||||
>
|
>
|
||||||
<Button size="small" danger>
|
<Button size="small" danger>
|
||||||
删除
|
删除
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { useThemeMode } from '../../hooks/useThemeMode';
|
|||||||
interface SettingEntry {
|
interface SettingEntry {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
version: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SystemSettings() {
|
export default function SystemSettings() {
|
||||||
@@ -38,16 +39,19 @@ export default function SystemSettings() {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const result = await getSetting(searchKey.trim());
|
const result = await getSetting(searchKey.trim());
|
||||||
const value = String(result.setting_value ?? '');
|
const value = typeof result.setting_value === 'object' && result.setting_value !== null
|
||||||
|
? JSON.stringify(result.setting_value, null, 2)
|
||||||
|
: String(result.setting_value ?? '');
|
||||||
|
const version = result.version;
|
||||||
|
|
||||||
setEntries((prev) => {
|
setEntries((prev) => {
|
||||||
const exists = prev.findIndex((e) => e.key === searchKey.trim());
|
const exists = prev.findIndex((e) => e.key === searchKey.trim());
|
||||||
if (exists >= 0) {
|
if (exists >= 0) {
|
||||||
const updated = [...prev];
|
const updated = [...prev];
|
||||||
updated[exists] = { ...updated[exists], value };
|
updated[exists] = { ...updated[exists], value, version };
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
return [...prev, { key: searchKey.trim(), value }];
|
return [...prev, { key: searchKey.trim(), value, version }];
|
||||||
});
|
});
|
||||||
message.success('查询成功');
|
message.success('查询成功');
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
@@ -71,16 +75,19 @@ export default function SystemSettings() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateSetting(key, value);
|
const editVersion = editEntry?.version;
|
||||||
|
const jsonValue = JSON.parse(value);
|
||||||
|
const result = await updateSetting(key, jsonValue, editVersion);
|
||||||
|
|
||||||
setEntries((prev) => {
|
setEntries((prev) => {
|
||||||
|
const displayValue = typeof jsonValue === 'object' ? JSON.stringify(jsonValue, null, 2) : value;
|
||||||
const exists = prev.findIndex((e) => e.key === key);
|
const exists = prev.findIndex((e) => e.key === key);
|
||||||
if (exists >= 0) {
|
if (exists >= 0) {
|
||||||
const updated = [...prev];
|
const updated = [...prev];
|
||||||
updated[exists] = { key, value };
|
updated[exists] = { key, value: displayValue, version: result.version };
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
return [...prev, { key, value }];
|
return [...prev, { key, value: displayValue, version: result.version }];
|
||||||
});
|
});
|
||||||
|
|
||||||
message.success('设置已保存');
|
message.success('设置已保存');
|
||||||
@@ -92,9 +99,9 @@ export default function SystemSettings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (key: string) => {
|
const handleDelete = async (key: string, version: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteSetting(key);
|
await deleteSetting(key, version);
|
||||||
setEntries((prev) => prev.filter((e) => e.key !== key));
|
setEntries((prev) => prev.filter((e) => e.key !== key));
|
||||||
message.success('设置已删除');
|
message.success('设置已删除');
|
||||||
} catch {
|
} catch {
|
||||||
@@ -165,7 +172,7 @@ export default function SystemSettings() {
|
|||||||
/>
|
/>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除此设置?"
|
title="确定删除此设置?"
|
||||||
onConfirm={() => handleDelete(record.key)}
|
onConfirm={() => handleDelete(record.key, record.version)}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
Reference in New Issue
Block a user