Commit 0480d43b by t0ng7u

🚀 feat(frontend): add robust boolean handling across settings pages

Summary
-------
1. Introduced a reusable `toBoolean` utility (`web/src/helpers/boolean.js`) that converts
   strings (`'true'/'false'`, `'1'/'0'`), numbers, and native booleans to a proper boolean.
2. Re-exported `toBoolean` via `web/src/helpers/index.js` for simple one-line imports.

Refactors
---------
• Systematically replaced all legacy `item.value === 'true'` checks with `toBoolean(item.value)` in
  the following components:
  – `SystemSetting.js`
  – `OperationSetting.js`
  – `PaymentSetting.js`
  – `RatioSetting.js`
  – `RateLimitSetting.js`
  – `ModelSetting.js`
  – `DrawingSetting.js`
  – `DashboardSetting.js`
  – `ChatsSetting.js`

• Unified import statements to
  `import { …, toBoolean } from '../../helpers';`
  removing redundant `../../helpers/boolean` paths.

Why
---
SQLite sometimes returns `1/0` or boolean literals instead of the string `'true'/'false'`, causing
checkbox states to reset on page reload. The new utility guarantees consistent boolean parsing,
fixing the issue across all environments (SQLite, MySQL, etc.) while improving code clarity.
parent 3425b6eb
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Card, Spin } from '@douyinfe/semi-ui'; import { Card, Spin } from '@douyinfe/semi-ui';
import SettingsChats from '../../pages/Setting/Chat/SettingsChats.js'; import SettingsChats from '../../pages/Setting/Chat/SettingsChats.js';
import { API, showError } from '../../helpers'; import { API, showError, toBoolean } from '../../helpers';
const ChatsSetting = () => { const ChatsSetting = () => {
let [inputs, setInputs] = useState({ let [inputs, setInputs] = useState({
...@@ -21,7 +21,7 @@ const ChatsSetting = () => { ...@@ -21,7 +21,7 @@ const ChatsSetting = () => {
item.key.endsWith('Enabled') || item.key.endsWith('Enabled') ||
['DefaultCollapseSidebar'].includes(item.key) ['DefaultCollapseSidebar'].includes(item.key)
) { ) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
import React, { useEffect, useState, useMemo } from 'react'; import React, { useEffect, useState, useMemo } from 'react';
import { Card, Spin, Button, Modal } from '@douyinfe/semi-ui'; import { Card, Spin, Button, Modal } from '@douyinfe/semi-ui';
import { API, showError, showSuccess } from '../../helpers'; import { API, showError, showSuccess, toBoolean } from '../../helpers';
import SettingsAPIInfo from '../../pages/Setting/Dashboard/SettingsAPIInfo.js'; import SettingsAPIInfo from '../../pages/Setting/Dashboard/SettingsAPIInfo.js';
import SettingsAnnouncements from '../../pages/Setting/Dashboard/SettingsAnnouncements.js'; import SettingsAnnouncements from '../../pages/Setting/Dashboard/SettingsAnnouncements.js';
import SettingsFAQ from '../../pages/Setting/Dashboard/SettingsFAQ.js'; import SettingsFAQ from '../../pages/Setting/Dashboard/SettingsFAQ.js';
...@@ -45,7 +45,7 @@ const DashboardSetting = () => { ...@@ -45,7 +45,7 @@ const DashboardSetting = () => {
} }
if (item.key.endsWith('Enabled') && if (item.key.endsWith('Enabled') &&
(item.key === 'DataExportEnabled')) { (item.key === 'DataExportEnabled')) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} }
}); });
setInputs(newInputs); setInputs(newInputs);
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Card, Spin } from '@douyinfe/semi-ui'; import { Card, Spin } from '@douyinfe/semi-ui';
import SettingsDrawing from '../../pages/Setting/Drawing/SettingsDrawing.js'; import SettingsDrawing from '../../pages/Setting/Drawing/SettingsDrawing.js';
import { API, showError } from '../../helpers'; import { API, showError, toBoolean } from '../../helpers';
const DrawingSetting = () => { const DrawingSetting = () => {
let [inputs, setInputs] = useState({ let [inputs, setInputs] = useState({
...@@ -23,7 +23,7 @@ const DrawingSetting = () => { ...@@ -23,7 +23,7 @@ const DrawingSetting = () => {
let newInputs = {}; let newInputs = {};
data.forEach((item) => { data.forEach((item) => {
if (item.key.endsWith('Enabled')) { if (item.key.endsWith('Enabled')) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Card, Spin, Tabs } from '@douyinfe/semi-ui'; import { Card, Spin, Tabs } from '@douyinfe/semi-ui';
import { API, showError, showSuccess } from '../../helpers'; import { API, showError, showSuccess, toBoolean } from '../../helpers';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import SettingGeminiModel from '../../pages/Setting/Model/SettingGeminiModel.js'; import SettingGeminiModel from '../../pages/Setting/Model/SettingGeminiModel.js';
import SettingClaudeModel from '../../pages/Setting/Model/SettingClaudeModel.js'; import SettingClaudeModel from '../../pages/Setting/Model/SettingClaudeModel.js';
...@@ -44,7 +44,7 @@ const ModelSetting = () => { ...@@ -44,7 +44,7 @@ const ModelSetting = () => {
} }
} }
if (item.key.endsWith('Enabled') || item.key.endsWith('enabled')) { if (item.key.endsWith('Enabled') || item.key.endsWith('enabled')) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
...@@ -5,7 +5,7 @@ import SettingsSensitiveWords from '../../pages/Setting/Operation/SettingsSensit ...@@ -5,7 +5,7 @@ import SettingsSensitiveWords from '../../pages/Setting/Operation/SettingsSensit
import SettingsLog from '../../pages/Setting/Operation/SettingsLog.js'; import SettingsLog from '../../pages/Setting/Operation/SettingsLog.js';
import SettingsMonitoring from '../../pages/Setting/Operation/SettingsMonitoring.js'; import SettingsMonitoring from '../../pages/Setting/Operation/SettingsMonitoring.js';
import SettingsCreditLimit from '../../pages/Setting/Operation/SettingsCreditLimit.js'; import SettingsCreditLimit from '../../pages/Setting/Operation/SettingsCreditLimit.js';
import { API, showError } from '../../helpers'; import { API, showError, toBoolean } from '../../helpers';
const OperationSetting = () => { const OperationSetting = () => {
let [inputs, setInputs] = useState({ let [inputs, setInputs] = useState({
...@@ -54,7 +54,7 @@ const OperationSetting = () => { ...@@ -54,7 +54,7 @@ const OperationSetting = () => {
item.key.endsWith('Enabled') || item.key.endsWith('Enabled') ||
['DefaultCollapseSidebar'].includes(item.key) ['DefaultCollapseSidebar'].includes(item.key)
) { ) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
...@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; ...@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { Card, Spin } from '@douyinfe/semi-ui'; import { Card, Spin } from '@douyinfe/semi-ui';
import SettingsGeneralPayment from '../../pages/Setting/Payment/SettingsGeneralPayment.js'; import SettingsGeneralPayment from '../../pages/Setting/Payment/SettingsGeneralPayment.js';
import SettingsPaymentGateway from '../../pages/Setting/Payment/SettingsPaymentGateway.js'; import SettingsPaymentGateway from '../../pages/Setting/Payment/SettingsPaymentGateway.js';
import { API, showError } from '../../helpers'; import { API, showError, toBoolean } from '../../helpers';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const PaymentSetting = () => { const PaymentSetting = () => {
...@@ -42,7 +42,7 @@ const PaymentSetting = () => { ...@@ -42,7 +42,7 @@ const PaymentSetting = () => {
break; break;
default: default:
if (item.key.endsWith('Enabled')) { if (item.key.endsWith('Enabled')) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Card, Spin } from '@douyinfe/semi-ui'; import { Card, Spin } from '@douyinfe/semi-ui';
import { API, showError } from '../../helpers/index.js'; import { API, showError, toBoolean } from '../../helpers/index.js';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import RequestRateLimit from '../../pages/Setting/RateLimit/SettingsRequestRateLimit.js'; import RequestRateLimit from '../../pages/Setting/RateLimit/SettingsRequestRateLimit.js';
...@@ -28,7 +28,7 @@ const RateLimitSetting = () => { ...@@ -28,7 +28,7 @@ const RateLimitSetting = () => {
} }
if (item.key.endsWith('Enabled')) { if (item.key.endsWith('Enabled')) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
...@@ -8,7 +8,7 @@ import ModelSettingsVisualEditor from '../../pages/Setting/Ratio/ModelSettingsVi ...@@ -8,7 +8,7 @@ import ModelSettingsVisualEditor from '../../pages/Setting/Ratio/ModelSettingsVi
import ModelRatioNotSetEditor from '../../pages/Setting/Ratio/ModelRationNotSetEditor.js'; import ModelRatioNotSetEditor from '../../pages/Setting/Ratio/ModelRationNotSetEditor.js';
import UpstreamRatioSync from '../../pages/Setting/Ratio/UpstreamRatioSync.js'; import UpstreamRatioSync from '../../pages/Setting/Ratio/UpstreamRatioSync.js';
import { API, showError } from '../../helpers'; import { API, showError, toBoolean } from '../../helpers';
const RatioSetting = () => { const RatioSetting = () => {
const { t } = useTranslation(); const { t } = useTranslation();
...@@ -51,7 +51,7 @@ const RatioSetting = () => { ...@@ -51,7 +51,7 @@ const RatioSetting = () => {
} }
} }
if (['DefaultUseAutoGroup', 'ExposeRatioEnabled'].includes(item.key)) { if (['DefaultUseAutoGroup', 'ExposeRatioEnabled'].includes(item.key)) {
newInputs[item.key] = item.value === 'true' ? true : false; newInputs[item.key] = toBoolean(item.value);
} else { } else {
newInputs[item.key] = item.value; newInputs[item.key] = item.value;
} }
......
...@@ -17,6 +17,7 @@ import { ...@@ -17,6 +17,7 @@ import {
removeTrailingSlash, removeTrailingSlash,
showError, showError,
showSuccess, showSuccess,
toBoolean,
} from '../../helpers'; } from '../../helpers';
import axios from 'axios'; import axios from 'axios';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
...@@ -106,7 +107,7 @@ const SystemSetting = () => { ...@@ -106,7 +107,7 @@ const SystemSetting = () => {
case 'LinuxDOOAuthEnabled': case 'LinuxDOOAuthEnabled':
case 'oidc.enabled': case 'oidc.enabled':
case 'WorkerAllowHttpImageRequestEnabled': case 'WorkerAllowHttpImageRequestEnabled':
item.value = item.value === 'true'; item.value = toBoolean(item.value);
break; break;
case 'Price': case 'Price':
case 'MinTopUp': case 'MinTopUp':
......
export const toBoolean = (value) => {
// 兼容字符串、数字以及布尔原生类型
if (typeof value === 'boolean') return value;
if (typeof value === 'number') return value === 1;
if (typeof value === 'string') {
const v = value.toLowerCase();
return v === 'true' || v === '1';
}
return false;
};
\ No newline at end of file
...@@ -6,3 +6,4 @@ export * from './render'; ...@@ -6,3 +6,4 @@ export * from './render';
export * from './log'; export * from './log';
export * from './data'; export * from './data';
export * from './token'; export * from './token';
export * from './boolean';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment