完成前端加密
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
cd target
|
||||
scp bill-1.0.0-SNAPSHOT.jar gc:/tmp
|
||||
ssh gc "sudo cp /tmp/bill-1.0.0-SNAPSHOT.jar /home/bill/service ; sudo . /home/bill/service/run.sh"
|
||||
@@ -8,7 +8,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.alawn</groupId>
|
||||
<artifactId>bill</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>bill</name>
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
<!-- <artifactId>jjwt</artifactId>-->
|
||||
<!-- <version>0.9.1</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
@@ -201,6 +206,10 @@
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env sh
|
||||
pid=`ps -ef | grep bill| grep java | awk '{print $2}'`
|
||||
|
||||
if [ $pid ]; then
|
||||
echo $pid
|
||||
kill -9 $pid
|
||||
fi
|
||||
|
||||
> nohup.out
|
||||
|
||||
nohup java -jar target/bill-1.0.0-SNAPSHOT.jar 2>/dev/null &
|
||||
@@ -1,7 +1,9 @@
|
||||
package net.alawn.bill.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.alawn.bill.security.JwtAuthenticationEntryPoint;
|
||||
import net.alawn.bill.security.JwtAuthenticationTokenFilter;
|
||||
import net.alawn.bill.util.AesEncryptUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -34,6 +36,8 @@ import java.util.Arrays;
|
||||
* @Description:
|
||||
* @Date: Create in 16:53 2019-05-17
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@@ -70,6 +74,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
/** 装载BCrypt密码编码器 */
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
log.info("passwordEncoder()");
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@@ -154,12 +159,18 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
//对密码进行加密
|
||||
@Override
|
||||
public String encode(CharSequence charSequence) {
|
||||
System.out.println(charSequence.toString());
|
||||
log.info("encode password:" + charSequence.toString());
|
||||
// String password = AesEncryptUtil.decrypt(charSequence.toString());
|
||||
// return DigestUtils.md5DigestAsHex(password.getBytes());
|
||||
return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
|
||||
}
|
||||
//对密码进行判断匹配
|
||||
@Override
|
||||
public boolean matches(CharSequence charSequence, String s) {
|
||||
log.info("matches passwordRaw :" + charSequence.toString());
|
||||
log.info("matches passwordDb:" + charSequence.toString());
|
||||
// String password = AesEncryptUtil.decrypt(charSequence.toString());
|
||||
// String encode = DigestUtils.md5DigestAsHex(password.getBytes());
|
||||
String encode = DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
|
||||
boolean res = s.equals( encode );
|
||||
return res;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class BasicController {
|
||||
|
||||
@RequestMapping(value = "/posts",method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Post> addPost(@RequestBody NewPost newPost, Principal principal) throws URISyntaxException {
|
||||
public ResponseEntity<Post> addPost(@RequestBody NewPost newPost) {
|
||||
AuthUser authUser = (AuthUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
long userId = authUser.getId();
|
||||
|
||||
@@ -90,7 +90,7 @@ public class BasicController {
|
||||
|
||||
@RequestMapping(value = "/merchants",method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Merchant> addMerchant(@RequestBody NewMerchant newMerchant) throws URISyntaxException {
|
||||
public ResponseEntity<Merchant> addMerchant(@RequestBody NewMerchant newMerchant) {
|
||||
/** 登记 Post */
|
||||
Merchant merchant = merchantRepo.save(newMerchant.build());
|
||||
merchantRepo.flush();
|
||||
@@ -99,7 +99,7 @@ public class BasicController {
|
||||
|
||||
@RequestMapping(value = "/merchants",method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<Merchant>> fetchMerchants() throws URISyntaxException {
|
||||
public ResponseEntity<List<Merchant>> fetchMerchants() {
|
||||
List<Merchant> merchants = merchantRepo.findAll();
|
||||
return ResponseEntity.ok(merchants);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.alawn.bill.entity.po;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.*;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@Entity
|
||||
@Table(name = "t_bill_premission")
|
||||
@ToString(exclude = {"user"})
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" },ignoreUnknown = true)
|
||||
@DynamicUpdate
|
||||
public class Premission extends EntityId{
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
// @JoinColumn(name = "userId", referencedColumnName = "id")
|
||||
@JoinColumn(name = "userId", referencedColumnName = "id")
|
||||
// @MapsId("username")
|
||||
@MapsId("id")
|
||||
private User user;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || o instanceof Premission
|
||||
&& id != null
|
||||
&& id.equals(((Premission) o).id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ public enum RespMsg {
|
||||
NO_DATA ( "200017", RespMsgConstants.NO_DATA ) ,
|
||||
USER_ALREADY_EXIST ( "200018", RespMsgConstants.USER_ALREADY_EXIST ) ,
|
||||
USER_NOT_EXIST_OR_PASSWORD_INCORRECT ( "200019", RespMsgConstants.USER_NOT_EXIST_OR_PASSWORD_INCORRECT ) ,
|
||||
USERNAME_OR_PASSWORD_IS_EMPTY ( "200020", RespMsgConstants.USERNAME_OR_PASSWORD_IS_EMPTY ) ,
|
||||
SUCCESS ( "000000", RespMsgConstants.SUCCESS ) ;
|
||||
|
||||
|
||||
|
||||
@@ -7,22 +7,23 @@ package net.alawn.bill.exception;
|
||||
*/
|
||||
public final class RespMsgConstants {
|
||||
|
||||
public final static String NO_STORAGE_FOUND = "没有发现存储" ;
|
||||
public final static String NO_STORAGE_FOUND = "没有发现存储" ;
|
||||
public final static String BLOB_DUPLICATE = "发现重复Blob" ;
|
||||
public final static String BLOB_NOT_EXIST = "Blob对象不存在" ;
|
||||
public final static String NO_BLOB_FOUND = "Blob对象不存在" ;
|
||||
public final static String BLOB_NOT_EXIST = "Blob对象不存在" ;
|
||||
public final static String NO_BLOB_FOUND = "Blob对象不存在" ;
|
||||
public final static String BUCKET_DUPLICATE = "发现重复Bucket" ;
|
||||
public final static String FILE_HANDLING = "文件处理异常" ;
|
||||
public final static String FILE_NOT_EXIST = "文件不存在" ;
|
||||
public final static String FILE_OCCUPIED = "文件/文件夹已被占用" ;
|
||||
public final static String NO_ACCESS_PERMISSION = "没有该访问权限" ;
|
||||
public final static String FILE_HANDLING = "文件处理异常" ;
|
||||
public final static String FILE_NOT_EXIST = "文件不存在" ;
|
||||
public final static String FILE_OCCUPIED = "文件/文件夹已被占用" ;
|
||||
public final static String NO_ACCESS_PERMISSION = "没有该访问权限" ;
|
||||
public final static String NO_BUCKET_FOUND = "没有找到Bucket" ;
|
||||
public final static String NO_DEFAULT_BUCKET = "没有找到默认Bucket" ;
|
||||
public final static String NO_DEFAULT_BUCKET = "没有找到默认Bucket" ;
|
||||
public final static String NO_DEFAULT_STORAGE = "没有找到默认存储设备" ;
|
||||
public final static String REQUEST_PARAMS = "请求参数有误" ;
|
||||
public final static String INTERNAL_ERROR = "内部错误" ;
|
||||
public final static String NO_DATA = "没有数据" ;
|
||||
public final static String USER_ALREADY_EXIST = "用户已存在" ;
|
||||
public final static String USER_NOT_EXIST_OR_PASSWORD_INCORRECT = "用户不存在或密码不正确" ;
|
||||
public final static String USERNAME_OR_PASSWORD_IS_EMPTY = "用户名或密码不得为空" ;
|
||||
public final static String SUCCESS = "业务成功" ;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@ import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
*/
|
||||
public interface AuthService {
|
||||
NewUser register(NewUser userDTO) throws HttpRequestMethodNotSupportedException, AuthenticationException;
|
||||
String login(String username, String password);
|
||||
String login(String username, String password) throws AuthenticationException;
|
||||
String refresh(String oldToken);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.alawn.bill.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.alawn.bill.entity.dto.NewUser;
|
||||
import net.alawn.bill.entity.po.Authority;
|
||||
import net.alawn.bill.entity.po.AuthorityId;
|
||||
@@ -11,6 +12,7 @@ import net.alawn.bill.repository.UserRepo;
|
||||
import net.alawn.bill.security.AuthUser;
|
||||
import net.alawn.bill.security.JwtTokenUtil;
|
||||
import net.alawn.bill.service.AuthService;
|
||||
import net.alawn.bill.util.AesEncryptUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -23,6 +25,7 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -31,6 +34,7 @@ import org.springframework.stereotype.Service;
|
||||
* @Date: Create in 15:59 2019-05-20
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
//@AllArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
@@ -62,6 +66,8 @@ public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Override
|
||||
public NewUser register(NewUser userDTO) throws AuthenticationException {
|
||||
log.info("AuthServiceImpl.register start");
|
||||
log.info("userDTO:" + userDTO);
|
||||
final String username = userDTO.getUsername();
|
||||
|
||||
if(userRepo.findByUsername(username) != null) {
|
||||
@@ -69,10 +75,14 @@ public class AuthServiceImpl implements AuthService {
|
||||
}
|
||||
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
final String rawPassword = userDTO.getPassword();
|
||||
|
||||
// final String rawPassword = userDTO.getPassword();
|
||||
final String password = AesEncryptUtil.decrypt(userDTO.getPassword());
|
||||
|
||||
User user = User.builder()
|
||||
.username(username)
|
||||
.password(encoder.encode(rawPassword)).build();
|
||||
.password(encoder.encode(password)).build();
|
||||
// .password(userDTO.getPassword()).build();
|
||||
User saved = userRepo.save(user);
|
||||
Authority savedAuth = authorityRepo.save(
|
||||
Authority.builder()
|
||||
@@ -90,11 +100,26 @@ public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Override
|
||||
public String login(String username, String password) {
|
||||
// public String login(String username, String passwordAES) {
|
||||
|
||||
/** 为空检查*/
|
||||
// if(StringUtils.isEmpty(username) || StringUtils.isEmpty(passwordAES)) {
|
||||
// throw new CommonException(RespMsg.USER_NOT_EXIST_OR_PASSWORD_INCORRECT);
|
||||
// }
|
||||
|
||||
// BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
password = AesEncryptUtil.decrypt(password);
|
||||
|
||||
UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||
final Authentication authentication = authenticationManager.authenticate(upToken);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
// if(!encoder.matches(password,userDetails.getPassword())) {
|
||||
// throw new CommonException(RespMsg.USER_NOT_EXIST_OR_PASSWORD_INCORRECT);
|
||||
// }
|
||||
|
||||
final String token = jwtTokenUtil.generateToken(userDetails);
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package net.alawn.bill.util;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @Author: Alawn
|
||||
* @Description:
|
||||
* @Date: Create in 17:27 2019-06-11
|
||||
*/
|
||||
public class AesEncryptUtil {
|
||||
|
||||
private static String iv = "0123456789ABCDEF";//偏移量字符串必须是16位 当模式是CBC的时候必须设置偏移量
|
||||
private static String Algorithm = "AES";
|
||||
private static String AlgorithmProvider = "AES/CBC/PKCS5Padding"; //算法/模式/补码方式
|
||||
|
||||
public static byte[] generatorKey() throws NoSuchAlgorithmException {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(Algorithm);
|
||||
keyGenerator.init(256);//默认128,获得无政策权限后可为192或256
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
return secretKey.getEncoded();
|
||||
}
|
||||
|
||||
public static IvParameterSpec getIv() throws UnsupportedEncodingException {
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
|
||||
return ivParameterSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
* @param src
|
||||
* @param key
|
||||
* @return
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws InvalidKeyException
|
||||
* @throws IllegalBlockSizeException
|
||||
* @throws BadPaddingException
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws InvalidAlgorithmParameterException
|
||||
*/
|
||||
public static byte[] encrypt(String src, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
|
||||
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
|
||||
IvParameterSpec ivParameterSpec = getIv();
|
||||
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
|
||||
byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
|
||||
return cipherBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
* @param src 原密码
|
||||
* @param key 解密后的byte数组
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] decrypt(String src, byte[] key) throws Exception {
|
||||
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
|
||||
|
||||
IvParameterSpec ivParameterSpec = getIv();
|
||||
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
|
||||
byte[] hexBytes = hexStringToBytes(src);
|
||||
byte[] plainBytes = cipher.doFinal(hexBytes);
|
||||
return plainBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将byte转换为16进制字符串
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String byteToHexString(byte[] src) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < src.length; i++) {
|
||||
int v = src[i] & 0xff;
|
||||
String hv = Integer.toHexString(v);
|
||||
if (hv.length() < 2) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(hv);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将16进制字符串装换为byte数组
|
||||
* @param hexString
|
||||
* @return
|
||||
*/
|
||||
public static byte[] hexStringToBytes(String hexString) {
|
||||
hexString = hexString.toUpperCase();
|
||||
int length = hexString.length() / 2;
|
||||
char[] hexChars = hexString.toCharArray();
|
||||
byte[] b = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
int pos = i * 2;
|
||||
b[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private static byte charToByte(char c) {
|
||||
return (byte) "0123456789ABCDEF".indexOf(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接传入psd然后解码进行验证使用
|
||||
* @param psd 前台传过来的String 加密后的数组
|
||||
* @return
|
||||
*/
|
||||
public static String decrypt(String psd) {
|
||||
try {
|
||||
byte key[] = "1234567890ABCDEF1234567890ABCDEf".getBytes("utf-8");
|
||||
return new String(decrypt(psd, key));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false,
|
||||
"targets": {
|
||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||
}
|
||||
}],
|
||||
"stage-2"
|
||||
],
|
||||
"plugins": ["transform-vue-jsx", "transform-runtime"],
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": ["env", "stage-2"],
|
||||
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -1,5 +0,0 @@
|
||||
/build/
|
||||
/config/
|
||||
/dist/
|
||||
/*.js
|
||||
/test/unit/coverage/
|
||||
@@ -1,29 +0,0 @@
|
||||
// https://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
extends: [
|
||||
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
||||
'plugin:vue/essential',
|
||||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||
'standard'
|
||||
],
|
||||
// required to lint *.vue files
|
||||
plugins: [
|
||||
'vue'
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
// allow async-await
|
||||
'generator-star-spacing': 'off',
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules/
|
||||
/dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
/test/unit/coverage/
|
||||
/test/e2e/reports/
|
||||
selenium-debug.log
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
@@ -1,10 +0,0 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
"postcss-import": {},
|
||||
"postcss-url": {},
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
||||
+25
-26
@@ -1,30 +1,29 @@
|
||||
# bill
|
||||
|
||||
> bill
|
||||
|
||||
## Build Setup
|
||||
|
||||
``` bash
|
||||
# install dependencies
|
||||
npm install
|
||||
|
||||
# serve with hot reload at localhost:8080
|
||||
npm run dev
|
||||
|
||||
# build for production with minification
|
||||
npm run build
|
||||
|
||||
# build for production and view the bundle analyzer report
|
||||
npm run build --report
|
||||
|
||||
# run unit tests
|
||||
npm run unit
|
||||
|
||||
# run e2e tests
|
||||
npm run e2e
|
||||
|
||||
# run all tests
|
||||
npm test
|
||||
## Project setup
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
yarn run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
yarn run build
|
||||
```
|
||||
|
||||
### Run your tests
|
||||
```
|
||||
yarn run test
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
yarn run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict'
|
||||
const merge = require('webpack-merge')
|
||||
const prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"'
|
||||
})
|
||||
@@ -1,76 +0,0 @@
|
||||
'use strict'
|
||||
// Template version: 1.3.1
|
||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
dev: {
|
||||
|
||||
// Paths
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
proxyTable: {},
|
||||
|
||||
// Various Dev Server settings
|
||||
host: 'localhost', // can be overwritten by process.env.HOST
|
||||
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||
autoOpenBrowser: false,
|
||||
errorOverlay: true,
|
||||
notifyOnErrors: true,
|
||||
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||
|
||||
// Use Eslint Loader?
|
||||
// If true, your code will be linted during bundling and
|
||||
// linting errors and warnings will be shown in the console.
|
||||
useEslint: true,
|
||||
// If true, eslint errors and warnings will also be shown in the error overlay
|
||||
// in the browser.
|
||||
showEslintErrorsInOverlay: false,
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
// https://webpack.js.org/configuration/devtool/#development
|
||||
devtool: 'cheap-module-eval-source-map',
|
||||
|
||||
// If you have problems debugging vue-files in devtools,
|
||||
// set this to false - it *may* help
|
||||
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||
cacheBusting: true,
|
||||
|
||||
cssSourceMap: true
|
||||
},
|
||||
|
||||
build: {
|
||||
// Template for index.html
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
|
||||
// Paths
|
||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
productionSourceMap: true,
|
||||
// https://webpack.js.org/configuration/devtool/#production
|
||||
devtool: '#source-map',
|
||||
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
'use strict'
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict'
|
||||
const merge = require('webpack-merge')
|
||||
const devEnv = require('./dev.env')
|
||||
|
||||
module.exports = merge(devEnv, {
|
||||
NODE_ENV: '"testing"'
|
||||
})
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
cd dist
|
||||
tar czvf ../dist.tar.gz *
|
||||
cd ..
|
||||
scp dist.tar.gz gc:/tmp/
|
||||
ssh gc "sudo tar xzvf /tmp/dist.tar.gz -C /home/bill/www;sudo systemctl reload nginx"
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>bill</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,92 +1,52 @@
|
||||
{
|
||||
"name": "bill",
|
||||
"version": "1.0.0",
|
||||
"description": "bill",
|
||||
"author": "alawn.cn@gmail.com",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||
"start": "npm run dev",
|
||||
"unit": "jest --config test/unit/jest.conf.js --coverage",
|
||||
"e2e": "node test/e2e/runner.js",
|
||||
"test": "npm run unit && npm run e2e",
|
||||
"lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
|
||||
"build": "node build/build.js"
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"element-ui": "^2.8.2",
|
||||
"file-saver": "^2.0.2",
|
||||
"axios": "^0.19.0",
|
||||
"core-js": "^2.6.5",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"element-ui": "^2.9.1",
|
||||
"moment": "^2.24.0",
|
||||
"vue": "^2.5.2",
|
||||
"vue": "^2.6.10",
|
||||
"vue-json-excel": "^0.2.98",
|
||||
"vue-router": "^3.0.1"
|
||||
"vue-router": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.2",
|
||||
"babel-core": "^6.22.1",
|
||||
"babel-eslint": "^8.2.1",
|
||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
||||
"babel-jest": "^24.8.0",
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-plugin-dynamic-import-node": "^1.2.0",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.22.0",
|
||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
||||
"babel-preset-env": "^1.3.2",
|
||||
"babel-preset-stage-2": "^6.22.0",
|
||||
"babel-register": "^6.22.0",
|
||||
"chalk": "^2.0.1",
|
||||
"chromedriver": "^2.27.2",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"cross-spawn": "^5.0.1",
|
||||
"css-loader": "^2.1.1",
|
||||
"eslint": "^4.15.0",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-friendly-formatter": "^3.0.0",
|
||||
"eslint-loader": "^1.7.1",
|
||||
"eslint-plugin-import": "^2.7.0",
|
||||
"eslint-plugin-node": "^5.2.0",
|
||||
"eslint-plugin-promise": "^3.4.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"eslint-plugin-vue": "^4.0.0",
|
||||
"extract-text-webpack-plugin": "^3.0.0",
|
||||
"file-loader": "^1.1.4",
|
||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"jest": "^24.8.0",
|
||||
"jest-serializer-vue": "^0.3.0",
|
||||
"nightwatch": "^1.1.11",
|
||||
"node-notifier": "^5.1.2",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.1",
|
||||
"ora": "^1.2.0",
|
||||
"portfinder": "^1.0.13",
|
||||
"postcss-import": "^11.0.0",
|
||||
"postcss-loader": "^2.0.8",
|
||||
"postcss-url": "^7.2.1",
|
||||
"rimraf": "^2.6.0",
|
||||
"selenium-server": "^3.0.1",
|
||||
"semver": "^5.3.0",
|
||||
"shelljs": "^0.7.6",
|
||||
"uglifyjs-webpack-plugin": "^1.1.1",
|
||||
"url-loader": "^1.1.2",
|
||||
"vue-jest": "^1.0.2",
|
||||
"vue-loader": "^13.3.0",
|
||||
"vue-style-loader": "^3.0.1",
|
||||
"vue-template-compiler": "^2.5.2",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-bundle-analyzer": "^3.3.2",
|
||||
"webpack-dev-server": "^2.9.1",
|
||||
"webpack-merge": "^4.1.0"
|
||||
"@vue/cli-plugin-babel": "^3.8.0",
|
||||
"@vue/cli-plugin-eslint": "^3.8.0",
|
||||
"@vue/cli-service": "^3.8.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"rules": {},
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>bill</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but bill doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,13 +1,28 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<!-- <img src="./assets/logo.png"> -->
|
||||
<!-- <img alt="logo" src="https://fairy8-1258530674.picsh.myqcloud.com/img/20190611100737.png" width="400px"> -->
|
||||
<span style="color:#0081FF;font-size:22px"><b>Bills Assistant</b></span>
|
||||
<!-- <HR align=center width=300 color=#987cb9 SIZE=1> -->
|
||||
<!-- <hr style="border:1 dashed #987cb9" width="50%" color=#ACACAC size=1/> -->
|
||||
<br/>
|
||||
<!-- <router-link to="/login">登录页</router-link> -->
|
||||
<p/>
|
||||
<router-view/>
|
||||
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
|
||||
<p/>
|
||||
|
||||
<img alt="footer" src="https://fairy8-1258530674.picsh.myqcloud.com/img/20190611100310.png" width="150px">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import HelloWorld from './components/HelloWorld.vue'
|
||||
|
||||
export default {
|
||||
name: 'App'
|
||||
name: 'app',
|
||||
/*components: {
|
||||
HelloWorld
|
||||
}*/
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import HttpRequest from '@/axios/api.request'
|
||||
|
||||
export const addMerchant = (merc) => {
|
||||
export const newMerchant = (merc) => {
|
||||
return HttpRequest.request({
|
||||
url: 'basic/merchants',
|
||||
method: 'post',
|
||||
@@ -20,6 +20,14 @@ export const fetchTitles = () => {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const addTitle = (title) => {
|
||||
return HttpRequest.request({
|
||||
url: 'basic/titles',
|
||||
method: 'post',
|
||||
data: title
|
||||
})
|
||||
}
|
||||
export const getMerchant = (id) => {
|
||||
return HttpRequest.request({
|
||||
url: 'basic/merchants/' + id,
|
||||
@@ -28,11 +36,11 @@ export const getMerchant = (id) => {
|
||||
}
|
||||
|
||||
|
||||
export const addPost = (merc) => {
|
||||
export const addPost = (post) => {
|
||||
return HttpRequest.request({
|
||||
url: 'basic/posts',
|
||||
method: 'post',
|
||||
data: merc
|
||||
data: post
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import HttpRequest from '@/axios/api.request'
|
||||
|
||||
export const UserLoginAction = (ruleForm) => {
|
||||
export const login = (ruleForm) => {
|
||||
return HttpRequest.request({
|
||||
url: 'auth',
|
||||
method: 'post',
|
||||
|
||||
@@ -6,6 +6,6 @@ const HttpRequest = axios.create({
|
||||
// api的base_url
|
||||
baseURL: baseUrl,
|
||||
// 请求超时时间
|
||||
timeout: 5000
|
||||
timeout: 10000
|
||||
})
|
||||
export default HttpRequest
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
export default {
|
||||
/**
|
||||
* @description api请求基础路径
|
||||
*/
|
||||
baseUrl: {
|
||||
dev: 'http://localhost:30000/',
|
||||
pro: 'http://localhost:30000/'
|
||||
// pro: 'http://101.132.124.171:8080/demo-1.0/api/'
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description api请求基础路径
|
||||
*/
|
||||
baseUrl: {
|
||||
dev: 'http://localhost:30000',
|
||||
pro: 'https://bill.fairy8.cn/api'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,84 +1,31 @@
|
||||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<h2>Essential Links</h2>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br>
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://vuejs.org"
|
||||
target="_blank"
|
||||
>
|
||||
Core Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://forum.vuejs.org"
|
||||
target="_blank"
|
||||
>
|
||||
Forum
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://chat.vuejs.org"
|
||||
target="_blank"
|
||||
>
|
||||
Community Chat
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://twitter.com/vuejs"
|
||||
target="_blank"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
<a
|
||||
href="http://vuejs-templates.github.io/webpack/"
|
||||
target="_blank"
|
||||
>
|
||||
Docs for This Template
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
||||
</ul>
|
||||
<h2>Ecosystem</h2>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="http://router.vuejs.org/"
|
||||
target="_blank"
|
||||
>
|
||||
vue-router
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="http://vuex.vuejs.org/"
|
||||
target="_blank"
|
||||
>
|
||||
vuex
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="http://vue-loader.vuejs.org/"
|
||||
target="_blank"
|
||||
>
|
||||
vue-loader
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/awesome-vue"
|
||||
target="_blank"
|
||||
>
|
||||
awesome-vue
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@@ -86,18 +33,16 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
data () {
|
||||
return {
|
||||
msg: 'Welcome to Your Vue.js App'
|
||||
}
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h1, h2 {
|
||||
font-weight: normal;
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
// The Vue build version to load with the `import` command
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
import router from './router'
|
||||
import App from './App.vue'
|
||||
import router from '@/router/index.js'
|
||||
|
||||
import ElementUI from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import HttpRequest from '@/axios/api.request'
|
||||
import moment from "moment";
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.component('downloadExcel', JsonExcel)
|
||||
Vue.use(ElementUI)
|
||||
Vue.prototype.$moment = moment;
|
||||
Vue.config.productionTip = false
|
||||
|
||||
|
||||
HttpRequest.interceptors.request.use(
|
||||
config => {
|
||||
@@ -28,10 +28,61 @@ HttpRequest.interceptors.request.use(
|
||||
}
|
||||
)
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
components: { App },
|
||||
template: '<App/>'
|
||||
|
||||
// http response 拦截器
|
||||
HttpRequest.interceptors.response.use(
|
||||
response => {
|
||||
return response;
|
||||
},
|
||||
error => {
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
// 返回 401 清除token信息并跳转到登录页面
|
||||
// store.commit(types.LOGOUT);
|
||||
localStorage.removeItem('token');
|
||||
|
||||
router.replace({
|
||||
path: 'login',
|
||||
query: {redirect: router.currentRoute.fullPath}
|
||||
})
|
||||
}
|
||||
}
|
||||
return Promise.reject(error.response.data) // 返回接口返回的错误信息
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.meta.requireAuth) { // 判断该路由是否需要登录权限
|
||||
|
||||
if (localStorage.token) {
|
||||
next();
|
||||
}
|
||||
else {
|
||||
next({
|
||||
path: '/login',
|
||||
query: {redirect: to.fullPath} // 将跳转的路由path作为参数,登录成功后跳转到该路由
|
||||
})
|
||||
}
|
||||
// if (store.state.token) {
|
||||
// next();
|
||||
// }
|
||||
// else {
|
||||
// next({
|
||||
// path: '/login',
|
||||
// query: {redirect: to.fullPath}
|
||||
// })
|
||||
// }
|
||||
}
|
||||
else {
|
||||
next();
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
||||
|
||||
@@ -1,40 +1,48 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import HelloWorld from '@/components/HelloWorld'
|
||||
import VueRouter from 'vue-router'
|
||||
/** import HelloWorld from '@/components/HelloWorld'*/
|
||||
Vue.use(VueRouter)
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
export default new VueRouter({
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Index',
|
||||
redirect: '/login'
|
||||
redirect: '/gird'
|
||||
},
|
||||
{
|
||||
path: '/merchant',
|
||||
name: 'Merchant',
|
||||
component: () => import(/* webpackChunkName: "merchant" */ '../views/Merchant.vue')
|
||||
meta: {
|
||||
requireAuth: true, // 添加该字段,表示进入这个路由是需要登录的
|
||||
},
|
||||
component: () => import('../views/Merchant.vue')
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
name: 'Register',
|
||||
component: () => import(/* webpackChunkName: "merchant" */ '../views/Register.vue')
|
||||
component: () => import('../views/Register.vue')
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: () => import(/* webpackChunkName: "merchant" */ '../views/Login.vue')
|
||||
component: () => import('../views/Login.vue')
|
||||
},
|
||||
{
|
||||
path: '/bill',
|
||||
name: 'Bill',
|
||||
component: () => import(/* webpackChunkName: "merchant" */ '../views/Bill.vue')
|
||||
meta: {
|
||||
requireAuth: true, // 添加该字段,表示进入这个路由是需要登录的
|
||||
},
|
||||
component: () => import('../views/Bill.vue')
|
||||
},
|
||||
{
|
||||
path: '/gird',
|
||||
name: 'Gird',
|
||||
component: () => import(/* webpackChunkName: "merchant" */ '../views/Gird.vue')
|
||||
meta: {
|
||||
requireAuth: true, // 添加该字段,表示进入这个路由是需要登录的
|
||||
},
|
||||
component: () => import('../views/Gird.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import CryptoJS from 'crypto-js/crypto-js'
|
||||
|
||||
// 默认的 KEY 与 iv
|
||||
const KEY = CryptoJS.enc.Hex.parse("3132333435363738393041424344454631323334353637383930414243444566");
|
||||
const IV = CryptoJS.enc.Hex.parse('30313233343536373839414243444546');
|
||||
/**
|
||||
* AES加密
|
||||
*/
|
||||
export function encrypt(word, keyStr, ivStr) {
|
||||
let key = KEY
|
||||
let iv = IV
|
||||
|
||||
if (keyStr) {
|
||||
key = CryptoJS.enc.Utf8.parse(keyStr);
|
||||
iv = CryptoJS.enc.Utf8.parse(ivStr);
|
||||
}
|
||||
// 传过来的密码
|
||||
let srcs = CryptoJS.enc.Utf8.parse(word);
|
||||
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
||||
iv: iv,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
});
|
||||
// console.log("-=-=-=-", encrypted.ciphertext)
|
||||
return encrypted.ciphertext.toString()
|
||||
|
||||
}
|
||||
/**
|
||||
* AES 解密
|
||||
*
|
||||
*/
|
||||
export function decrypt(word, keyStr, ivStr) {
|
||||
let key = KEY
|
||||
let iv = IV
|
||||
|
||||
if (keyStr) {
|
||||
key = CryptoJS.enc.Utf8.parse(keyStr);
|
||||
iv = CryptoJS.enc.Utf8.parse(ivStr);
|
||||
}
|
||||
|
||||
let src = CryptoJS.format.Hex.parse(word);
|
||||
|
||||
var decrypt = CryptoJS.AES.decrypt(src, key, {
|
||||
iv: iv,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
});
|
||||
|
||||
return CryptoJS.enc.Utf8.stringify(decrypt)
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<el-form-item label="" label-width="80px">
|
||||
<el-checkbox v-model="bill.sentQuick" checked="true" :disabled="disabled">立即发送</el-checkbox>
|
||||
<el-checkbox v-model="bill.sentQuick" :checked="true" :disabled="disabled">立即发送</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- <el-form-item label="明细" prop="username"> -->
|
||||
<!--分割线-->
|
||||
<!-- <span><el-divider></el-divider></span> -->
|
||||
<el-table :data="bill.billItems" height="400px" style="width: 100%">
|
||||
<el-table :data="bill.billItems" height="400px" style="width: 100%" >
|
||||
<el-table-column prop="dating" label="日期" width="100"></el-table-column>
|
||||
<el-table-column prop="titleAbbr" label="抬头" width="150">
|
||||
<template slot-scope="scope">
|
||||
@@ -57,13 +57,13 @@
|
||||
<el-table-column prop="merchantAbbr" label="餐饮商户" width="150"></el-table-column>
|
||||
<el-table-column prop="amount" label="金额" width="80"></el-table-column>
|
||||
<el-table-column align="right">
|
||||
<template slot="header" slot-scope="scope">
|
||||
<template slot="header">
|
||||
<!-- <el-button class="itemBtn" type="primary" size="medium" @click="clearFocusRow();isAddShow = true;resetForm('addForm');" :disabled="disabled">添加</el-button> -->
|
||||
<el-button
|
||||
class="itemBtn"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="clearFocusRow();isAddShow = true;resetForm('addForm');"
|
||||
@click="clearFocusRow();isAddShow = true"
|
||||
:disabled="disabled"
|
||||
>添加</el-button>
|
||||
</template>
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
<!--增加-->
|
||||
<div width="600px">
|
||||
<el-dialog title="增加" :visible.sync="isAddShow" width="700px">
|
||||
<el-dialog title="增加" :visible.sync="isAddShow" width="700px" @close="resetFormFields('addForm')">
|
||||
<el-form ref="addForm" :model="focusRow" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
@@ -148,7 +148,7 @@
|
||||
<i
|
||||
class="el-icon-edit el-input__icon"
|
||||
slot="suffix"
|
||||
@click="handleIconClickTitles"
|
||||
@click="handleIconClickMerchant"
|
||||
></i>
|
||||
<template slot-scope="{ item }">
|
||||
<div class="name">{{ item.abbr }}</div>
|
||||
@@ -187,17 +187,16 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="addItem('addForm')" :disabled="disabled">确 定</el-button>
|
||||
<el-button @click="resetFormFields('addForm')">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="addItem('addForm')" :disabled="disabled">确 定</el-button>
|
||||
<el-button @click="resetForm('addForm')">重置</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!--编辑-->
|
||||
<div width="600px">
|
||||
<el-dialog title="编辑" :visible.sync="isEditShow" width="700px">
|
||||
<el-dialog title="编辑" :visible.sync="isEditShow" width="700px" @close="resetFormFields('editForm')">
|
||||
<el-form ref="editForm" :model="focusRow" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
@@ -236,11 +235,7 @@
|
||||
placeholder="请选择餐饮商户"
|
||||
@select="handleSelectMerchant"
|
||||
>
|
||||
<i
|
||||
class="el-icon-edit el-input__icon"
|
||||
slot="suffix"
|
||||
@click="handleIconClickTitles"
|
||||
></i>
|
||||
<i class="el-icon-edit el-input__icon" slot="suffix" @click="handleIconClickMerchant" ></i>
|
||||
<template slot-scope="{ item }">
|
||||
<div class="name">{{ item.abbr }}</div>
|
||||
<span class="subtitle">{{ item.name }}</span>
|
||||
@@ -278,12 +273,60 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<!-- <div slot="footer" class="dialog-footer"> -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="updateItem('editForm')" :disabled="disabled">确 定</el-button>
|
||||
<!-- <el-button type="primary" @click="updateItem()" >确 定</el-button> -->
|
||||
<el-button @click="resetForm('editForm')">重置</el-button>
|
||||
</div>
|
||||
<el-button @click="resetFormFields('editForm')">重置</el-button>
|
||||
</el-form-item>
|
||||
<!-- </div> -->
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!--添加邮寄地址-->
|
||||
<div width="600px">
|
||||
<el-dialog title="增加地址" :visible.sync="isPostEditShow" width="700px">
|
||||
<el-form ref="addPost" :model="post" :rules="rules" label-width="80px">
|
||||
<!--地址-->
|
||||
<el-form-item label="地址">
|
||||
<el-input v-model="post.address"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人">
|
||||
<el-input v-model="post.contact"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话">
|
||||
<el-input v-model="post.mobile"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="addPost()">添加</el-button>
|
||||
<!-- <el-button>取消</el-button> -->
|
||||
</el-form-item>
|
||||
<!-- <div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="addItem('addForm')" :disabled="disabled">确 定</el-button>
|
||||
<el-button @click="resetForm('addForm')">重置</el-button>
|
||||
</div> -->
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!--添加抬头-->
|
||||
<div width="600px">
|
||||
<el-dialog title="增加抬头" :visible.sync="isTitleEditShow" width="700px">
|
||||
<el-form ref="addTitle" :model="title" :rules="rules" label-width="80px">
|
||||
<!--地址-->
|
||||
<el-form-item label="简称">
|
||||
<el-input v-model="title.abbr"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="抬头">
|
||||
<el-input v-model="title.contact"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="税号">
|
||||
<el-input v-model="title.taxNo"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="addTitle()">添加</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,7 +335,8 @@
|
||||
|
||||
<script>
|
||||
import {
|
||||
newPost,
|
||||
addTitle,
|
||||
addPost,
|
||||
fetchPosts,
|
||||
getPost,
|
||||
fetchTitles,
|
||||
@@ -305,6 +349,8 @@ export default {
|
||||
return {
|
||||
isAddShow: false,
|
||||
isEditShow: false,
|
||||
isPostEditShow: false,
|
||||
isTitleEditShow: false,
|
||||
posts: [],
|
||||
titles: [],
|
||||
merchants: [],
|
||||
@@ -312,13 +358,15 @@ export default {
|
||||
editBtnDisabled: false,
|
||||
disabled: false,
|
||||
// focusRow: { index: null,dating: "2019-05-28", titleId: null, titleAbbr: "上海沐融",titleName:"",taxNo:"",merchantId: null, merchantAbbr: "华容月",amount: 0.0 },
|
||||
post:{address:"",contact:"",mobile:""},
|
||||
title:{abbr:"",name:"",taxNo:""},
|
||||
focusRow: {},
|
||||
bill: {
|
||||
postId: "",
|
||||
// postAddress: "",
|
||||
postContact: "",
|
||||
// postMobile : "",
|
||||
postId: "",
|
||||
// postId: "",
|
||||
// postAddress: "",
|
||||
sendQuick: false,
|
||||
billItems: [
|
||||
@@ -349,14 +397,30 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetFormFields(formName){
|
||||
console.info('resetFormFields.formName:' + formName);
|
||||
this.$nextTick(()=>{
|
||||
console.info('resetFormFields.resetFields');
|
||||
this.$refs[formName].resetFields();
|
||||
});
|
||||
},
|
||||
addPost() {
|
||||
addPost(this.post).then(res=>{
|
||||
this.loadPosts();
|
||||
this.isPostEditShow = false;
|
||||
this.$message({ message: "提交成功", type: "success" });
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
this.$router.go(-1);
|
||||
},
|
||||
resetForm(formName) {
|
||||
this.$refs[formName].resetFields();
|
||||
// this.disabled = false;
|
||||
// this.clearFocusRow();
|
||||
},
|
||||
// resetForm(formName) {
|
||||
// console.info('formName:' + formName);
|
||||
// // console.info('this.$refs' + JSON.stringify(this.$refs));
|
||||
// this.$refs[formName].resetFields();
|
||||
// // this.disabled = false;
|
||||
// // this.clearFocusRow();
|
||||
// },
|
||||
/** 在表格中添加明细 */
|
||||
addItem(formName) {
|
||||
var oriForm = formName;
|
||||
@@ -374,7 +438,6 @@ export default {
|
||||
this.clearFocusRow();
|
||||
console.info("focusRow:" + JSON.stringify(this.focusRow));
|
||||
this.isAddShow = false;
|
||||
// this.resetForm(oriForm);
|
||||
} else {
|
||||
console.log("error submit!!");
|
||||
return false;
|
||||
@@ -383,6 +446,7 @@ export default {
|
||||
},
|
||||
/** 在表格中添加明细 */
|
||||
updateItem(formName) {
|
||||
var oriForm = formName;
|
||||
this.$refs[formName].validate(valid => {
|
||||
if (valid) {
|
||||
console.info("index:" + index);
|
||||
@@ -456,44 +520,30 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
reset(formName) {
|
||||
// this.$refs[formName].resetFields();
|
||||
// this.disabled = false;
|
||||
},
|
||||
// querySearch(queryString, cb) {
|
||||
// var posts = this.posts;
|
||||
// console.error("posts:" + posts);
|
||||
// var results = queryString ? posts.filter(this.createFilter(queryString)) : posts;
|
||||
// // 调用 callback 返回建议列表的数据
|
||||
// cb(results);
|
||||
// },
|
||||
/** AutoComplete Posts 处理*/
|
||||
querySearchAsyncPosts(queryString, cb) {
|
||||
var list = [{}];
|
||||
fetchPosts().then(function(response) {
|
||||
for (let i of response.data) {
|
||||
i.value = i.contact; //将想要展示的数据作为value
|
||||
// i.value = i.contact; //将想要展示的数据作为value
|
||||
}
|
||||
list = response.data;
|
||||
cb(list);
|
||||
});
|
||||
|
||||
// var posts = this.posts;
|
||||
// console.error("posts:" + posts);
|
||||
// var results = queryString ? posts.filter(this.createFilter(queryString)) : posts;
|
||||
// // 调用 callback 返回建议列表的数据
|
||||
// cb(results);
|
||||
var results = queryString ? this.posts.filter(this.createFilterPosts(queryString)):this.posts;
|
||||
cb(results);
|
||||
},
|
||||
createFilterPosts(queryString) {
|
||||
return posts => {
|
||||
return post => {
|
||||
return (
|
||||
posts.contact.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
post.contact.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
);
|
||||
};
|
||||
},
|
||||
loadPosts() {
|
||||
console.error("loadPosts");
|
||||
console.info("loadPosts");
|
||||
// console.info("$ref:" + );
|
||||
fetchPosts().then(res=>{
|
||||
console.info("res:" + res);
|
||||
console.info("res.data:" + JSON.stringify(res.data));
|
||||
this.posts = res.data;
|
||||
for (let i of this.posts) {
|
||||
i.value = i.contact; //将想要展示的数据作为value
|
||||
}
|
||||
})
|
||||
console.info("posts:" + JSON.stringify(this.posts));
|
||||
},
|
||||
handleSelectPosts(item) {
|
||||
this.bill.postId = item.id;
|
||||
@@ -501,30 +551,30 @@ export default {
|
||||
console.log("postContact:" + this.bill.postContact);
|
||||
},
|
||||
handleIconClickPosts(ev) {
|
||||
this.isPostEditShow = true;
|
||||
console.log('handleIconClickPosts');
|
||||
console.log(ev);
|
||||
},
|
||||
|
||||
/** AutoComplete Titles 处理*/
|
||||
querySearchAsyncTitles(queryString, cb) {
|
||||
var list = [{}];
|
||||
fetchTitles().then(function(response) {
|
||||
console.info(response);
|
||||
for (let i of response.data) {
|
||||
i.value = i.abbr; // 将想要展示的数据作为value
|
||||
}
|
||||
list = response.data;
|
||||
cb(list);
|
||||
});
|
||||
var results = queryString ? this.titles.filter(this.createFilterTitles(queryString)):this.titles;
|
||||
cb(results);
|
||||
},
|
||||
createFilterTitles(queryString) {
|
||||
return titles => {
|
||||
return title => {
|
||||
return (
|
||||
titles.abbr.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
title.abbr.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
);
|
||||
};
|
||||
},
|
||||
loadTitles() {
|
||||
console.error("loadTitles");
|
||||
fetchTitles().then(res=>{
|
||||
this.titles = res.data;
|
||||
for (let i of this.titles) {
|
||||
i.value = i.abbr; //将想要展示的数据作为value
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSelectTitles(item) {
|
||||
this.focusRow.titleId = item.id;
|
||||
@@ -539,20 +589,13 @@ export default {
|
||||
},
|
||||
/** AutoComplete Merchant 处理*/
|
||||
querySearchAsyncMerchant(queryString, cb) {
|
||||
var list = [{}];
|
||||
fetchMerchants().then(function(response) {
|
||||
for (let i of response.data) {
|
||||
i.value = i.abbr; // 将想要展示的数据作为value
|
||||
}
|
||||
list = response.data;
|
||||
cb(list);
|
||||
});
|
||||
var results = queryString ? this.merchants.filter(this.createFilterMerchant(queryString)):this.merchants;
|
||||
cb(results);
|
||||
},
|
||||
createFilterMerchant(queryString) {
|
||||
return merchants => {
|
||||
return merchant => {
|
||||
return (
|
||||
merchants.contact.toLowerCase().indexOf(queryString.toLowerCase()) ===
|
||||
0
|
||||
merchant.abbr.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
);
|
||||
};
|
||||
},
|
||||
@@ -567,27 +610,30 @@ export default {
|
||||
console.log(ev);
|
||||
},
|
||||
loadMerchant() {
|
||||
console.error("loadTitles");
|
||||
fetchMerchants().then(res=>{
|
||||
this.merchants = res.data;
|
||||
for (let i of this.merchants) {
|
||||
i.value = i.abbr; //将想要展示的数据作为value
|
||||
}
|
||||
})
|
||||
},
|
||||
/** 清理当前缓存 */
|
||||
clearFocusRow() {
|
||||
// console.log(this.$refs)
|
||||
this.focusRow = {};
|
||||
console.info("clearFocusRow");
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.posts = this.loadPosts();
|
||||
// console.info('mounted.this.posts:' + posts);
|
||||
async mounted() {
|
||||
await this.loadPosts();
|
||||
await this.loadTitles();
|
||||
await this.loadMerchant();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.subtitle {
|
||||
font-size: 12px;
|
||||
color: #b4b4b4;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
@@ -659,6 +705,36 @@ a {
|
||||
text-align: left;
|
||||
/* width: 800px; */
|
||||
}
|
||||
.name {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
/* line-height: small; */
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 13px;
|
||||
color: #b4b4b4;
|
||||
}
|
||||
/* .highlighted .subtitle {
|
||||
color: #ddd;
|
||||
} */
|
||||
/* .my-autocomplete {
|
||||
li {
|
||||
line-height: small;
|
||||
padding: 1px;
|
||||
.name {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 12px;
|
||||
color: #b4b4b4;
|
||||
}
|
||||
|
||||
.highlighted .addr {
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
} */
|
||||
.posts,
|
||||
.titles,
|
||||
.merchants {
|
||||
|
||||
@@ -29,24 +29,25 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { UserLoginAction } from "../api/user.js";
|
||||
import { login } from '../api/user.js';
|
||||
import { encrypt,decrypt } from "../utils/encoder.js";
|
||||
export default {
|
||||
name: "Login",
|
||||
name: 'Login',
|
||||
data() {
|
||||
return {
|
||||
disabled: false,
|
||||
ruleForm: {
|
||||
username: "",
|
||||
password: ""
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{ required: true, message: "请输入户名", trigger: "blur" },
|
||||
{ min: 3, max: 15, message: "长度在 3 到 15 个字符", trigger: "blur" }
|
||||
{ required: true, message: '请输入户名', trigger: 'blur' },
|
||||
{ min: 3, max: 15, message: '长度在 3 到 30 个字符', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "请输入密码", trigger: "change" },
|
||||
{ min: 3, max: 15, message: "长度在 3 到 15 个字符", trigger: "blur" }
|
||||
{ required: true, message: '请输入密码', trigger: 'change' },
|
||||
{ min: 3, max: 15, message: '长度在 3 到 30 个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -57,19 +58,26 @@ export default {
|
||||
var _this = this;
|
||||
if (valid) {
|
||||
this.disabled = true;
|
||||
UserLoginAction(this.ruleForm)
|
||||
/** 加密处理 */
|
||||
var encoderStr = encrypt(this.ruleForm.password);
|
||||
console.log('密文:' + encoderStr);
|
||||
console.log('解密:' + decrypt(encoderStr));
|
||||
this.ruleForm.password = encoderStr;
|
||||
|
||||
/** 访问登录服务 */
|
||||
login(this.ruleForm)
|
||||
.then(res => {
|
||||
var token = "Bearer " + res.data.token;
|
||||
console.log("token:" + token);
|
||||
window.localStorage.setItem("token", token);
|
||||
this.$message({ message: "登录成功", type: "success" });
|
||||
var token = 'Bearer ' + res.data.token;
|
||||
console.log('token:' + token);
|
||||
window.localStorage.setItem('token', token);
|
||||
this.$message({ message: '登录成功', type: 'success' });
|
||||
this.$router.push({ path: 'Gird' })
|
||||
})
|
||||
.catch(function(error) {
|
||||
// _this.$message({ message: error.response.statusText, type: 'error' });
|
||||
// _this.$message.error();
|
||||
|
||||
_this.disabled = false;
|
||||
_this.disabled = false;
|
||||
if (error.response) {
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
@@ -86,20 +94,32 @@ export default {
|
||||
_this.$message.error('未知错误');
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.log("Error", error.message);
|
||||
_this.$message.error(error.response.message);
|
||||
// console.log('Error', error.message);
|
||||
console.log('Error', error.status);
|
||||
if(error.status == 401 ){
|
||||
_this.$message.error('用户名或密码有误');
|
||||
_this.reset('ruleForm');
|
||||
// _this.ruleForm.password = '';
|
||||
}
|
||||
else {
|
||||
// _this.ruleForm.password = '';
|
||||
_this.$message.error(error.status.toString() + error.message);
|
||||
_this.reset('ruleForm');
|
||||
}
|
||||
}
|
||||
console.log(error.config);
|
||||
// _this.$message.error(error.response.statusText);
|
||||
});
|
||||
} else {
|
||||
console.log("error submit!!");
|
||||
console.log('error submit!!');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
reset(formName) {
|
||||
console.log('reset')
|
||||
this.$refs[formName].resetFields();
|
||||
this.$refs[formName].focus();
|
||||
this.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,15 @@
|
||||
<el-input v-model="ruleForm.fullname" clearable placeholder="请输入姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="ruleForm.password" @keyup.enter.native="onSubmit('ruleForm')" show-password placeholder="请输入密码"></el-input>
|
||||
<el-input
|
||||
v-model="ruleForm.password"
|
||||
@keyup.enter.native="onSubmit('ruleForm')"
|
||||
show-password
|
||||
placeholder="请输入密码"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit('ruleForm')" :disabled="disabled">登录</el-button>
|
||||
<el-button type="primary" @click="onSubmit('ruleForm')" :disabled="disabled">注册</el-button>
|
||||
<el-button @click="reset('ruleForm')">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -22,6 +27,7 @@
|
||||
|
||||
<script>
|
||||
import { register } from "../api/user.js";
|
||||
import { encrypt,decrypt } from "../utils/encoder.js";
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
@@ -35,7 +41,7 @@ export default {
|
||||
rules: {
|
||||
username: [
|
||||
{ required: true, message: "请输入用户名", trigger: "blur" },
|
||||
{ min: 3, max: 15, message: "长度在 3 到 15 个字符", trigger: "blur" }
|
||||
{ min: 3, max: 15, message: "长度在 3 到 30 个字符", trigger: "blur" }
|
||||
],
|
||||
fullname: [
|
||||
{ required: true, message: "请输入姓名", trigger: "blur" },
|
||||
@@ -43,7 +49,7 @@ export default {
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "请输入密码", trigger: "change" },
|
||||
{ min: 3, max: 15, message: "长度在 3 到 15 个字符", trigger: "blur" }
|
||||
{ min: 3, max: 15, message: "长度在 3 到 30 个字符", trigger: "blur" }
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -53,20 +59,28 @@ export default {
|
||||
this.$refs[formName].validate(valid => {
|
||||
var _this = this;
|
||||
if (valid) {
|
||||
this.disabled = true;
|
||||
register(this.ruleForm)
|
||||
this.disabled = true;
|
||||
/** 加密处理 */
|
||||
var encoderStr = encrypt(this.ruleForm.password);
|
||||
console.log('解密:' + decrypt(encoderStr));
|
||||
this.ruleForm.password = encoderStr;
|
||||
/** 访问注册服务 */
|
||||
register(this.ruleForm)
|
||||
.then(res => {
|
||||
this.$message({ message: "注册成功", type: "success" });
|
||||
this.$router.push({ path: 'Login' })
|
||||
this.$router.push({ path: "Login" });
|
||||
})
|
||||
.catch(function(error) {
|
||||
// _this.$message({ message: error.response.statusText, type: 'error' });
|
||||
// _this.$message.error();
|
||||
_this.disabled = false;
|
||||
_this.disabled = false;
|
||||
if (error.response) {
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
_this.$message({ message: error.response.data.message, type: 'error' });
|
||||
_this.$message({
|
||||
message: error.response.data.message,
|
||||
type: "error"
|
||||
});
|
||||
console.log(error.response.data);
|
||||
console.log(error.response.status);
|
||||
console.log(error.response.headers);
|
||||
@@ -76,7 +90,7 @@ export default {
|
||||
// http.ClientRequest in node.js
|
||||
// _this.$message.error(error.request);
|
||||
console.log(error.request);
|
||||
_this.$message.error('未知错误');
|
||||
_this.$message.error("未知错误");
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.log("Error", error.message);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// A custom Nightwatch assertion.
|
||||
// The assertion name is the filename.
|
||||
// Example usage:
|
||||
//
|
||||
// browser.assert.elementCount(selector, count)
|
||||
//
|
||||
// For more information on custom assertions see:
|
||||
// http://nightwatchjs.org/guide#writing-custom-assertions
|
||||
|
||||
exports.assertion = function (selector, count) {
|
||||
this.message = 'Testing if element <' + selector + '> has count: ' + count
|
||||
this.expected = count
|
||||
this.pass = function (val) {
|
||||
return val === this.expected
|
||||
}
|
||||
this.value = function (res) {
|
||||
return res.value
|
||||
}
|
||||
this.command = function (cb) {
|
||||
var self = this
|
||||
return this.api.execute(function (selector) {
|
||||
return document.querySelectorAll(selector).length
|
||||
}, [selector], function (res) {
|
||||
cb.call(self, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
require('babel-register')
|
||||
var config = require('../../config')
|
||||
|
||||
// http://nightwatchjs.org/gettingstarted#settings-file
|
||||
module.exports = {
|
||||
src_folders: ['test/e2e/specs'],
|
||||
output_folder: 'test/e2e/reports',
|
||||
custom_assertions_path: ['test/e2e/custom-assertions'],
|
||||
|
||||
selenium: {
|
||||
start_process: true,
|
||||
server_path: require('selenium-server').path,
|
||||
host: '127.0.0.1',
|
||||
port: 4444,
|
||||
cli_args: {
|
||||
'webdriver.chrome.driver': require('chromedriver').path
|
||||
}
|
||||
},
|
||||
|
||||
test_settings: {
|
||||
default: {
|
||||
selenium_port: 4444,
|
||||
selenium_host: 'localhost',
|
||||
silent: true,
|
||||
globals: {
|
||||
devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
|
||||
}
|
||||
},
|
||||
|
||||
chrome: {
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
javascriptEnabled: true,
|
||||
acceptSslCerts: true
|
||||
}
|
||||
},
|
||||
|
||||
firefox: {
|
||||
desiredCapabilities: {
|
||||
browserName: 'firefox',
|
||||
javascriptEnabled: true,
|
||||
acceptSslCerts: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// 1. start the dev server using production config
|
||||
process.env.NODE_ENV = 'testing'
|
||||
|
||||
const webpack = require('webpack')
|
||||
const DevServer = require('webpack-dev-server')
|
||||
|
||||
const webpackConfig = require('../../build/webpack.prod.conf')
|
||||
const devConfigPromise = require('../../build/webpack.dev.conf')
|
||||
|
||||
let server
|
||||
|
||||
devConfigPromise.then(devConfig => {
|
||||
const devServerOptions = devConfig.devServer
|
||||
const compiler = webpack(webpackConfig)
|
||||
server = new DevServer(compiler, devServerOptions)
|
||||
const port = devServerOptions.port
|
||||
const host = devServerOptions.host
|
||||
return server.listen(port, host)
|
||||
})
|
||||
.then(() => {
|
||||
// 2. run the nightwatch test suite against it
|
||||
// to run in additional browsers:
|
||||
// 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings"
|
||||
// 2. add it to the --env flag below
|
||||
// or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
|
||||
// For more information on Nightwatch's config file, see
|
||||
// http://nightwatchjs.org/guide#settings-file
|
||||
let opts = process.argv.slice(2)
|
||||
if (opts.indexOf('--config') === -1) {
|
||||
opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
|
||||
}
|
||||
if (opts.indexOf('--env') === -1) {
|
||||
opts = opts.concat(['--env', 'chrome'])
|
||||
}
|
||||
|
||||
const spawn = require('cross-spawn')
|
||||
const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
|
||||
|
||||
runner.on('exit', function (code) {
|
||||
server.close()
|
||||
process.exit(code)
|
||||
})
|
||||
|
||||
runner.on('error', function (err) {
|
||||
server.close()
|
||||
throw err
|
||||
})
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
// For authoring Nightwatch tests, see
|
||||
// http://nightwatchjs.org/guide#usage
|
||||
|
||||
module.exports = {
|
||||
'default e2e tests': function (browser) {
|
||||
// automatically uses dev Server port from /config.index.js
|
||||
// default: http://localhost:8080
|
||||
// see nightwatch.conf.js
|
||||
const devServer = browser.globals.devServerURL
|
||||
|
||||
browser
|
||||
.url(devServer)
|
||||
.waitForElementVisible('#app', 5000)
|
||||
.assert.elementPresent('.hello')
|
||||
.assert.containsText('h1', 'Welcome to Your Vue.js App')
|
||||
.assert.elementCount('img', 1)
|
||||
.end()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"jest": true
|
||||
},
|
||||
"globals": {
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
rootDir: path.resolve(__dirname, '../../'),
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'json',
|
||||
'vue'
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
|
||||
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
|
||||
},
|
||||
testPathIgnorePatterns: [
|
||||
'<rootDir>/test/e2e'
|
||||
],
|
||||
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
|
||||
setupFiles: ['<rootDir>/test/unit/setup'],
|
||||
mapCoverage: true,
|
||||
coverageDirectory: '<rootDir>/test/unit/coverage',
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{js,vue}',
|
||||
'!src/main.js',
|
||||
'!src/router/index.js',
|
||||
'!**/node_modules/**'
|
||||
]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
@@ -1,11 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import HelloWorld from '@/components/HelloWorld'
|
||||
|
||||
describe('HelloWorld.vue', () => {
|
||||
it('should render correct contents', () => {
|
||||
const Constructor = Vue.extend(HelloWorld)
|
||||
const vm = new Constructor().$mount()
|
||||
expect(vm.$el.querySelector('.hello h1').textContent)
|
||||
.toEqual('Welcome to Your Vue.js App')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user