申报人注册功能添加

master
zhc077 2 months ago
parent 33143e79fd
commit 76eea2db8a
  1. 16
      jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
  2. 100
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
  3. 7
      jeecgboot-vue3/src/api/sys/user.ts
  4. 6
      jeecgboot-vue3/src/locales/lang/en/sys.ts
  5. 8
      jeecgboot-vue3/src/locales/lang/zh-CN/sys.ts
  6. 4
      jeecgboot-vue3/src/views/system/loginmini/MiniLogin.vue
  7. 178
      jeecgboot-vue3/src/views/system/loginmini/MiniRegister.vue

@ -173,6 +173,21 @@ public class ShiroConfig {
// 企业微信证书排除
filterChainDefinitionMap.put("/WW_verify*", "anon");
filterChainDefinitionMap.put("/sys/sysDepart/queryDepartStuTreeSync", "anon"); //申报人部门注册接口排除
filterChainDefinitionMap.put("/sys/sysDepart/queryTreeStuList", "anon"); //申报人部门注册接口排除
filterChainDefinitionMap.put("/sys/user/userRegister4Shenbaoren", "anon");//申报人用户注册
filterChainDefinitionMap.put("/sys/sysDepart/queryDepartTreeSync", "anon");//申报人用户注册
// 添加自己的过滤器并且取名为jwt
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
//如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
@ -185,6 +200,7 @@ public class ShiroConfig {
// 未授权界面返回JSON
shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}

@ -25,6 +25,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.*;
@ -42,11 +43,13 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@ -105,6 +108,9 @@ public class SysUserController {
@Autowired
private JeecgRedisClient jeecgRedisClient;
@Resource
private JeecgBaseConfig jeecgBaseConfig;
/**
* 获取租户下用户数据支持租户隔离
* @param user
@ -1850,4 +1856,98 @@ public class SysUserController {
public Result<?> importAppUser(HttpServletRequest request, HttpServletResponse response)throws IOException {
return sysUserService.importAppUser(request);
}
/**
* 申报人注册接口
* @param jsonObject
* @param user
* @return
*/
@PostMapping("/userRegister4Shenbaoren")
public Result<JSONObject> userRegister4Shenbaoren(@RequestBody JSONObject jsonObject, SysUser user) {
Result<JSONObject> result = new Result<JSONObject>();
String phone = jsonObject.getString("phone");
String captcha = jsonObject.getString("smscode");
String departmentid = jsonObject.getString("departmentid");
String realname = jsonObject.getString("realname");
String checkKey = jsonObject.getString("checkKey");
String workon = jsonObject.getString("workno");
if(captcha==null){
result.error500("验证码无效");
return result;
}
String lowerCaseCaptcha = captcha.toLowerCase();
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
String origin = lowerCaseCaptcha+checkKey+jeecgBaseConfig.getSignatureSecret();
String realKey = Md5Util.md5Encode(origin, "utf-8");
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
Object checkCode = redisUtil.get(realKey);
//当进入登录页时,有一定几率出现验证码错误 #1714
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", checkKey, lowerCaseCaptcha, checkCode);
result.error500("验证码错误");
// 改成特殊的code 便于前端判断
result.setCode(HttpStatus.PRECONDITION_FAILED.value());
return result;
}
String username = jsonObject.getString("username");
//未设置用户名,则用手机号作为用户名
if(oConvertUtils.isEmpty(username)){
username = phone;
}
//未设置密码,则随机生成一个密码
String password = jsonObject.getString("password");
String email = jsonObject.getString("email");
SysUser sysUser1 = sysUserService.getUserByName(username);
if (sysUser1 != null) {
result.setMessage("用户名已注册");
result.setSuccess(false);
return result;
}
SysUser sysUser2 = sysUserService.getUserByPhone(phone);
if (sysUser2 != null) {
result.setMessage("该手机号已注册");
result.setSuccess(false);
return result;
}
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.in("work_no", workon);
List<SysUser> sysUser3 = sysUserService.list(queryWrapper);
if (sysUser3.size()>0) {
result.setMessage("该学号/工号已注册");
result.setSuccess(false);
return result;
}
if(oConvertUtils.isEmpty(realname)){
realname = username;
}
try {
user.setCreateTime(new Date());// 设置创建时间
String salt = oConvertUtils.randomGen(8);
String passwordEncode = PasswordUtil.encrypt(username, password, salt);
user.setSalt(salt);
user.setUsername(username);
user.setWorkNo(workon);
user.setRealname(realname);
user.setPassword(passwordEncode);
//user.setEmail(email);
user.setPhone(phone);
user.setStatus(CommonConstant.USER_UNFREEZE);
user.setDelFlag(CommonConstant.DEL_FLAG_0);
user.setActivitiSync(CommonConstant.ACT_SYNC_0);
sysUserService.addUserWithRole(user,"1724327596426760194");
sysUserService.addUserWithDepart(user,departmentid);
result.success("注册成功");
} catch (Exception e) {
result.error500("注册失败");
}
return result;
}
}

@ -27,6 +27,8 @@ enum Api {
getCaptcha = '/sys/sms',
//
registerApi = '/sys/user/register',
//
userRegister4Shenbaoren = '/sys/user/userRegister4Shenbaoren',
//
checkOnlyUser = '/sys/user/checkOnlyUser',
//SSO
@ -114,6 +116,11 @@ export function getCodeInfo(currdatetime) {
let url = Api.getInputCode + `/${currdatetime}`;
return defHttp.get({ url: url });
}
export function registerStu(params) {
return defHttp.post({url: Api.userRegister4Shenbaoren, params}, {isReturnNativeResponse: true});
}
/**
* @description: 获取短信验证码
*/

@ -92,6 +92,8 @@ export default {
mobileCorrectPlaceholder: 'Please input correct mobile',
policyPlaceholder: 'Register after checking',
diffPwd: 'The two passwords are inconsistent',
selectdep: 'Please select dep',
userName: 'Username',
password: 'Password',
@ -100,6 +102,10 @@ export default {
email: 'Email',
smsCode: 'SMS code',
mobile: 'Mobile',
realName: 'realname',
workNo: 'workno',
department: 'department',
//
authentication:'authentication',

@ -69,12 +69,14 @@ export default {
signInTitle: 'Jeecg Boot',
signInDesc: '是中国最具影响力的 企业级低代码平台!在线开发,可视化拖拽设计,零代码实现80%的基础功能~',
policy: '我同意敲敲云隐私政策',
policy: '我同意敲敲云隐私政策5',
scanSign: `扫码后,即可完成登录`,
scanSuccess: `扫码成功,登录中`,
loginButton: '登录',
registerButton: '注册',
registerButton4danwei: '单位注册',
registerButton4shenbaoren: '申报人注册',
rememberMe: '记住我',
forgetPassword: '忘记密码?',
otherSignIn: '其他登录方式',
@ -92,6 +94,7 @@ export default {
mobileCorrectPlaceholder: '请输入正确的手机号码',
policyPlaceholder: '勾选后才能注册',
diffPwd: '两次输入密码不一致',
selectdep: '请选择所属部门/单位',
userName: '账号',
password: '密码',
@ -100,6 +103,9 @@ export default {
email: '邮箱',
smsCode: '短信验证码',
mobile: '手机号码',
realName: '姓名',
workNo: '工号',
department: '部门/单位',
subTitleText: '{0}秒后返回登录页面',

@ -95,7 +95,11 @@
<a class="aui-linek-code aui-flex-box" @click="codeHandleClick">{{ t('sys.login.qrSignInFormTitle') }}</a>
</div>
<div class="aui-flex">
<!--
<a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton') }}</a>
-->
<a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton4danwei') }}</a>
<a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton4shenbaoren') }}</a>
</div>
</div>
</div>

@ -23,48 +23,93 @@
</a-form-item>
<a-form-item>
<div class="aui-input-line">
<Icon class="aui-icon" icon="ant-design:mobile-outlined"/>
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.mobile')" v-model:value="formData.mobile" />
<Icon class="aui-icon" icon="ant-design:mobile-outlined" />
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.realName')" v-model:value="formData.realname" />
</div>
</a-form-item>
<a-form-item>
<div class="aui-input-line">
<Icon class="aui-icon" icon="ant-design:mobile-outlined" />
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.workNo')" v-model:value="formData.workno" />
</div>
</a-form-item>
<!-- <a-form-item>-->
<!-- <div class="aui-input-line">-->
<!-- &lt;!&ndash; <Icon class="aui-icon" icon="ant-design:mobile-outlined" /> &ndash;&gt;-->
<!-- &lt;!&ndash; <a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.department')" />&ndash;&gt;-->
<!-- <JStuSelectDept v-model:value="formData.department" :multi="false" />-->
<!-- </div>-->
<!-- </a-form-item>-->
<a-form-item>
<div class="aui-input-line">
<JSelectDept v-model:value="formData.department" :multi="false" type="array" />
</div>
</a-form-item>
<a-form-item>
<div class="aui-input-line">
<Icon class="aui-icon" icon="ant-design:mobile-outlined" />
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.mobile')" v-model:value="formData.mobile" />
</div>
</a-form-item>
<!-- <a-form-item>
<div class="aui-input-line">
<Icon class="aui-icon" icon="ant-design:mail-outlined"/>
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.smsCode')" v-model:value="formData.smscode" />
<div v-if="showInterval" class="aui-code-line" @click="getLoginCode">{{t('component.countdown.normalText')}}</div>
<div v-else class="aui-code-line">{{t('component.countdown.sendText',[unref(timeRuning)])}}</div>
</div>
</a-form-item>
</a-form-item> -->
<a-form-item>
<div class="aui-input-line">
<Icon class="aui-icon" icon="ant-design:lock-outlined"/>
<a-input class="fix-auto-fill" :type="pwdIndex==='close'?'password':'text'" :placeholder="t('sys.login.password')" v-model:value="formData.password" />
<Icon class="aui-icon" icon="ant-design:lock-outlined" />
<a-input
class="fix-auto-fill"
:type="pwdIndex === 'close' ? 'password' : 'text'"
:placeholder="t('sys.login.password')"
v-model:value="formData.password"
/>
<div class="aui-eye">
<img :src="eyeKImg" alt="开启" v-if="pwdIndex==='open'" @click="pwdClick('close')" />
<img :src="eyeGImg" alt="关闭" v-else-if="pwdIndex==='close'" @click="pwdClick('open')" />
<img :src="eyeKImg" alt="开启" v-if="pwdIndex === 'open'" @click="pwdClick('close')" />
<img :src="eyeGImg" alt="关闭" v-else-if="pwdIndex === 'close'" @click="pwdClick('open')" />
</div>
</div>
</a-form-item>
<a-form-item>
<div class="aui-input-line">
<Icon class="aui-icon" icon="ant-design:lock-outlined"/>
<a-input class="fix-auto-fill" :type="confirmPwdIndex==='close'?'password':'text'" :placeholder="t('sys.login.confirmPassword')" v-model:value="formData.confirmPassword" />
<Icon class="aui-icon" icon="ant-design:lock-outlined" />
<a-input
class="fix-auto-fill"
:type="confirmPwdIndex === 'close' ? 'password' : 'text'"
:placeholder="t('sys.login.confirmPassword')"
v-model:value="formData.confirmPassword"
/>
<div class="aui-eye">
<img :src="eyeKImg" alt="开启" v-if="confirmPwdIndex==='open'" @click="confirmPwdClick('close')" />
<img :src="eyeGImg" alt="关闭" v-else-if="confirmPwdIndex==='close'" @click="confirmPwdClick('open')" />
<img :src="eyeKImg" alt="开启" v-if="confirmPwdIndex === 'open'" @click="confirmPwdClick('close')" />
<img :src="eyeGImg" alt="关闭" v-else-if="confirmPwdIndex === 'close'" @click="confirmPwdClick('open')" />
</div>
</div>
</a-form-item>
<a-form-item name="policy">
<div class="aui-flex">
<div class="aui-flex-box">
<div class="aui-choice">
<a-checkbox v-model:checked="formData.policy" />
<span style="color: #1b90ff;margin-left: 4px">{{ t('sys.login.policy') }}</span>
</div>
</div>
<div class="aui-inputClear">
<i class="icon icon-code"></i>
<a-form-item>
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.inputCode')" v-model:value="formData.smscode" />
</a-form-item>
<div class="aui-code">
<img v-if="randCodeData.requestCodeSuccess" :src="randCodeData.randCodeImage" @click="handleChangeCheckCode" />
<img v-else style="margin-top: 2px; max-width: initial" :src="codeImg" @click="handleChangeCheckCode" />
</div>
</a-form-item>
</div>
<!-- <a-form-item name="policy">
<div class="aui-flex">
<div class="aui-flex-box">
<div class="aui-choice">
<a-checkbox v-model:checked="formData.policy" />
<span style="color: #1b90ff;margin-left: 4px">{{ t('sys.login.policy') }}</span>
</div>
</div>
</div>
</a-form-item>-->
</div>
</div>
<div class="aui-formButton">
@ -81,23 +126,22 @@
</div>
</div>
</div>
<!-- 图片验证码弹窗 -->
<CaptchaModal @register="captchaRegisterModal" @ok="getLoginCode" />
</template>
<script lang="ts" setup name="mini-register">
import { ref, reactive, unref, toRaw } from 'vue';
import { getCaptcha, register } from '/@/api/sys/user';
import { ref, reactive, unref, toRaw,onMounted } from 'vue';
import { getCaptcha, registerStu, getCodeInfo } from '/@/api/sys/user';
import { SmsEnum } from '/@/views/sys/login/useLogin';
import { useMessage } from '/@/hooks/web/useMessage';
import logoImg from '/@/assets/loginmini/icon/jeecg_logo.png';
import jeecgAdTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png';
import eyeKImg from '/@/assets/loginmini/icon/icon-eye-k.png';
import eyeGImg from '/@/assets/loginmini/icon/icon-eye-g.png';
import { useI18n } from "/@/hooks/web/useI18n";
import CaptchaModal from '@/components/jeecg/captcha/CaptchaModal.vue';
import { useModal } from "@/components/Modal";
import { ExceptionEnum } from "@/enums/exceptionEnum";
import JStuSelectDept from '/@/components/Form/src/jeecg/components/JStuSelectDept.vue';
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
import { useI18n } from '/@/hooks/web/useI18n';
import codeImg from '/@/assets/images/checkcode.png';
const { t } = useI18n();
const { notification, createErrorModal, createMessage } = useMessage();
@ -105,12 +149,17 @@
const formRef = ref();
const formData = reactive<any>({
username: '',
workno: '',
mobile: '',
smscode: '',
password: '',
confirmPassword: '',
policy: false,
// policy: false,
realname: '',
department: '',
});
//
//
const showInterval = ref<boolean>(true);
//60s
@ -121,7 +170,6 @@
const pwdIndex = ref<string>('close');
//
const confirmPwdIndex = ref<string>('close');
const [captchaRegisterModal, { openModal: openCaptchaModal }] = useModal();
/**
* 返回
@ -130,7 +178,21 @@
emit('go-back');
initForm();
}
//
const randCodeData = reactive<any>({
randCodeImage: '',
requestCodeSuccess: false,
checkKey: null,
});
function handleChangeCheckCode() {
formData.inputCode = '';
randCodeData.checkKey = 1629428467008;
getCodeInfo(randCodeData.checkKey).then((res) => {
randCodeData.randCodeImage = res;
randCodeData.requestCodeSuccess = true;
});
}
/**
* 获取手机验证码
*/
@ -139,13 +201,7 @@
createMessage.warn(t('sys.login.mobilePlaceholder'));
return;
}
//update-begin---author:wangshuai---date:2024-04-18---for:QQYUN-9005IP15---
const result = await getCaptcha({ mobile: formData.mobile, smsmode: SmsEnum.REGISTER }).catch((res) =>{
if(res.code === ExceptionEnum.PHONE_SMS_FAIL_CODE){
openCaptchaModal(true, {});
}
});
//update-end---author:wangshuai---date:2024-04-18---for:QQYUN-9005IP15---
const result = await getCaptcha({ mobile: formData.mobile, smsmode: SmsEnum.REGISTER });
if (result) {
const TIME_COUNT = 60;
if (!unref(timer)) {
@ -169,18 +225,26 @@
createMessage.warn(t('sys.login.accountPlaceholder'));
return;
}
if (!formData.mobile) {
createMessage.warn(t('sys.login.mobilePlaceholder'));
if (!formData.realname) {
createMessage.warn(t('sys.login.realName'));
return;
}
if (!formData.smscode) {
createMessage.warn(t('sys.login.smsPlaceholder'));
if (!formData.department) {
createMessage.warn(t('sys.login.selectdep'));
return;
}
if (!formData.mobile) {
createMessage.warn(t('sys.login.mobilePlaceholder'));
return;
}
if (!formData.password) {
createMessage.warn(t('sys.login.passwordPlaceholder'));
return;
}
// if (!formData.workno) {
// createMessage.warn(t('sys.login.passwordPlaceholder'));
// return;
// }
if (!formData.confirmPassword) {
createMessage.warn(t('sys.login.confirmPassword'));
return;
@ -189,10 +253,14 @@
createMessage.warn(t('sys.login.diffPwd'));
return;
}
if(!formData.policy){
createMessage.warn(t('sys.login.policyPlaceholder'));
if (!formData.smscode) {
createMessage.warn(t('sys.login.smsPlaceholder'));
return;
}
// if (!formData.policy) {
// createMessage.warn(t('sys.login.policyPlaceholder'));
// return;
// }
registerAccount();
}
@ -201,12 +269,16 @@
*/
async function registerAccount() {
try {
const resultInfo = await register(
const resultInfo = await registerStu(
toRaw({
workno: formData.workno,
username: formData.username,
departmentid: formData.department,
realname: formData.realname,
password: formData.password,
phone: formData.mobile,
smscode: formData.smscode,
checkKey: randCodeData.checkKey,
})
);
if (resultInfo && resultInfo.data.success) {
@ -236,8 +308,8 @@
* 初始化表单
*/
function initForm() {
Object.assign(formData,{username:'',mobile: '', smscode: '', password: '', confirmPassword: '', policy: false})
if(!unref(timer)){
Object.assign(formData, { workno: '', username: '', mobile: '', realname: '', department: '', smscode: '', password: '', confirmPassword: ''/*, policy: false*/ });
if (!unref(timer)) {
showInterval.value = true;
clearInterval(unref(timer));
timer.value = null;
@ -260,15 +332,19 @@
function confirmPwdClick(value) {
confirmPwdIndex.value = value;
}
onMounted(() => {
//
handleChangeCheckCode();
});
defineExpose({
initForm
})
</script>
initForm,
});
</script>
<style lang="less" scoped>
@import '/@/assets/loginmini/style/home.less';
@import '/@/assets/loginmini/style/base.less';
.aui-input-line .aui-icon{
.aui-input-line .aui-icon {
position: absolute;
z-index: 2;
top: 10px;

Loading…
Cancel
Save