From bb45d484db8daa9b6633c892e110a8dc8844d6e8 Mon Sep 17 00:00:00 2001 From: vincentlu <t1341870251@gmail.com> Date: 星期一, 10 二月 2025 15:16:35 +0800 Subject: [PATCH] # --- rsf-framework/src/main/resources/templates/react-admin/ReactCreate.txt | 2 rsf-server/src/main/java/com/vincent/rsf/server/system/controller/param/TenantInitParam.java | 20 ++ rsf-admin/src/page/host/HostCreate.jsx | 2 rsf-admin/src/page/user/UserCreate.jsx | 2 rsf-admin/src/page/role/RoleCreate.jsx | 2 rsf-admin/src/page/config/ConfigCreate.jsx | 2 rsf-admin/src/themes/themes.jsx | 2 rsf-admin/src/i18n/zh.js | 17 + rsf-admin/src/i18n/en.js | 17 + rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java | 26 -- rsf-admin/src/page/tenant/TenantCreate.jsx | 400 ++++++++++++++++++++++++++++++++++++-------- rsf-server/src/main/java/com/vincent/rsf/server/system/controller/TenantController.java | 11 + 12 files changed, 401 insertions(+), 102 deletions(-) diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js index 0390e96..e356675 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -244,12 +244,29 @@ confirmNewPwd: 'Confirm Password', resetBtn: 'Reset', tip: { + usernameLimit: 'Only 3-20 English letters or numbers are allowed. No special characters.', pwdInputLimit: "New Password must be 6-13 characters long and include both letters and numbers.", pwdNotSameAsOld: "New Password cannot be the same as the Current Password.", pwdNotMatch: "New Password and Confirm Password do not match.", } } }, + tenant: { + create: { + title: { + basic: 'Basic Information', + root: 'Add Administrator', + confirm: 'Confirm', + }, + btn: { + next: 'Next Step', + back: 'Back Step', + }, + tip: { + onlyEn: 'Only 3-20 English letters are allowed.' + }, + }, + }, } }; diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index 60efdde..9490a9c 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -244,12 +244,29 @@ confirmNewPwd: '纭鏂板瘑鐮�', resetBtn: '閲嶇疆瀵嗙爜', tip: { + usernameLimit: '浠呭厑璁歌緭鍏� 3-20 涓嫳鏂囧瓧姣嶆垨鏁板瓧锛屼笉鑳藉寘鍚壒娈婂瓧绗�', pwdInputLimit: "瀵嗙爜蹇呴』涓�6-13浣�,涓斿繀椤诲寘鍚瓧姣嶅拰鏁板瓧", pwdNotSameAsOld: "鏂板瘑鐮佷笉鑳戒笌褰撳墠瀵嗙爜鐩稿悓", pwdNotMatch: "纭瀵嗙爜涓嶄竴鑷�", } } }, + tenant: { + create: { + title: { + basic: '鍩虹淇℃伅', + root: '娣诲姞绠$悊鍛�', + confirm: '纭', + }, + btn: { + next: '涓嬩竴姝�', + back: '涓婁竴姝�', + }, + tip: { + onlyEn: '浠呭厑璁歌緭鍏� 3-20 涓嫳鏂囧瓧姣�' + }, + }, + }, } }; diff --git a/rsf-admin/src/page/config/ConfigCreate.jsx b/rsf-admin/src/page/config/ConfigCreate.jsx index a3fe657..079e40e 100644 --- a/rsf-admin/src/page/config/ConfigCreate.jsx +++ b/rsf-admin/src/page/config/ConfigCreate.jsx @@ -79,7 +79,7 @@ <DialogCloseButton onClose={handleClose} /> </Box> </DialogTitle> - <DialogContent> + <DialogContent sx={{ mt: 2 }}> <Grid container rowSpacing={2} columnSpacing={2}> {/* <Grid item xs={6} display="flex" gap={1}> <TextInput diff --git a/rsf-admin/src/page/host/HostCreate.jsx b/rsf-admin/src/page/host/HostCreate.jsx index dbf0182..8061e95 100644 --- a/rsf-admin/src/page/host/HostCreate.jsx +++ b/rsf-admin/src/page/host/HostCreate.jsx @@ -80,7 +80,7 @@ <DialogCloseButton onClose={handleClose} /> </Box> </DialogTitle> - <DialogContent> + <DialogContent sx={{ mt: 2 }}> <Grid container rowSpacing={2} columnSpacing={2}> <Grid item xs={12} display="flex" gap={1}> <TextInput diff --git a/rsf-admin/src/page/role/RoleCreate.jsx b/rsf-admin/src/page/role/RoleCreate.jsx index dd2bce1..0ded77a 100644 --- a/rsf-admin/src/page/role/RoleCreate.jsx +++ b/rsf-admin/src/page/role/RoleCreate.jsx @@ -79,7 +79,7 @@ <DialogCloseButton onClose={handleClose} /> </Box> </DialogTitle> - <DialogContent> + <DialogContent sx={{ mt: 2 }}> <Grid container rowSpacing={2} columnSpacing={2}> <Grid item xs={6} display="flex" gap={1}> <TextInput diff --git a/rsf-admin/src/page/tenant/TenantCreate.jsx b/rsf-admin/src/page/tenant/TenantCreate.jsx index 37e3d05..4e0dea7 100644 --- a/rsf-admin/src/page/tenant/TenantCreate.jsx +++ b/rsf-admin/src/page/tenant/TenantCreate.jsx @@ -23,100 +23,354 @@ Stack, Grid, Box, + Stepper, + Step, + StepLabel, + StepContent, + Button, + TextField, + InputAdornment, + IconButton, } from '@mui/material'; +import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form"; +import { matchPath, useLocation } from 'react-router'; import DialogCloseButton from "../components/DialogCloseButton"; import StatusSelectInput from "../components/StatusSelectInput"; import MemoInput from "../components/MemoInput"; +import Visibility from '@mui/icons-material/Visibility'; +import VisibilityOff from '@mui/icons-material/VisibilityOff'; const TenantCreate = (props) => { const { open, setOpen } = props; - const translate = useTranslate(); const notify = useNotify(); + const { + control, + handleSubmit, + watch, + setValue, + getValues, + reset, + formState: { + errors, + isDirty, + }, + trigger + } = useForm(); + + const passwordVal = watch('password'); + + const [activeStep, setActiveStep] = useState(0); + const [showPassword, setShowPassword] = useState(false); + + const validateCurrentStep = async () => { + let fieldsToValidate = []; + if (activeStep === 0) { + fieldsToValidate = ['name', 'flag']; + } else if (activeStep === 1) { + fieldsToValidate = ['username', 'email', 'password', 'confirmPassword']; + } else if (activeStep === 2) { + fieldsToValidate = ['memo']; + } + return await trigger(fieldsToValidate); + }; + + const handleNext = async () => { + const isValid = await validateCurrentStep(); + if (!isValid) { + return; + } + setActiveStep(prev => prev + 1); + }; + + const handleBack = () => { + setActiveStep(prev => prev - 1); + }; const handleClose = (event, reason) => { if (reason !== "backdropClick") { + setActiveStep(0); setOpen(false); + reset(); } }; - const handleSuccess = async (data) => { - setOpen(false); - notify('common.response.success'); - }; + const onSubmit = (data) => { + console.log(data); + return; - const handleError = async (error) => { - notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } }); - }; + // setOpen(false); + reset(); + // notify('common.response.success'); + + // notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } }); + } return ( <> - <CreateBase - record={{}} - transform={(data) => { - return data; - }} - mutationOptions={{ onSuccess: handleSuccess, onError: handleError }} + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + fullWidth + disableRestoreFocus + maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' > - <Dialog - open={open} - onClose={handleClose} - aria-labelledby="form-dialog-title" - fullWidth - disableRestoreFocus - maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' - > - <Form> - <DialogTitle id="form-dialog-title" sx={{ - position: 'sticky', - top: 0, - backgroundColor: 'background.paper', - zIndex: 1000 - }} - > - {translate('create.title')} - <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> - <DialogCloseButton onClose={handleClose} /> - </Box> - </DialogTitle> - <DialogContent> - <Grid container rowSpacing={2} columnSpacing={2}> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.tenant.name" - source="name" - parse={v => v} - autoFocus - validate={required()} - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.tenant.flag" - source="flag" - parse={v => v} - autoFocus - validate={required()} - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <StatusSelectInput /> - </Grid> - <Grid item xs={12} display="flex" gap={1}> - <Stack direction="column" spacing={1} width={'100%'}> - <MemoInput /> - </Stack> - </Grid> - </Grid> - </DialogContent> - <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> - <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }} > - <SaveButton /> - </Toolbar> - </DialogActions> - </Form> - </Dialog> - </CreateBase> + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }}> + {translate('create.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + {open && ( + <form noValidate onSubmit={handleSubmit(onSubmit)} > + <Stepper activeStep={activeStep} orientation="vertical"> + <Step> + <StepLabel>{translate('page.tenant.create.title.basic')}</StepLabel> + <StepContent> + <Stack spacing={3} mt={2} direction='column' width={'50%'}> + <Controller + name="name" + control={control} + defaultValue="" + rules={{ required: true }} + parse={v => v} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('table.field.tenant.name')} + variant="outlined" + autoComplete="off" + error={!!error} + helperText={error ? translate('ra.validation.required') : ""} + /> + )} + /> + <Controller + name="flag" + control={control} + defaultValue="" + rules={{ + required: { + value: true, + message: translate('ra.validation.required') + }, + pattern: { + value: /^[A-Za-z]{3,20}$/, + message: translate('page.tenant.create.tip.onlyEn'), + } + }} + parse={v => v} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('table.field.tenant.flag')} + variant="outlined" + autoComplete="off" + error={!!error} + helperText={error ? error.message : ""} + /> + )} + /> + </Stack> + <Box sx={{ mt: 3 }}> + <Button onClick={handleNext} variant="contained"> + {translate('page.tenant.create.btn.next')} + </Button> + <Button disabled={activeStep === 0} onClick={handleBack}> + {translate('page.tenant.create.btn.back')} + </Button> + </Box> + </StepContent> + </Step> + + <Step> + <StepLabel>{translate('page.tenant.create.title.root')}</StepLabel> + <StepContent> + <Stack spacing={3} mt={2} direction='column' width={'50%'}> + <Controller + name="username" + control={control} + defaultValue="" + rules={{ + required: { + value: true, + message: translate('ra.validation.required') + }, + pattern: { + value: /^[A-Za-z0-9]{3,20}$/, + message: translate('page.settings.resetPwd.tip.usernameLimit'), + }, + }} + parse={v => v} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('table.field.user.username')} + variant="outlined" + autoComplete="off" + error={!!error} + helperText={error ? error.message : ""} + /> + )} + /> + <Controller + name="email" + control={control} + defaultValue="" + rules={{ + required: false, + pattern: { + value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, + message: translate("ra.validation.email"), + }, + }} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('table.field.user.email')} + variant="outlined" + autoComplete="off" + error={!!error} + helperText={error ? error.message : ""} + /> + )} + /> + <Controller + name="password" + control={control} + defaultValue="" + rules={{ + required: { + value: true, + message: translate('ra.validation.required'), + }, + pattern: { + value: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,13}$/, + message: translate('page.settings.resetPwd.tip.pwdInputLimit'), + }, + }} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('page.settings.resetPwd.newPwd')} + type={showPassword ? 'text' : 'password'} + variant="outlined" + autoComplete="off" + error={!!error} + helperText={error ? error.message : ""} + InputProps={{ + endAdornment: ( + <InputAdornment position="end"> + <IconButton + aria-label="toggle password visibility" + onClick={() => setShowPassword((show) => !show)} + onMouseDown={(event) => { event.preventDefault() }} + edge="end" + > + {showPassword ? <VisibilityOff /> : <Visibility />} + </IconButton> + </InputAdornment> + ), + }} + /> + )} + /> + <Controller + name="confirmPassword" + control={control} + defaultValue="" + rules={{ + required: translate('ra.validation.required'), + validate: value => + value === passwordVal || translate('page.settings.resetPwd.tip.pwdNotMatch'), + }} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('page.settings.resetPwd.confirmNewPwd')} + type={showPassword ? 'text' : 'password'} + variant="outlined" + autoComplete="off" + error={!!error} + helperText={error?.message || ""} + InputProps={{ + endAdornment: ( + <InputAdornment position="end"> + <IconButton + aria-label="toggle password visibility" + onClick={() => setShowPassword((show) => !show)} + onMouseDown={(event) => { event.preventDefault() }} + edge="end" + > + {showPassword ? <VisibilityOff /> : <Visibility />} + </IconButton> + </InputAdornment> + ), + }} + /> + )} + /> + </Stack> + <Box sx={{ mt: 3 }}> + <Button onClick={handleNext} variant="contained"> + {translate('page.tenant.create.btn.next')} + </Button> + <Button onClick={handleBack}> + {translate('page.tenant.create.btn.back')} + </Button> + </Box> + </StepContent> + </Step> + + <Step> + <StepLabel>{translate('page.tenant.create.title.confirm')}</StepLabel> + <StepContent> + <Stack spacing={3} mt={2} direction='column' width={'50%'}> + <Controller + name="memo" + control={control} + defaultValue="" + rules={{ required: false }} + parse={v => v} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('common.field.memo')} + variant="outlined" + autoComplete="off" + fullWidth + multiline + minRows={2} + error={!!error} + helperText={error ? translate('ra.validation.required') : ""} + /> + )} + /> + </Stack> + <Box sx={{ mt: 3 }}> + <Button type="submit" variant="contained"> + {translate('ra.action.save')} + </Button> + <Button onClick={handleBack}> + {translate('page.tenant.create.btn.back')} + </Button> + </Box> + </StepContent> + </Step> + </Stepper> + </form> + )} + </DialogContent> + <DialogActions sx={{ height: 10, position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + </DialogActions> + </Dialog> </> ) } diff --git a/rsf-admin/src/page/user/UserCreate.jsx b/rsf-admin/src/page/user/UserCreate.jsx index c0c9a04..c2d8e08 100644 --- a/rsf-admin/src/page/user/UserCreate.jsx +++ b/rsf-admin/src/page/user/UserCreate.jsx @@ -107,7 +107,7 @@ <DialogCloseButton onClose={handleClose} /> </Box> </DialogTitle> - <DialogContent> + <DialogContent sx={{ mt: 2 }}> <Grid container rowSpacing={2} columnSpacing={2}> <Grid item xs={6} display="flex" gap={1}> <TextInput diff --git a/rsf-admin/src/themes/themes.jsx b/rsf-admin/src/themes/themes.jsx index 05856c1..093fe0f 100644 --- a/rsf-admin/src/themes/themes.jsx +++ b/rsf-admin/src/themes/themes.jsx @@ -11,7 +11,6 @@ import { DEFAULT_THEME_NAME } from '@/config/setting'; import { softDarkTheme, softLightTheme } from './softTheme'; -import { chiptuneTheme } from './chiptuneTheme'; import { rsfLightTheme, rsfDarkTheme } from './rsfTheme'; export const themes = [ @@ -21,5 +20,4 @@ { name: 'nano', light: nanoLightTheme, dark: nanoDarkTheme }, // { name: 'radiant', light: radiantLightTheme, dark: radiantDarkTheme }, // { name: 'house', light: houseLightTheme, dark: houseDarkTheme }, - // { name: 'chiptune', light: chiptuneTheme }, ]; diff --git a/rsf-framework/src/main/resources/templates/react-admin/ReactCreate.txt b/rsf-framework/src/main/resources/templates/react-admin/ReactCreate.txt index d461fb6..9760184 100644 --- a/rsf-framework/src/main/resources/templates/react-admin/ReactCreate.txt +++ b/rsf-framework/src/main/resources/templates/react-admin/ReactCreate.txt @@ -82,7 +82,7 @@ <DialogCloseButton onClose={handleClose} /> </Box> </DialogTitle> - <DialogContent> + <DialogContent sx={{ mt: 2 }}> <Grid container rowSpacing={2} columnSpacing={2}> @{REACTCREATECONTENT} <Grid item xs={6} display="flex" gap={1}> diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java index 65fa3ef..60e6d14 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java @@ -11,11 +11,11 @@ public static void main(String[] args) throws Exception { ReactGenerator generator = new ReactGenerator(); - generator.backendPrefixPath = "zy-acs-manager/"; - generator.frontendPrefixPath = "zy-acs-flow/"; + generator.backendPrefixPath = "rsf-server/"; + generator.frontendPrefixPath = "rsf-admin/"; generator.sqlOsType = SqlOsType.MYSQL; - generator.url="localhost:3306/react_admin_dev"; + generator.url="localhost:3306/rsf"; generator.username="root"; generator.password="xltys1995"; // generator.url="47.97.1.152:51433;databasename=jkasrs"; @@ -46,22 +46,4 @@ */ } -/** - * - * TRUNCATE man_bus; - * TRUNCATE man_task; - * TRUNCATE man_travel; - * TRUNCATE man_segment; - * TRUNCATE man_jam; - * TRUNCATE man_action; - * - * TRUNCATE man_code; - * TRUNCATE man_code_gap; - * TRUNCATE man_route; - * - * TRUNCATE man_func_sta; - * TRUNCATE man_loc; - * TRUNCATE man_sta; - * TRUNCATE man_nav_map; - * - */ + diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/TenantController.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/TenantController.java index 8c0639d..ff30c51 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/TenantController.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/TenantController.java @@ -9,6 +9,7 @@ import com.vincent.rsf.server.common.domain.KeyValVo; import com.vincent.rsf.server.common.domain.PageParam; import com.vincent.rsf.server.common.utils.ExcelUtil; +import com.vincent.rsf.server.system.controller.param.TenantInitParam; import com.vincent.rsf.server.system.entity.Tenant; import com.vincent.rsf.server.system.service.TenantService; import org.springframework.beans.factory.annotation.Autowired; @@ -62,6 +63,16 @@ return R.ok("Save Success").add(tenant); } + @PreAuthorize("hasAuthority('system:tenant:save')") + @OperationLog("Init Tenant") + @PostMapping("/tenant/init") + public R init(@RequestBody TenantInitParam param) { + + + + return R.ok("Initialize Success"); + } + @PreAuthorize("hasAuthority('system:tenant:update')") @OperationLog("Update Tenant") @PostMapping("/tenant/update") diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/param/TenantInitParam.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/param/TenantInitParam.java new file mode 100644 index 0000000..af77d0a --- /dev/null +++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/param/TenantInitParam.java @@ -0,0 +1,20 @@ +package com.vincent.rsf.server.system.controller.param; + +import lombok.Data; + +@Data +public class TenantInitParam { + + private String name; + + private String flag; + + private String username; + + private String password; + + private String email; + + private String memo; + +} -- Gitblit v1.9.1