1. 新增用户注册需要邮箱验证码
2. 机器码、软件权限控制、用户 隔离,除非超级管理员,其他用户只能看到自己下面的用户,管理员可以看到除超级管理员以外的所有
This commit is contained in:
lq1405 2025-03-16 23:00:31 +08:00
parent 208b887f79
commit 9a2bc86427
17 changed files with 407 additions and 35 deletions

View File

@ -73,7 +73,13 @@ export default [
name: 'laitoolOptions', name: 'laitoolOptions',
path: '/options/laitoolOptions', path: '/options/laitoolOptions',
component: './Options/LaitoolOptions/LaitoolOptions/index', component: './Options/LaitoolOptions/LaitoolOptions/index',
access: 'canLaitoolOptions', access: 'canOptions',
},
{
name: 'systemOptions',
path: '/options/systemOptions',
component: './Options/SystemOptions/index',
access: 'canOptions',
} }
] ]
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "lms", "name": "lms",
"version": "1.0.1", "version": "1.0.4",
"private": true, "private": true,
"description": "An out-of-box UI solution for enterprise applications", "description": "An out-of-box UI solution for enterprise applications",
"scripts": { "scripts": {

View File

@ -16,7 +16,6 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
isAdminOrSuperAdmin: false, isAdminOrSuperAdmin: false,
canOptions: false, canOptions: false,
canLaitoolOptions: false,
canApplySoftwareControl: false, canApplySoftwareControl: false,
canSofrwareControlManagement: false, canSofrwareControlManagement: false,
@ -51,14 +50,16 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
canUserManagement: true, canUserManagement: true,
canMachineManagement: true, canMachineManagement: true,
canUpgradeMachine: true canUpgradeMachine: true,
canSofrwareControlManagement: true,
} }
} }
if (currentUser?.roleNames?.includes("Admin")) { if (currentUser?.roleNames?.includes("Admin")) {
access = { access = {
...access, ...access,
canPrompt: true, canPrompt: false,
canUserManagement: true, canUserManagement: true,
canEditUser: true, canEditUser: true,
@ -66,8 +67,7 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
isAdmin: true, isAdmin: true,
isAdminOrSuperAdmin: true, isAdminOrSuperAdmin: true,
canOptions: true, canOptions: false,
canLaitoolOptions: true,
canMachineManagement: true, canMachineManagement: true,
canEditMachine: true, canEditMachine: true,
@ -93,7 +93,6 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
isAdminOrSuperAdmin: true, isAdminOrSuperAdmin: true,
canOptions: true, canOptions: true,
canLaitoolOptions: true,
canMachineManagement: true, canMachineManagement: true,
canEditMachine: true, canEditMachine: true,

View File

@ -9,6 +9,7 @@ export default {
'menu.options': '配置管理', 'menu.options': '配置管理',
'menu.options.laitoolOptions': 'Laitool配置', 'menu.options.laitoolOptions': 'Laitool配置',
'menu.options.systemOptions': '系统配置',
'menu.roleManagement': '角色管理', 'menu.roleManagement': '角色管理',

View File

@ -3,7 +3,7 @@ import { Form, Card, Row, Col, InputNumber, Button, Input, message } from 'antd'
import TextArea from 'antd/es/input/TextArea'; import TextArea from 'antd/es/input/TextArea';
import { useSoftStore } from '@/store/software'; import { useSoftStore } from '@/store/software';
import { GetOptions, getOptionsStringValue, SaveOptions } from '@/services/services/options/optionsTool'; import { GetOptions, getOptionsStringValue, SaveOptions } from '@/services/services/options/optionsTool';
import { OptionKeyName } from '@/services/enum/optionEnum'; import { AllOptionKeyName, OptionKeyName } from '@/services/enum/optionEnum';
interface ImageOptionsProps { interface ImageOptionsProps {
// Add your props here // Add your props here
@ -19,7 +19,7 @@ const ImageOptions: React.FC<ImageOptionsProps> = ({ visible }) => {
if (!visible) return; if (!visible) return;
setTopSpinning(true); setTopSpinning(true);
setTopSpinTip("加载信息中"); setTopSpinTip("加载信息中");
GetOptions("image").then((res) => { GetOptions(AllOptionKeyName.Image).then((res) => {
form.setFieldsValue({ form.setFieldsValue({
[OptionKeyName.LaitoolFluxApiModelList]: getOptionsStringValue(res, OptionKeyName.LaitoolFluxApiModelList, "{}"), [OptionKeyName.LaitoolFluxApiModelList]: getOptionsStringValue(res, OptionKeyName.LaitoolFluxApiModelList, "{}"),
}); });

View File

@ -1,3 +1,4 @@
import { AllOptionKeyName } from '@/services/enum/optionEnum';
import { GetOptions, getOptionsStringValue, SaveOptions } from '@/services/services/options/optionsTool'; import { GetOptions, getOptionsStringValue, SaveOptions } from '@/services/services/options/optionsTool';
import { useOptionsStore } from '@/store/options'; import { useOptionsStore } from '@/store/options';
import { useSoftStore } from '@/store/software'; import { useSoftStore } from '@/store/software';
@ -23,7 +24,7 @@ const SimpleOptions: React.FC<SimpleOptionsProps> = ({ visible }) => {
setTopSpinning(true); setTopSpinning(true);
setTopSpinTip("加载信息中"); setTopSpinTip("加载信息中");
// 这边加载所有的配音数据 // 这边加载所有的配音数据
GetOptions("software").then((res) => { GetOptions(AllOptionKeyName.Software).then((res) => {
setLaitoolOptions(res); setLaitoolOptions(res);
form.setFieldsValue({ form.setFieldsValue({
LaitoolHomePage: getOptionsStringValue(res, 'LaitoolHomePage', ""), LaitoolHomePage: getOptionsStringValue(res, 'LaitoolHomePage', ""),

View File

@ -1,3 +1,4 @@
import { AllOptionKeyName } from '@/services/enum/optionEnum';
import { GetOptions, getOptionsStringValue, SaveOptions } from '@/services/services/options/optionsTool'; import { GetOptions, getOptionsStringValue, SaveOptions } from '@/services/services/options/optionsTool';
import { useOptionsStore } from '@/store/options'; import { useOptionsStore } from '@/store/options';
import { useSoftStore } from '@/store/software'; import { useSoftStore } from '@/store/software';
@ -40,7 +41,7 @@ const DubSettingTTsOptions: React.FC<DubSettingTTsOptionsProps> = ({ visible })
setTopSpinning(true); setTopSpinning(true);
setTopSpinTip("加载信息中"); setTopSpinTip("加载信息中");
// 这边加载所有的配音数据 // 这边加载所有的配音数据
GetOptions('tts').then((res) => { GetOptions(AllOptionKeyName.TTS).then((res) => {
setTTsOptions(res); setTTsOptions(res);
form.setFieldsValue({ edgeTTsRoles: getOptionsStringValue(res, 'EdgeTTsRoles', "{}") }) form.setFieldsValue({ edgeTTsRoles: getOptionsStringValue(res, 'EdgeTTsRoles', "{}") })
} }

View File

@ -9,7 +9,6 @@ import BasicOptions from '../BasicOptions';
const LaitoolOptions: React.FC = () => { const LaitoolOptions: React.FC = () => {
const { initialState } = useModel('@@initialState'); const { initialState } = useModel('@@initialState');
const [tabKey, setTabKey] = React.useState<string | undefined>(undefined);
const items = [{ const items = [{
label: `软件设置`, label: `软件设置`,
@ -21,16 +20,12 @@ const LaitoolOptions: React.FC = () => {
key: "dub", key: "dub",
children: <DubSetting />, children: <DubSetting />,
style: undefined, style: undefined,
destroyInactiveTabPane : true destroyInactiveTabPane: true
}] }]
const onChange = (key: string) => {
setTabKey(key);
};
return ( return (
<TemplateContainer title={false} navTheme={initialState?.settings?.navTheme ?? "realDark"}> <TemplateContainer title={false} navTheme={initialState?.settings?.navTheme ?? "realDark"}>
<Tabs defaultActiveKey="1" destroyInactiveTabPane={true} items={items} onChange={onChange} /> <Tabs defaultActiveKey="1" destroyInactiveTabPane={true} items={items} />
</TemplateContainer> </TemplateContainer>
); );
}; };

View File

@ -0,0 +1,207 @@
import React, { useState, useEffect } from 'react';
import { Form, Input, Button, Card, message, Switch, Modal } from 'antd';
import { MailOutlined } from '@ant-design/icons';
import { useSoftStore } from '@/store/software';
import { GetOptions, getOptionsValue, GetSimpleOptions, SaveOptions } from '@/services/services/options/optionsTool';
import { AllOptionKeyName, OptionKeyName } from '@/services/enum/optionEnum';
import { request } from '@umijs/max';
interface MailSettingProps {
visible?: boolean;
}
interface MailConfig {
smtpServer: string;
port: number;
username: string;
password: string;
senderEmail: string;
enableSSL: boolean;
enableMailService: boolean;
testReceiveMail: string;
}
const MailSettingOption: React.FC<MailSettingProps> = ({ visible }) => {
const [form] = Form.useForm();
const { setTopSpinning, setTopSpinTip, topSpinning } = useSoftStore();
const [messageApi, messageHolder] = message.useMessage();
const [modalApi, modalHolder] = Modal.useModal();
useEffect(() => {
// Fetch current mail settings
fetchMailSettings();
}, [visible]);
const fetchMailSettings = async () => {
try {
setTopSpinTip("正在加载邮箱设置");
setTopSpinning(true);
const response = await GetOptions(AllOptionKeyName.MailSetting);
let mailSetting = getOptionsValue<MailConfig>(response, OptionKeyName.SMTPMailSetting, {
smtpServer: '',
port: 465,
username: '',
password: '',
senderEmail: '',
enableSSL: false,
enableMailService: false,
testReceiveMail: ''
});
form.setFieldsValue(mailSetting);
messageApi.success("数据加载成功!");
} catch (error: any) {
messageApi.error("数据加载失败!" + error.message);
} finally {
setTopSpinning(false);
}
};
const onFinish = async (values: MailConfig) => {
try {
setTopSpinTip("正在保存邮箱设置");
setTopSpinning(true);
console.log(values);
// Replace with actual API call
await SaveOptions({
[OptionKeyName.SMTPMailSetting]: JSON.stringify({
...values,
enableSSL: values.enableSSL ? true : false,
enableMailService: values.enableMailService ? true : false
}),
[OptionKeyName.EnableMailService]: values.enableMailService ? String(true) : String(false)
});
messageApi.success('Mail settings saved successfully');
} catch (error) {
messageApi.error('Failed to save mail settings');
} finally {
setTopSpinning(false);
}
};
const handleTestEmail = async () => {
try {
const confirmed = await modalApi.confirm({
title: '温馨提示',
content: '在执行词操作之前,请先保存邮件设置,否则无法发送测试邮件',
okText: '发送',
cancelText: '取消',
});
if (confirmed == false) {
return;
}
setTopSpinning(true);
setTopSpinTip('正在发送测试邮件');
let res = await request<ApiResponse.SuccessItem<string>>('/lms/LaitoolOptions/TestSendMail', {
method: 'POST',
});
if (res.code != 1) {
messageApi.error(res.message);
return;
}
messageApi.success('测试邮件发送成功,请查看收件箱');
} catch (error) {
messageApi.error('Failed to send test email');
} finally {
setTopSpinning(false);
}
};
return (
<Card title="邮箱设置" extra={<MailOutlined />}>
<Form
form={form}
layout="vertical"
onFinish={onFinish}
disabled={topSpinning}
>
<div style={{ display: 'flex', gap: '24px' }}>
<Form.Item
name="enableMailService"
valuePropName="checked"
label='开启/关闭邮箱服务'
>
<Switch checkedChildren="开启" unCheckedChildren="关闭" />
</Form.Item>
<Form.Item
name="enableSSL"
valuePropName="checked"
label='启用SMTP SSL'
>
<Switch checkedChildren="开启" unCheckedChildren="关闭" />
</Form.Item>
</div>
<Form.Item
name="smtpServer"
label="SMTP 服务器"
rules={[{ required: true, message: '请输入SMTP服务器' }]}
>
<Input placeholder="e.g. smtp.exmail.qq.com" />
</Form.Item>
<Form.Item
name="port"
label="发信端口号"
rules={[{ required: true, message: '请输入端口号' }]}
>
<Input type="number" placeholder="e.g. 465" />
</Form.Item>
<Form.Item
name="username"
label="发信用户名"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input placeholder="用户名" />
</Form.Item>
<Form.Item
name="password"
label="SMTP访问凭证"
rules={[{ required: true, message: '请输入SMTP访问凭证' }]}
>
<Input.Password placeholder="请输入SMTP访问凭证" />
</Form.Item>
<Form.Item
name="senderEmail"
label="发信邮箱"
rules={[
{ required: true, message: '请输入发送用户邮箱' },
{ type: 'email', message: '请输入发送用户邮箱' }
]}
>
<Input placeholder="e.g. noreply@example.com" />
</Form.Item>
<Form.Item
name="testReceiveMail"
label="测试收信邮箱"
rules={[
{ required: true, message: '请输入接收测试邮件的邮箱' },
{ type: 'email', message: '请输入接收测试邮件的邮箱' }
]}
>
<Input placeholder="e.g. test@example.com" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={topSpinning} style={{ marginRight: 16 }}>
</Button>
<Button onClick={handleTestEmail} loading={topSpinning}>
</Button>
</Form.Item>
</Form>
{messageHolder}
{modalHolder}
</Card>
);
};
export default MailSettingOption;

View File

@ -0,0 +1,31 @@
import TemplateContainer from '@/pages/TemplateContainer';
import { useModel } from '@umijs/max';
import { Tabs, TabsProps, theme } from 'antd';
import React from 'react';
import MailSettingOption from './MailSettingOption';
const LaitoolOptions: React.FC = () => {
const { initialState } = useModel('@@initialState');
const [activeKeys, setActiveKeys] = React.useState<string[]>([]);
const items = [{
label: `邮件设置`,
key: "mail",
style: undefined,
children: <MailSettingOption visible={activeKeys.includes('imageOptions')} />
}]
const onChange = (key: string | string[]) => {
setActiveKeys(Array.isArray(key) ? key : [key]);
};
return (
<TemplateContainer title={false} navTheme={initialState?.settings?.navTheme ?? "realDark"}>
<Tabs defaultActiveKey="1" destroyInactiveTabPane={true} items={items} onChange={onChange} />
</TemplateContainer>
);
};
export default LaitoolOptions;

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import TemplateContainer from '@/pages/TemplateContainer'; import TemplateContainer from '@/pages/TemplateContainer';
import { useModel } from '@umijs/max'; import { useAccess, useModel } from '@umijs/max';
import { Button, Dropdown, Form, Input, message, Modal, Select, Table, TableProps, Tag } from 'antd'; import { Button, Dropdown, Form, Input, message, Modal, Select, Table, TableProps, Tag } from 'antd';
import { FilterValue, SorterResult, TableCurrentDataSource, TablePaginationConfig } from 'antd/es/table/interface'; import { FilterValue, SorterResult, TableCurrentDataSource, TablePaginationConfig } from 'antd/es/table/interface';
import { Software, SoftwareControl } from '@/services/services/software'; import { Software, SoftwareControl } from '@/services/services/software';
@ -9,6 +9,7 @@ import moment from 'moment';
import { DeleteOutlined, EditOutlined, MenuOutlined, PlusSquareOutlined } from '@ant-design/icons'; import { DeleteOutlined, EditOutlined, MenuOutlined, PlusSquareOutlined } from '@ant-design/icons';
import { GetOptions, getOptionsStringValue } from '@/services/services/options/optionsTool'; import { GetOptions, getOptionsStringValue } from '@/services/services/options/optionsTool';
import { useSoftStore } from '@/store/software'; import { useSoftStore } from '@/store/software';
import { AllOptionKeyName } from '@/services/enum/optionEnum';
interface SoftwareControlManagementProps { interface SoftwareControlManagementProps {
@ -24,6 +25,7 @@ const SoftwareControlManagement: FC<SoftwareControlManagementProps> = () => {
const [softwareBasicInfo, setSoftwareBasicInfo] = useState<SoftwareModel.SoftwareBasicInfo[]>(); const [softwareBasicInfo, setSoftwareBasicInfo] = useState<SoftwareModel.SoftwareBasicInfo[]>();
const [softwareOptions, setSoftwareOptions] = useState<any>([]); const [softwareOptions, setSoftwareOptions] = useState<any>([]);
const [data, setData] = React.useState<SoftwareModel.SoftwareControlBase[]>([]); const [data, setData] = React.useState<SoftwareModel.SoftwareControlBase[]>([]);
const access = useAccess();
const [tableParams, setTableParams] = useState<TableModel.TableParams>({ const [tableParams, setTableParams] = useState<TableModel.TableParams>({
pagination: { pagination: {
current: 1, current: 1,
@ -99,6 +101,7 @@ const SoftwareControlManagement: FC<SoftwareControlManagementProps> = () => {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 100, width: 100,
hidden: !access.isAdminOrSuperAdmin,
render: (_, record) => ( render: (_, record) => (
<Dropdown <Dropdown
menu={{ menu={{
@ -218,7 +221,7 @@ const SoftwareControlManagement: FC<SoftwareControlManagementProps> = () => {
setTopSpinning(true); setTopSpinning(true);
setTopSpinTip("加载信息中"); setTopSpinTip("加载信息中");
let LaiToolTrialDays = 1; let LaiToolTrialDays = 1;
let res = await GetOptions("trial"); let res = await GetOptions(AllOptionKeyName.Trial);
days = Number(getOptionsStringValue(res, 'LaiToolTrialDays', "") || LaiToolTrialDays); days = Number(getOptionsStringValue(res, 'LaiToolTrialDays', "") || LaiToolTrialDays);
setTopSpinning(false); setTopSpinning(false);
} }

View File

@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Form, Input, Button, Spin, message } from 'antd'; import { Form, Input, Button, Spin, message, Row, Col } from 'antd';
import { UserRegistr } from '@/services/services/login'; import { UserRegistr } from '@/services/services/login';
import { set } from 'lodash'; import { history, request } from '@umijs/max';
import { history } from '@umijs/max';
const Register: React.FC = () => { const Register: React.FC = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [spinning, setSpinning] = useState(false); const [spinning, setSpinning] = useState(false);
const [messageApi, messageHolder] = message.useMessage(); const [messageApi, messageHolder] = message.useMessage();
const [countdown, setCountdown] = useState(0); // 倒计时状态
useEffect(() => { useEffect(() => {
// 检查当前网址是不是包含query并且?aff=后面有6位数字 // 检查当前网址是不是包含query并且?aff=后面有6位数字
@ -18,12 +18,59 @@ const Register: React.FC = () => {
} }
}, []); }, []);
// 发送邮箱验证码
const sendVerificationCode = async () => {
try {
debugger;
const email = form.getFieldsValue().email;
if (!email) {
messageApi.warning('请先填写邮箱');
return;
}
// 验证邮箱格式
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
messageApi.warning('请输入有效的邮箱格式');
return;
}
// 开始请求发送的接口
let res = await request<ApiResponse.SuccessItem<string>>(`/lms/User/SendVerificationCode`, {
method: 'POST',
data: { email }
});
if (res.code != 1) {
throw new Error(res.message);
}
// 设置倒计时
setCountdown(60);
const timer = setInterval(() => {
setCountdown((prevCountdown) => {
if (prevCountdown <= 1) {
clearInterval(timer);
return 0;
}
return prevCountdown - 1;
});
}, 1000);
messageApi.success('验证码已发送,请查收邮箱');
} catch (error: any) {
messageApi.error(error.message || '发送验证码失败');
} finally {
}
};
const onFinish = async (values: UserModel.UserRegisterParams) => { const onFinish = async (values: UserModel.UserRegisterParams) => {
// 判断两次密码是否一致 // 判断两次密码是否一致
if (values.password !== values.confirm) { if (values.password !== values.confirm) {
messageApi.warning('两次密码不一致!'); messageApi.warning('两次密码不一致!');
return; return;
} }
debugger
// 开始注册 // 开始注册
setSpinning(true); setSpinning(true);
@ -41,8 +88,6 @@ const Register: React.FC = () => {
finally { finally {
setSpinning(false); setSpinning(false);
} }
}; };
return ( return (
@ -80,6 +125,34 @@ const Register: React.FC = () => {
<Input placeholder='邮箱号' /> <Input placeholder='邮箱号' />
</Form.Item> </Form.Item>
<Form.Item
name="verificationCode"
rules={[{ required: true, message: '请输入邮箱验证码!' }]}
>
<Row gutter={8}>
<Col flex="auto">
<Input placeholder='邮箱验证码' />
</Col>
<Col>
<Button
type="primary"
onClick={sendVerificationCode}
disabled={countdown > 0}
style={{
width: '100px',
background: countdown > 0 ? '#f0f0f0' : '#1890ff',
borderColor: countdown > 0 ? '#d9d9d9' : '#1890ff',
color: countdown > 0 ? '#595959' : '#fff',
fontWeight: 500,
borderRadius: '4px',
}}
>
{countdown > 0 ? `${countdown}秒后重试` : '获取验证码'}
</Button>
</Col>
</Row>
</Form.Item>
<Form.Item <Form.Item
name="password" name="password"
rules={[ rules={[

View File

@ -2,12 +2,44 @@ export enum OptionType {
String = 1, String = 1,
JSON = 2, JSON = 2,
Number = 3, Number = 3,
Boolean = 4,
} }
export enum AllOptionKeyName {
/** 获取所有的 Option */
All = "all",
/** 获取TTS相关的 Option */
TTS = "tts",
/** 获取软件相关的 Option */
Software = "software",
/** 软件试用相关 Option */
Trial = "trial",
/** 出图相关的 Option */
Image = "image",
/** 邮件设置相关 Option */
MailSetting = "mailSetting",
}
export enum OptionKeyName { export enum OptionKeyName {
/** laitool Flux API 模型类型 */ /** laitool Flux API 模型类型 */
LaitoolFluxApiModelList = "LaitoolFluxApiModelList", LaitoolFluxApiModelList = "LaitoolFluxApiModelList",
/// <summary>
/// SMTP的邮件设置
/// </summary>
SMTPMailSetting = "SMTPMailSetting",
/// <summary>
/// 是否开启邮箱服务
/// </summary>
EnableMailService = "EnableMailService",
} }

View File

@ -129,7 +129,8 @@ export async function UserRegistr(params: UserModel.UserRegisterParams): Promise
email: params.email ?? '', email: params.email ?? '',
password: secPassword, password: secPassword,
tokenId: publicKey.token, tokenId: publicKey.token,
affiliateCode: params.affiliateCode affiliateCode: params.affiliateCode,
verificationCode: params.verificationCode
} }
let res = await request<ApiResponse.SuccessItem<string>>('/lms/User/Register', { let res = await request<ApiResponse.SuccessItem<string>>('/lms/User/Register', {
method: 'POST', method: 'POST',

View File

@ -1,4 +1,4 @@
import { OptionType } from "@/services/enum/optionEnum"; import { AllOptionKeyName, OptionKeyName, OptionType } from "@/services/enum/optionEnum";
import { isEmpty } from "lodash"; import { isEmpty } from "lodash";
/** /**
@ -32,6 +32,8 @@ export function getOptionsValue<T>(options: OptionModel.Option[], keyName: strin
return JSON.parse(option.value) as T; return JSON.parse(option.value) as T;
case OptionType.Number: case OptionType.Number:
return Number(option.value) as T; return Number(option.value) as T;
case OptionType.Boolean:
return Boolean(option.value as string) as T;
default: default:
throw new Error(`Unsupported option type: ${option.type}`); throw new Error(`Unsupported option type: ${option.type}`);
} }
@ -74,6 +76,8 @@ export function getOptionsStringValue(options: OptionModel.Option[], keyName: st
return String(option.value); return String(option.value);
case OptionType.Number: case OptionType.Number:
return String(Number(option.value)); return String(Number(option.value));
case OptionType.Boolean:
return String(Boolean(option.value));
default: default:
throw new Error(`Unsupported option type: ${option.type}`); throw new Error(`Unsupported option type: ${option.type}`);
} }
@ -88,11 +92,11 @@ export function getOptionsStringValue(options: OptionModel.Option[], keyName: st
import { request } from "@umijs/max"; import { request } from "@umijs/max";
/** /**
* TTS *
* @returns {Promise<OptionModel.Option[]>} OptionModel.Option Promise * @returns {Promise<OptionModel.Option[]>} OptionModel.Option Promise
* @throws {Error} 1 * @throws {Error} 1
*/ */
export async function GetOptions(optionsKey: string): Promise<OptionModel.Option[]> { export async function GetOptions(optionsKey: AllOptionKeyName): Promise<OptionModel.Option[]> {
let res = await request<ApiResponse.SuccessItem<OptionModel.Option[]>>(`/lms/LaitoolOptions/GetAllOptions/${optionsKey}`, { let res = await request<ApiResponse.SuccessItem<OptionModel.Option[]>>(`/lms/LaitoolOptions/GetAllOptions/${optionsKey}`, {
method: 'GET', method: 'GET',
headers: { headers: {
@ -105,6 +109,25 @@ export async function GetOptions(optionsKey: string): Promise<OptionModel.Option
return res.data; return res.data;
} }
/**
*
* @param optionsKey
* @returns
*/
export async function GetSimpleOptions(optionsKey: OptionKeyName): Promise<OptionModel.Option[]> {
debugger
let res = await request<ApiResponse.SuccessItem<OptionModel.Option[]>>(`/lms/LaitoolOptions/GetSimpleOptions/${optionsKey}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
});
if (res.code != 1) {
throw new Error(res.message);
}
return res.data;
}
/** /**
* *
* @param {string} key * @param {string} key
@ -113,7 +136,7 @@ export async function GetOptions(optionsKey: string): Promise<OptionModel.Option
* @throws {Error} 1 * @throws {Error} 1
*/ */
export async function SaveOptions(options: object): Promise<void> { export async function SaveOptions(options: object): Promise<void> {
debugger
let data: { key: string; value: any; }[] = []; let data: { key: string; value: any; }[] = [];
Object.entries(options).reduce((acc, [key, value]) => { Object.entries(options).reduce((acc, [key, value]) => {
data.push({ key: key, value: value.toString() }); data.push({ key: key, value: value.toString() });

View File

@ -21,8 +21,6 @@ declare namespace AccessType {
//#region 软件配置项操作权限 //#region 软件配置项操作权限
/** 是不是可以操作配置型 */ /** 是不是可以操作配置型 */
canOptions: boolean; canOptions: boolean;
/** 是不是可以操作软件配置项 */
canLaitoolOptions: boolean;
//#endregion //#endregion
//#region 机器权限 //#region 机器权限

View File

@ -13,6 +13,7 @@ declare namespace UserModel {
email?: string email?: string
confirm?: string confirm?: string
affiliateCode: string affiliateCode: string
verificationCode: string
} }
/** /**