Merge remote-tracking branch 'origin/main'

# Conflicts:
#	ruoyi-ui/src/views/market/whole/index.vue
This commit is contained in:
Lenovo 2024-07-15 18:40:21 +08:00
commit 49cb9c82ba
23 changed files with 519 additions and 169 deletions

View File

@ -66,10 +66,9 @@ public class BusAgentInfoController extends BaseController {
public TableDataInfo list(BusAgentInfo busAgentInfo) {
startPage();
LoginUser user = SecurityUtils.getLoginUser();
// if(!"admin".equals(user.getUsername())){
// busAgentInfo.setSuperiorAgentCode(user.getUserId());
// }
busAgentInfo.setSuperiorAgentCode(user.getUserId());
if(!"admin".equals(user.getUsername())){
busAgentInfo.setSuperiorAgentCode(user.getUserId());
}
List<BusAgentInfo> list = busAgentInfoService.selectBusAgentInfoList(busAgentInfo);
List<BusAgentInfo> listData = list.stream().map(bean -> {
BusStoreInfo busStoreInfo = new BusStoreInfo();

View File

@ -109,7 +109,7 @@ public class BusStoreInfoController extends BaseController {
BusStoreInfo busStoreInfo = new BusStoreInfo();
BeanUtils.copyProperties(reqBusStoreInfo, busStoreInfo);
LoginUser user = SecurityUtils.getLoginUser();
if (!"OK777".equals(user.getUsername())||!"OK999".equals(user.getUsername())) {
if (!"OK777".equals(user.getUsername())) {
busStoreInfo.setBindUser(user.getUsername());
}
List<BusStoreInfo> list = busStoreInfoService.selectBusStoreInfoList(busStoreInfo);

View File

@ -62,6 +62,10 @@ public class ReqBusStoreConfigInfo {
@JsonFormat(shape = JsonFormat.Shape.STRING)
private int selfDeliveryDuration;
/** 营销限额 */
@ApiModelProperty(name = "营销限额开关")
private String quotaStatus;
/** 营销限额 */
@ApiModelProperty(name = "营销限额")
@JsonFormat(shape = JsonFormat.Shape.STRING)

View File

@ -1,28 +1,62 @@
package com.ruoyi.web.controller.common;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.service.ISmsService;
import com.ruoyi.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@Api("短信模块")
@RestController
@RequestMapping("/sms")
public class SmsController {
/**
* 短信验证码长度
*/
private final Integer LENGTH = 6;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysConfigService configService;
@Autowired
private ISmsService iSmsService;
@PostMapping("sendSms")
@ApiOperation("短信发送接口")
public R sendSms(@RequestPart String phone) {
iSmsService.sendSmsOne(phone);
return R.ok();
public AjaxResult sendSms(@RequestPart String phone) {
AjaxResult ajax = AjaxResult.success();
boolean captchaEnabled = configService.selectCaptchaEnabled();
ajax.put("captchaEnabled", captchaEnabled);
if (!captchaEnabled)
{
return ajax;
}
// 保存验证码信息
String uuid = IdUtils.simpleUUID();
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
String smsCode = generateCode();
redisCache.setCacheObject(verifyKey, smsCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
iSmsService.sendSmsOne(phone, smsCode);
ajax.put("uuid", uuid);
return ajax;
}
@PostMapping("validationCode")
@ -32,4 +66,13 @@ public class SmsController {
return R.ok(iSmsService.validationCode(phone, code));
}
/**
* 生成随机的验证码
*
* @return
*/
public String generateCode() {
return RandomStringUtils.randomNumeric(LENGTH);
}
}

View File

@ -51,6 +51,17 @@ public class SysLoginController
return ajax;
}
@PostMapping("/loginSms")
public AjaxResult loginSms(@RequestBody LoginBody loginBody)
{
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.loginSms(loginBody.getUsername(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* 获取用户信息
*

View File

@ -42,7 +42,7 @@ public class TestController extends BaseController
@ApiOperation("短信测试接口")
public R sendSMS() {
String phone = "17612400322";
iSmsService.sendSmsOne(phone);
iSmsService.sendSmsOne(phone, "123456");
return R.ok();
}

View File

@ -132,7 +132,7 @@ tencent:
cloud:
secretId: AKID48T2eHtniosmm0vz59CPZyUgzIlNGKV2
secretKey: bJuNk3B7tW1QqEXjg5faULJBwwpgMo8y
signName: 优势管家
signName: 优势管家
templateId: 2200612
smsSdkAppId: 1400921153
region: ap-beijing

View File

@ -4,6 +4,7 @@ user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误
phone.code.not.match=手机短信验证码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号已被删除

View File

@ -21,6 +21,33 @@ public class LoginBody
* 验证码
*/
private String code;
private String phone;
private String smsCode;
private String loginType;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getSmsCode() {
return smsCode;
}
public void setSmsCode(String smsCode) {
this.smsCode = smsCode;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
/**
* 唯一标识

View File

@ -111,11 +111,12 @@ public class SecurityConfig
.authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
requests.antMatchers("/login", "/register", "/captchaImage","/sms").permitAll()
requests.antMatchers("/login", "/register", "/captchaImage","/sendSms","/loginSms").permitAll()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
.antMatchers("/mt/cookies").permitAll()
.antMatchers("/test/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();

View File

@ -0,0 +1,39 @@
package com.ruoyi.framework.security.context;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
import java.util.Collection;
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
public SmsCodeAuthenticationToken(Object principal) {
super((Collection)null);
this.principal = principal;
this.setAuthenticated(false);
}
public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
public Object getCredentials() {
return null;
}
public Object getPrincipal() {
return this.principal;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
super.setAuthenticated(false);
}
}

View File

@ -1,6 +1,8 @@
package com.ruoyi.framework.web.service;
import javax.annotation.Resource;
import com.ruoyi.framework.security.context.SmsCodeAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
@ -100,6 +102,50 @@ public class SysLoginService
return tokenService.createToken(loginUser);
}
/**
* 登录验证
*
* @param phone 用户名
* @param smsCode 短信验证码
* @param uuid 唯一标识
* @return 结果
*/
public String loginSms(String phone, String smsCode, String uuid)
{
// 验证码校验
validateCaptcha(phone, smsCode, uuid);
// 用户验证
Authentication authentication = null;
try
{
SmsCodeAuthenticationToken authenticationToken = new SmsCodeAuthenticationToken(phone);
AuthenticationContextHolder.setContext(authenticationToken);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("phone.code.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
finally
{
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
}
/**
* 校验验证码
*

View File

@ -1,51 +1,51 @@
package com.ruoyi.quartz.task;
import com.ruoyi.business.service.IAiService;
import com.ruoyi.business.service.IMeituanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 定时任务调度测试
*
* @author ruoyi
*/
@Component("ryTask")
public class RyTask {
@Autowired
private IAiService aiService;
@Autowired
private IMeituanService iMeituanService;
/**
* 获取订单并解析号码 5分钟
*/
public void getOrders() {
iMeituanService.orderInfoList();
}
/**
* 发送AI 1分钟
*
* @throws Exception
*/
public void sendToAi() throws Exception {
aiService.sendToAi();
}
/**
* 获取AI结果 5分钟
*/
public void getAiResult() {
aiService.queryAiTask();
}
/**
* 统计昨日营销数 每天8点执行一次
*/
public void getReturnInfo() {
iMeituanService.getReturnInfo();
}
}
//package com.ruoyi.quartz.task;
//
//import com.ruoyi.business.service.IAiService;
//import com.ruoyi.business.service.IMeituanService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//
///**
// * 定时任务调度测试
// *
// * @author ruoyi
// */
//@Component("ryTask")
//public class RyTask {
// @Autowired
// private IAiService aiService;
// @Autowired
// private IMeituanService iMeituanService;
//
// /**
// * 获取订单并解析号码 5分钟
// */
// public void getOrders() {
// iMeituanService.orderInfoList();
// }
//
// /**
// * 发送AI 1分钟
// *
// * @throws Exception
// */
// public void sendToAi() throws Exception {
// aiService.sendToAi();
// }
//
// /**
// * 获取AI结果 5分钟
// */
// public void getAiResult() {
// aiService.queryAiTask();
// }
//
// /**
// * 统计昨日营销数 每天8点执行一次
// */
// public void getReturnInfo() {
// iMeituanService.getReturnInfo();
//
// }
//
//}

View File

@ -70,6 +70,10 @@ public class BusStoreConfigInfo extends BaseEntity
@Excel(name = "自配送营销时长")
private int selfDeliveryDuration;
/** 营销限额 */
@Excel(name = "营销限额开关")
private String quotaStatus;
/** 营销限额 */
@Excel(name = "营销限额")
private int quota;
@ -80,6 +84,14 @@ public class BusStoreConfigInfo extends BaseEntity
@Excel(name = "归属销售id")
private Long saleBindId;
public String getQuotaStatus() {
return quotaStatus;
}
public void setQuotaStatus(String quotaStatus) {
this.quotaStatus = quotaStatus;
}
public void setId(Long id)
{
this.id = id;
@ -248,6 +260,7 @@ public class BusStoreConfigInfo extends BaseEntity
.append("endTime", getEndTime())
.append("isSpliceOrder", getIsSpliceOrder())
.append("selfDeliveryDuration", getSelfDeliveryDuration())
.append("quotaStatus", getQuotaStatus())
.append("quota", getQuota())
.append("remark", getRemark())
.append("saleBindId", getSaleBindId())

View File

@ -331,6 +331,13 @@ public class AiServiceImpl implements IAiService {
content = busStoreConfigInfo.getContent4();
}
// 当日此店铺营销限额
if ("1".equals(busStoreConfigInfo.getQuotaStatus()) && busStoreConfigInfo.getQuota() != 0){
int quota = busReturnVisitInfoMapper.countByToday(storeInfo.getStoreCode());
if (quota >= busStoreConfigInfo.getQuota()) {
break;
}
}
//加入免运营订单-黑名单的 不营销跳出
BusBanOperateInfo busBanOperateInfo = new BusBanOperateInfo();
busBanOperateInfo.setBanOperateCode(busOrderInfo.getCustomId());
@ -339,13 +346,6 @@ public class AiServiceImpl implements IAiService {
if (list1.size() > 0) {
continue;
}
// 当日此店铺营销限额
if (busStoreConfigInfo.getQuota() != 0){
int quota = busReturnVisitInfoMapper.countByToday(storeInfo.getStoreCode());
if (quota >= busStoreConfigInfo.getQuota()) {
break;
}
}
// redisTemplate.opsForValue().set(busStoreConfigInfo.getStoreCode() + now.format(dateTimeFormatterNow), quota + "");
BusFifteenInfo fifteenInfo = new BusFifteenInfo();
fifteenInfo.setCustomId(busOrderInfo.getCustomId());

View File

@ -4,11 +4,6 @@ import com.tencentcloudapi.common.exception.TencentCloudSDKException;
public interface ISmsService {
/**
* 发送短信的验证码
* @return
*/
public String generateCode();
/**
* 发送短信的验证码
* @param phoneNumber
@ -30,5 +25,5 @@ public interface ISmsService {
* @param phone
* @return
*/
void sendSmsOne(String phone);
void sendSmsOne(String phone, String smsCode);
}

View File

@ -16,11 +16,6 @@ import java.util.Random;
@Service
public class SmsServiceImpl implements ISmsService {
/**
* 短信验证码长度
*/
private final Integer LENGTH = 6;
@Autowired
private TencentCloudProperties tencentCloudProperties;
/**
@ -45,15 +40,6 @@ public class SmsServiceImpl implements ISmsService {
return resp.getSendStatusSet()[0].getCode();
}
/**
* 生成随机的验证码
*
* @return
*/
public String generateCode() {
return RandomStringUtils.randomNumeric(LENGTH);
}
@Override
public Boolean validationCode(String phone, String code) {
final String data = (String) redisTemplate.opsForValue().get(phone);
@ -65,19 +51,18 @@ public class SmsServiceImpl implements ISmsService {
}
@Override
public void sendSmsOne(String phone) {
public void sendSmsOne(String phone, String smsCode) {
try {
/*验证手机号是否存在*/
if(false){
throw new ServiceException("手机号不存在,请联系管理员注册!");
}
String code = generateCode();
String[] phoneNumber = new String[]{phone};
String[] params = new String[]{code};
String[] params = new String[]{smsCode};
String status = sendSms(phoneNumber, params);
System.out.println(status + "sms code = "+code);
System.out.println(status + "sms code = "+smsCode);
if("Ok".equals(status)){
redisTemplate.opsForValue().set(phone, code);
redisTemplate.opsForValue().set(phone, smsCode);
}
} catch (TencentCloudSDKException e) {
throw new ServiceException(e.getMessage());

View File

@ -19,12 +19,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="isSpliceOrder" column="is_splice_order" />
<result property="selfDeliveryDuration" column="self_delivery_duration" />
<result property="quota" column="quota" />
<result property="quotaStatus" column="quota_status" />
<result property="remark" column="remark" />
<result property="saleBindId" column="sale_bind_id" />
</resultMap>
<sql id="selectBusStoreConfigInfoVo">
select id, store_code, store_name, content1, content2, content3, content4, min_order_num, max_order_num, start_time, end_time, is_splice_order, self_delivery_duration, quota, remark,sale_bind_id from bus_store_config_info
select id, store_code, store_name, content1, content2, content3, content4, min_order_num, max_order_num, start_time, end_time, is_splice_order, self_delivery_duration, quota, quota_status, remark,sale_bind_id from bus_store_config_info
</sql>
<select id="selectBusStoreConfigInfoList" parameterType="BusStoreConfigInfo" resultMap="BusStoreConfigInfoResult">
@ -77,6 +78,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="isSpliceOrder != null">is_splice_order,</if>
<if test="selfDeliveryDuration != null">self_delivery_duration,</if>
<if test="quota != null">quota,</if>
<if test="quotaStatus != null">quota_status,</if>
<if test="remark != null">remark,</if>
<if test="saleBindId != null">sale_bind_id,</if>
</trim>
@ -95,6 +97,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="isSpliceOrder != null">#{isSpliceOrder},</if>
<if test="selfDeliveryDuration != null">#{selfDeliveryDuration},</if>
<if test="quota != null">#{quota},</if>
<if test="quotaStatus != null">#{quotaStatus},</if>
<if test="remark != null">#{remark},</if>
<if test="saleBindId != null">#{saleBindId},</if>
</trim>
@ -116,6 +119,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="isSpliceOrder != null">is_splice_order = #{isSpliceOrder},</if>
<if test="selfDeliveryDuration != null">self_delivery_duration = #{selfDeliveryDuration},</if>
<if test="quota != null">quota = #{quota},</if>
<if test="quotaStatus != null">quota_status = #{quotaStatus},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="saleBindId != null">sale_bind_id = #{saleBindId},</if>
</trim>

View File

@ -58,3 +58,33 @@ export function getCodeImg() {
timeout: 20000
})
}
export function sendSms(data) {
return request({
url: '/sendSms',
headers: {
isToken: false
},
method: 'post',
data: data,
timeout: 20000
})
}
// 短信登录方法
export function loginSms(phone, smsCode, uuid) {
const data = {
phone,
smsCode,
uuid
}
return request({
url: '/loginSms',
headers: {
isToken: false,
repeatSubmit: false
},
method: 'post',
data: data
})
}

View File

@ -17,6 +17,14 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="上级代理" prop="superiorAgentAccount">
<el-input
v-model="queryParams.superiorAgentAccount"
placeholder="请输入上级代理账户"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -200,6 +208,7 @@ export default {
pageSize: 10,
agentAccount: null,
agentName: null,
superiorAgentAccount: null,
delStatus: "1"
},
//

View File

@ -1,59 +1,102 @@
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<div class="login-form">
<h3 class="title">优势后台管理系统</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
placeholder="账号"
>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<el-tabs type="card" :stretch=true>
<el-tab-pane label="账户密码登录" weith="50%">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules">
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
placeholder="账号"
>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="手机短信登录" weith="50%">
<el-form ref="loginForm2" :model="loginForm2" :rules="loginRules2">
<el-form-item prop="phone">
<el-input
v-model="loginForm2.phone"
type="text"
auto-complete="off"
placeholder="手机号码"
>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="smsCode">
<el-input
v-model="loginForm2.smsCode"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<!-- <el-input v-model="loginForm.code" autocomplete="off" style="width: 160px;"></el-input> -->
<el-button :disabled="countdown > 0" @click="sendCode"
style="width: 37%">{{ countdown > 0 ? `${countdown}s后重新发送` : '获取验证码' }}</el-button>
</el-form-item>
<el-form-item>
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click="submitForm">登录</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2024 youshi.bj.cn All Rights Reserved.</span>
@ -73,11 +116,19 @@ export default {
codeUrl: "",
loginForm: {
username: "admin",
password: "admin123",
password: "",
rememberMe: false,
code: "",
uuid: ""
uuid: "",
phone:"",
smsCode: ""
},
loginForm2: {
phone:"",
smsCode: "",
loginType: 'sms'
},
countdown: 0,
loginRules: {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" }
@ -87,6 +138,12 @@ export default {
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
loginRules2: {
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
]
},
loading: false,
//
captchaEnabled: true,
@ -117,6 +174,40 @@ export default {
}
});
},
sendCode() {
//
this.$refs.loginForm2.validate(valid => {
if (valid) {
console.log('发送验证码到手机:', this.loginForm.phone);
this.countdown = 60; // 60
this.intervalId = setInterval(() => {
if (this.countdown > 0) {
this.countdown -= 1;
} else {
clearInterval(this.intervalId);
}
}, 1000);
alert('提交成功!');
} else {
console.log('验证失败!');
return false;
}
}
);
},
submitForm() {
//
console.log('提交登录信息:', this.loginForm2);
if(this.loginForm2.smsCode==""||this.loginForm2.smsCode.length!=6){
this.$modal.msgError("请输入短信验证码");
}
//
this.$refs.loginForm2.validate((valid) => {
if (valid) {
//
}
});
},
getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");

View File

@ -175,6 +175,7 @@
<el-table-column label="是否开启" prop="returnVisitStatus" align="center" width="85" >
<template slot-scope="scope">
<el-switch
:disabled="isDisabled"
v-model="scope.row.returnVisitStatus"
active-value="1"
inactive-value="2"
@ -185,13 +186,13 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width =120>
<template slot-scope="scope">
<el-button v-if="scope.row.returnVisitStatus !== 1"
<el-button v-if="userAccount !='OK777' && scope.row.returnVisitStatus !== '1'"
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>配置</el-button>
<el-button v-if="scope.row.returnVisitStatus !== 1"
<el-button v-if="userAccount !='OK777' && scope.row.returnVisitStatus !== '1'"
size="mini"
type="text"
icon="el-icon-delete"
@ -304,9 +305,22 @@
</el-form-item>
<el-form-item label="营销时长" prop="selfDeliveryDuration">
<el-input-number v-model="form.selfDeliveryDuration" controls-position="right" :min="0" />
<el-tooltip effect="dark" placement="right">
<div slot="content">功能说明营销时长<br/>设定自配送无送达时间状态的订单营销时长单位是分钟顾客下单多少分钟后开始营销</div>
<i class="el-tooltip el-icon-question" tabindex="0" ></i>
</el-tooltip>
</el-form-item>
<el-form-item label="营销限额" prop="quota">
<el-input-number v-model="form.quota" controls-position="right" :min="0" />
<el-radio-group v-model="form.quotaStatus" @change="changeQuotaStatus">
<el-radio
v-for="dict in dict.type.sys_return_visit_status"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item lable="(每日)">
<el-input-number :disabled="isDisabledQuotaStatus" v-model="form.quota" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="是否拼好饭">
<el-radio-group v-model="form.isSpliceOrder">
@ -377,6 +391,9 @@ export default {
open: false,
//
openDataScope: false,
userAccount: undefined,
isDisabled: false,
isDisabledQuotaStatus: false,
map: {
storeCount: 0,
openCount: 0,
@ -399,7 +416,7 @@ export default {
saleList: [],
timeRange: undefined,
//
form: {},
form: {quotaStatus:'1'},
defaultProps: {
children: "children",
label: "label"
@ -435,6 +452,10 @@ export default {
};
},
created() {
this.userAccount = this.$store.state.user.name;
if(this.$store.state.user.name == 'OK777'){
this.isDisabled = true;
}
this.getListSale();
this.getList();
this.storeStatistics();
@ -455,6 +476,13 @@ export default {
column.label
]
},
changeQuotaStatus(){
if(this.form.quotaStatus == '2'){
this.isDisabledQuotaStatus = true
}else if(this.form.quotaStatus == '1'){
this.isDisabledQuotaStatus = false
}
},
/** 查询角色列表 */
getList() {
this.loading = true;

View File

@ -147,20 +147,20 @@
@click="handleExport"
>导出</el-button>
</el-col>
<el-col :span="1.5"><el-button size="mini" >当前账分{{nowIntegral}}</el-button></el-col>
<el-col :span="1.5" class="top-right-btn"><el-button size="mini" type="error">当前账分{{nowIntegral}}</el-button></el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="storeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" type="index" ></el-table-column>
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="序号" type="index" width="50" />
<el-table-column label="平台" prop="platformType" width="55">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_platform_type" :value="scope.row.platformType"/>
</template>
</el-table-column>
<el-table-column label="编号" prop="storeCode" :show-overflow-tooltip="true" width="55" align="center" />
<el-table-column label="名称" prop="storeName" :show-overflow-tooltip="true" align="center" />
<el-table-column label="编号" prop="storeCode" width="85" align="center" />
<el-table-column label="名称" prop="storeName" align="center" />
<el-table-column label="在线状态" prop ="grantStatus" align="center" width="75" >
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_grant_status" :value="scope.row.grantStatus"/>
@ -173,8 +173,8 @@
<el-table-column label="昨日营销比(%)" prop="lastReturnVisitRate" align="center" :render-header="renderPrice" width="120" />
<el-table-column label="今日回访量" prop="todayReturnVisitNum" align="center" width="85" />
<el-table-column label="评分" prop="score" align="center" width="55" />
<el-table-column label="归属" prop="saleBindId" align="center" :formatter="idToName" width="65" />
<el-table-column label="创建时间" align="center" prop="bindTime" width="160">
<el-table-column label="归属" prop="saleBindId" align="center" :formatter="idToName" width="75" />
<el-table-column label="创建时间" align="center" prop="bindTime" width="150">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.bindTime) }}</span>
</template>
@ -183,6 +183,7 @@
<el-table-column label="是否开启" prop="returnVisitStatus" align="center" width="85" >
<template slot-scope="scope">
<el-switch
:disabled="isDisabled"
v-model="scope.row.returnVisitStatus"
active-value="1"
inactive-value="2"
@ -193,19 +194,19 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width =120>
<template slot-scope="scope">
<el-button v-if="scope.row.returnVisitStatus !== 1"
<el-button v-if="userAccount !='OK777' && scope.row.returnVisitStatus !== '1'"
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>配置</el-button>
<el-button v-if="scope.row.selfDeliveryStatus == 1 && scope.row.returnVisitStatus !== 1"
<el-button v-if="userAccount !='OK777' && scope.row.selfDeliveryStatus == '1' && scope.row.returnVisitStatus !== '1'"
size="mini"
type="text"
icon="el-icon-bicycle"
@click="handleSelfDelivery(scope.row)"
>自配送</el-button>
<el-button v-if="scope.row.returnVisitStatus !== 1"
<el-button v-if="userAccount !='OK777' && scope.row.returnVisitStatus !== '1'"
size="mini"
type="text"
icon="el-icon-delete"
@ -338,7 +339,16 @@
<el-input-number v-model="form.selfDeliveryDuration" controls-position="right" :min="0" />
</el-form-item> -->
<el-form-item label="营销限额" prop="quota">
<el-input-number v-model="form.quota" controls-position="right" :min="0" />
<el-radio-group v-model="form.quotaStatus" @change="changeQuotaStatus">
<el-radio
v-for="dict in dict.type.sys_return_visit_status"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item lable="(每日)">
<el-input-number :disabled="isDisabledQuotaStatus" v-model="form.quota" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="是否拼好饭">
<el-radio-group v-model="form.isSpliceOrder">
@ -440,6 +450,9 @@ export default {
noGrantCount: 0
},
userAccount: undefined,
isDisabled: false,
isDisabledQuotaStatus: false,
//
queryParams: {
pageNum: 1,
@ -459,10 +472,10 @@ export default {
expEndTime: undefined
},
saleList: [],
timeRange: undefined,
timeRange: ['00:00:00','23:59:59'],
timeRange1: undefined,
//
form: {},
form: {quotaStatus:'1'},
form1: {},
defaultProps: {
children: "children",
@ -489,6 +502,10 @@ export default {
};
},
created() {
this.userAccount = this.$store.state.user.name;
if(this.$store.state.user.name == 'OK777'){
this.isDisabled = true;
}
this.getListSale();
this.getList();
this.storeStatistics();
@ -510,6 +527,13 @@ export default {
column.label
]
},
changeQuotaStatus(){
if(this.form.quotaStatus == '2'){
this.isDisabledQuotaStatus = true
}else if(this.form.quotaStatus == '1'){
this.isDisabledQuotaStatus = false
}
},
/** 查询角色列表 */
getList() {
this.loading = true;