64 changed files with 26858 additions and 0 deletions
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<classpath> |
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"> |
||||
<attributes> |
||||
<attribute name="optional" value="true"/> |
||||
<attribute name="maven.pomderived" value="true"/> |
||||
</attributes> |
||||
</classpathentry> |
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> |
||||
<attributes> |
||||
<attribute name="maven.pomderived" value="true"/> |
||||
</attributes> |
||||
</classpathentry> |
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"> |
||||
<attributes> |
||||
<attribute name="optional" value="true"/> |
||||
<attribute name="maven.pomderived" value="true"/> |
||||
<attribute name="test" value="true"/> |
||||
</attributes> |
||||
</classpathentry> |
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> |
||||
<attributes> |
||||
<attribute name="maven.pomderived" value="true"/> |
||||
</attributes> |
||||
</classpathentry> |
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> |
||||
<attributes> |
||||
<attribute name="maven.pomderived" value="true"/> |
||||
</attributes> |
||||
</classpathentry> |
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/> |
||||
<classpathentry kind="output" path="target/classes"/> |
||||
</classpath> |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<projectDescription> |
||||
<name>picture-bed</name> |
||||
<comment></comment> |
||||
<projects> |
||||
</projects> |
||||
<buildSpec> |
||||
<buildCommand> |
||||
<name>org.eclipse.jdt.core.javabuilder</name> |
||||
<arguments> |
||||
</arguments> |
||||
</buildCommand> |
||||
<buildCommand> |
||||
<name>org.eclipse.m2e.core.maven2Builder</name> |
||||
<arguments> |
||||
</arguments> |
||||
</buildCommand> |
||||
</buildSpec> |
||||
<natures> |
||||
<nature>org.eclipse.jdt.core.javanature</nature> |
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature> |
||||
</natures> |
||||
</projectDescription> |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1 |
||||
encoding//src/main/java=UTF-8 |
||||
encoding//src/main/resources=UTF-8 |
||||
encoding/<project>=UTF-8 |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
eclipse.preferences.version=1 |
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate |
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 |
||||
org.eclipse.jdt.core.compiler.compliance=1.8 |
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning |
||||
org.eclipse.jdt.core.compiler.release=disabled |
||||
org.eclipse.jdt.core.compiler.source=1.8 |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
activeProfiles= |
||||
eclipse.preferences.version=1 |
||||
resolveWorkspaceProjects=true |
||||
version=1 |
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
server.port=80 |
||||
server.servlet.context-path=/ |
||||
version.num=1.0.0 |
||||
|
||||
# 程序自身数据源配置 |
||||
spring.datasource.url=jdbc:mysql://localhost:3306/picture?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true |
||||
spring.datasource.username=root |
||||
spring.datasource.password=51131420 |
||||
|
||||
picture.root.path=E:/image |
||||
|
||||
timeout.login.token=1000000 |
||||
spring.servlet.multipart.max-file-size=10MB |
||||
spring.servlet.multipart.max-request-size=100MB |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- Configuration后面的status,这个用于设置log4j2自身内部的信息输出 --> |
||||
<!-- monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数。 --> |
||||
<configuration status="error" monitorInterval="60"> |
||||
|
||||
<appenders> |
||||
<!--控制台 --> |
||||
<Console name="Console" target="SYSTEM_OUT"> |
||||
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> |
||||
<ThresholdFilter level="debug" onMatch="ACCEPT" |
||||
onMismatch="DENY" /> |
||||
<!--输出日志的格式 --> |
||||
<PatternLayout |
||||
pattern="%d{HH:mm:ss.SSS} [%p] %class{36} %L %M - %msg%xEx%n" /> |
||||
</Console> |
||||
</appenders> |
||||
<loggers> |
||||
<logger name="vip.xumy" level="DEBUG"></logger> |
||||
<root level="warn"> |
||||
<appender-ref ref="Console" /> |
||||
</root> |
||||
</loggers> |
||||
</configuration> |
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-parent</artifactId> |
||||
<version>2.0.2.RELEASE</version> |
||||
</parent> |
||||
<groupId>vip.xumy.picture</groupId> |
||||
<artifactId>picture-bed</artifactId> |
||||
<version>1.0.0</version> |
||||
<name>picture-bed</name> |
||||
|
||||
<properties> |
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
||||
<xumy.admin.version>1.2.0</xumy.admin.version> |
||||
<log4j.version>1.2.17</log4j.version> |
||||
<fastjson.version>1.2.46</fastjson.version> |
||||
<mybatis-spring-boot.version>1.3.2</mybatis-spring-boot.version> |
||||
<druid.version>1.1.9</druid.version> |
||||
<mybatis.pagehelper.version>1.2.5</mybatis.pagehelper.version> |
||||
<sqlitejdbc.version>0.5.6</sqlitejdbc.version> |
||||
<bouncycastle.version>1.46</bouncycastle.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
|
||||
<dependency> |
||||
<groupId>vip.xumy.admin</groupId> |
||||
<artifactId>xumy_admin</artifactId> |
||||
<version>${xumy.admin.version}</version> |
||||
</dependency> |
||||
|
||||
<!-- 代码修改之后可以实时生效,该模块在完整的打包环境下运行的时候会被禁用 --> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-devtools</artifactId> |
||||
<optional>true</optional> |
||||
</dependency> |
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-web</artifactId> |
||||
<exclusions> |
||||
<exclusion> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-logging</artifactId> |
||||
</exclusion> |
||||
</exclusions> |
||||
</dependency> |
||||
|
||||
<!-- SpringBoot 的测试依赖 --> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-test</artifactId> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
</dependencies> |
||||
|
||||
<!-- Package as an executable jar --> |
||||
<build> |
||||
<finalName>pciture</finalName> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
<configuration> |
||||
<executable>true</executable> |
||||
</configuration> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
</project> |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
package vip.xumy.picture; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||
|
||||
import vip.xumy.admin.sys.conf.SysInitializer; |
||||
import vip.xumy.admin.verify.conf.VerifyInitializer; |
||||
import vip.xumy.picture.conf.PictureRescueInitializer; |
||||
|
||||
public class PictureRescueApplocation extends SpringBootServletInitializer { |
||||
|
||||
public static void main(String[] args) { |
||||
Class<?>[] arr = new Class<?>[] { VerifyInitializer.class, SysInitializer.class, PictureRescueInitializer.class }; |
||||
SpringApplication.run(arr, args); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
package vip.xumy.picture.conf; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.ApplicationArguments; |
||||
import org.springframework.boot.ApplicationRunner; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import vip.xumy.admin.sys.service.ConfigService; |
||||
|
||||
/** |
||||
* @author:mengyxu |
||||
* @date:2020年3月25日 |
||||
*/ |
||||
|
||||
@Component |
||||
@Configuration |
||||
public class PictureApplicationRunner implements ApplicationRunner { |
||||
private static final String HOSTR_CFG_KEY = "intranet_host"; |
||||
private static final String HOSTE_CFG_KEY = "internet_host"; |
||||
public static Map<String, String> HOST_MAP = new HashMap<>();; |
||||
|
||||
@Autowired |
||||
public void setConfigService(ConfigService configService) { |
||||
HOST_MAP.put("traHost", configService.getStringConfig(HOSTR_CFG_KEY, null)); |
||||
HOST_MAP.put("tertHost", configService.getStringConfig(HOSTE_CFG_KEY, null)); |
||||
} |
||||
|
||||
@Override |
||||
public void run(ApplicationArguments args) throws Exception { |
||||
// TODO Auto-generated method stub
|
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
package vip.xumy.picture.conf; |
||||
|
||||
import org.mybatis.spring.annotation.MapperScan; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
||||
import org.springframework.boot.builder.SpringApplicationBuilder; |
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||
import org.springframework.context.annotation.ComponentScan; |
||||
|
||||
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class) |
||||
@ComponentScan(value = "vip.xumy.picture") |
||||
@MapperScan("vip.xumy.picture.**.mapper") |
||||
public class PictureRescueInitializer extends SpringBootServletInitializer { |
||||
|
||||
@Override |
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { |
||||
return builder.sources(PictureRescueInitializer.class); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
package vip.xumy.picture.ctrl; |
||||
|
||||
import java.util.List; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.web.bind.annotation.DeleteMapping; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.PostMapping; |
||||
import org.springframework.web.bind.annotation.PutMapping; |
||||
import org.springframework.web.bind.annotation.RequestBody; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import com.github.pagehelper.Page; |
||||
import com.github.pagehelper.PageHelper; |
||||
|
||||
import vip.xumy.admin.utils.LoginUtil; |
||||
import vip.xumy.core.exception.CoreException; |
||||
import vip.xumy.core.pojo.com.AjaxResponse; |
||||
import vip.xumy.core.pojo.com.PageResponse; |
||||
import vip.xumy.picture.pojo.Picture; |
||||
import vip.xumy.picture.service.PictureService; |
||||
|
||||
/** |
||||
* Do not use for any commercial purposes without permission |
||||
* |
||||
* @author: mengyxu |
||||
* @date: 2021年12月31日 |
||||
*/ |
||||
|
||||
@RestController |
||||
@RequestMapping("picture") |
||||
public class PictureController { |
||||
@Autowired |
||||
private PictureService pictureService; |
||||
|
||||
@GetMapping |
||||
public PageResponse<Picture> list(Picture example, HttpServletRequest request) { |
||||
example.setUser(LoginUtil.getUserId(request)); |
||||
Page<Picture> pages = PageHelper.startPage(example.getPage(), example.getSize()); |
||||
List<Picture> list = pictureService.list(example); |
||||
PageResponse<Picture> rsp = new PageResponse<>(); |
||||
rsp.setRows(list); |
||||
rsp.setTotal(pages.getTotal()); |
||||
return rsp; |
||||
} |
||||
|
||||
@PostMapping |
||||
public AjaxResponse save(MultipartFile file, HttpServletRequest request) throws CoreException { |
||||
pictureService.save(file, LoginUtil.getUserId(request)); |
||||
return new AjaxResponse(true, "上传成功"); |
||||
} |
||||
|
||||
@PutMapping |
||||
public AjaxResponse update(@RequestBody Picture picture) throws CoreException { |
||||
pictureService.update(picture); |
||||
return new AjaxResponse(true, "更新成功"); |
||||
} |
||||
|
||||
@DeleteMapping |
||||
public AjaxResponse delete(@RequestBody Picture picture) throws CoreException { |
||||
pictureService.delete(picture); |
||||
return new AjaxResponse(true, "删除成功"); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
package vip.xumy.picture.ctrl; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
import vip.xumy.picture.conf.PictureApplicationRunner; |
||||
|
||||
/** Do not use for any commercial purposes without permission |
||||
* @author: mengyxu |
||||
* @date: 2021年12月31日 |
||||
*/ |
||||
|
||||
@RestController |
||||
@RequestMapping("public") |
||||
public class PublicControoler { |
||||
|
||||
@GetMapping("host") |
||||
public Map<String, String> getHost(){ |
||||
return PictureApplicationRunner.HOST_MAP; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
package vip.xumy.picture.mapper; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.apache.ibatis.annotations.Delete; |
||||
import org.apache.ibatis.annotations.Insert; |
||||
import org.apache.ibatis.annotations.Mapper; |
||||
import org.apache.ibatis.annotations.Select; |
||||
import org.apache.ibatis.annotations.Update; |
||||
|
||||
import vip.xumy.picture.pojo.Picture; |
||||
|
||||
/** |
||||
* Do not use for any commercial purposes without permission |
||||
* |
||||
* @author: mengyxu |
||||
* @date: 2021年12月31日 |
||||
*/ |
||||
|
||||
@Mapper |
||||
public interface PictureMapper { |
||||
|
||||
@Select({ "<script>", "SELECT * FROM user_picture ", "<where>", "<if test='user != null'> AND user = #{user} </if>", |
||||
"<if test='startTime != null'> AND time >= #{startTime} </if>", |
||||
"<if test='endTime != null'> AND #{endTime} > time </if>", |
||||
"<if test='remark != null'> AND remark LIKE CONCAT('%', #{remark}, '%') </if>", |
||||
"<if test='status != null'> AND status = #{status} </if>", "</where>", "ORDER BY time DESC", "</script>" }) |
||||
List<Picture> list(Picture example); |
||||
|
||||
@Insert({ "INSERT INTO user_picture VALUES (#{id}, #{user}, NOW(), #{path}, #{space}, #{status}, #{remark})" }) |
||||
void save(Picture picture); |
||||
|
||||
@Update({ "UPDATE user_picture SET status = #{status}, remark = #{remark} WHERE id = #{id}" }) |
||||
void update(Picture picture); |
||||
|
||||
@Delete({ "DELETE FROM user_picture WHERE id = #{id}" }) |
||||
void delete(String id); |
||||
|
||||
@Delete({ "DELETE FROM user_picture WHERE user = #{user}" }) |
||||
void deleteAll(String user); |
||||
|
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
package vip.xumy.picture.pojo; |
||||
|
||||
import lombok.Getter; |
||||
import lombok.Setter; |
||||
import vip.xumy.core.pojo.base.BasePeriod; |
||||
|
||||
/** |
||||
* Do not use for any commercial purposes without permission |
||||
* |
||||
* @author: mengyxu |
||||
* @date: 2021年12月31日 |
||||
*/ |
||||
|
||||
@Setter |
||||
@Getter |
||||
public class Picture extends BasePeriod { |
||||
|
||||
private String id; |
||||
private String user; |
||||
private String path; |
||||
private String space; |
||||
private String status; |
||||
private String remark; |
||||
|
||||
} |
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
package vip.xumy.picture.service; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
import java.util.UUID; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import vip.xumy.core.exception.CoreException; |
||||
import vip.xumy.core.utils.ImageType; |
||||
import vip.xumy.picture.mapper.PictureMapper; |
||||
import vip.xumy.picture.pojo.Picture; |
||||
|
||||
/** |
||||
* Do not use for any commercial purposes without permission |
||||
* |
||||
* @author: mengyxu |
||||
* @date: 2021年12月31日 |
||||
*/ |
||||
|
||||
@Service |
||||
public class PictureService { |
||||
@Autowired |
||||
private PictureMapper pictureMapper; |
||||
|
||||
@Value("${picture.root.path}") |
||||
public void setRootPath(String path) { |
||||
if (path != null && path.endsWith("/")) { |
||||
this.rootPath = path; |
||||
} else { |
||||
this.rootPath = path + "/"; |
||||
} |
||||
} |
||||
|
||||
private String rootPath; |
||||
|
||||
public List<Picture> list(Picture example) { |
||||
return pictureMapper.list(example); |
||||
} |
||||
|
||||
public Picture save(MultipartFile file, String user) throws CoreException { |
||||
byte[] data; |
||||
try { |
||||
data = file.getBytes(); |
||||
} catch (IOException e) { |
||||
throw new CoreException("图片上传失败"); |
||||
} |
||||
ImageType type = ImageType.getImageType(data); |
||||
if (type == null) { |
||||
throw new CoreException("未知的图片类型"); |
||||
} |
||||
String uuid = UUID.randomUUID().toString(); |
||||
String path = uuid.replace("-", "/") + "." + type.getType(); |
||||
writeToFile(path, data); |
||||
Picture picture = new Picture(); |
||||
picture.setUser(user); |
||||
picture.setId(uuid.replace("-", "")); |
||||
picture.setPath(path); |
||||
picture.setStatus("0"); |
||||
picture.setSpace(Math.ceil(data.length * 1.0 / 1024) + "KB"); |
||||
pictureMapper.save(picture); |
||||
return picture; |
||||
} |
||||
|
||||
private void writeToFile(String path, byte[] data) throws CoreException { |
||||
File file = new File(rootPath + path); |
||||
File parent = file.getParentFile(); |
||||
if (!parent.exists()) { |
||||
file.mkdirs(); |
||||
} |
||||
try (FileOutputStream fos = new FileOutputStream(file)) { |
||||
fos.write(data); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
file.delete(); |
||||
deleteEmptyDir(parent); |
||||
throw new CoreException("图片保存失败"); |
||||
} |
||||
} |
||||
|
||||
public void update(Picture picture) { |
||||
pictureMapper.update(picture); |
||||
} |
||||
|
||||
public void delete(Picture picture) { |
||||
deleteFile(picture.getPath()); |
||||
pictureMapper.delete(picture.getId()); |
||||
} |
||||
|
||||
private void deleteFile(String path) { |
||||
File file = new File(rootPath + path); |
||||
file.deleteOnExit(); |
||||
deleteEmptyDir(file.getParentFile()); |
||||
} |
||||
|
||||
private void deleteEmptyDir(File dir) { |
||||
if (!dir.exists() || !dir.isDirectory()) { |
||||
return; |
||||
} |
||||
if (dir.list().length == 0) { |
||||
dir.delete(); |
||||
deleteEmptyDir(dir.getParentFile()); |
||||
} |
||||
} |
||||
|
||||
public void deleteAll(String user) { |
||||
pictureMapper.deleteAll(user); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
[*.{js,jsx,ts,tsx,vue}] |
||||
indent_style = space |
||||
indent_size = 2 |
||||
trim_trailing_whitespace = true |
||||
insert_final_newline = true |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
NODE_ENV="development" |
||||
VUE_APP_BASE_URL="localhost" |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
NODE_ENV="preview" |
||||
VUE_APP_BASE_URL="" |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
NODE_ENV="production" |
||||
VUE_APP_BASE_URL="" |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
NODE_ENV="test" |
||||
VUE_APP_BASE_URL="" |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
.DS_Store |
||||
node_modules |
||||
/dist |
||||
|
||||
# local env files |
||||
.env.local |
||||
.env.*.local |
||||
|
||||
# Log files |
||||
npm-debug.log* |
||||
yarn-debug.log* |
||||
yarn-error.log* |
||||
pnpm-debug.log* |
||||
|
||||
# Editor directories and files |
||||
.idea |
||||
.vscode |
||||
*.suo |
||||
*.ntvs* |
||||
*.njsproj |
||||
*.sln |
||||
*.sw? |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
# monitor-vue |
||||
|
||||
## Project setup |
||||
``` |
||||
yarn install |
||||
``` |
||||
|
||||
### Compiles and hot-reloads for development |
||||
``` |
||||
yarn serve |
||||
``` |
||||
|
||||
### Compiles and minifies for production |
||||
``` |
||||
yarn build |
||||
``` |
||||
|
||||
### Lints and fixes files |
||||
``` |
||||
yarn lint |
||||
``` |
||||
|
||||
### Customize configuration |
||||
See [Configuration Reference](https://cli.vuejs.org/config/). |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
module.exports = { |
||||
presets: [ |
||||
'@vue/cli-plugin-babel/preset' |
||||
] |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
[1105/164547.236:ERROR:directory_reader_win.cc(43)] FindFirstFile: 系统找不到指定的路径。 (0x3) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
{ |
||||
"name": "picture", |
||||
"version": "0.1.0", |
||||
"private": true, |
||||
"scripts": { |
||||
"dev": "vue-cli-service serve", |
||||
"build": "vue-cli-service build --mode production", |
||||
"lint": "vue-cli-service lint", |
||||
"preview": "vue-cli-service build --mode preview", |
||||
"test": "vue-cli-service build --mode test" |
||||
}, |
||||
"dependencies": { |
||||
"core-js": "^3.6.5", |
||||
"vue": "^2.6.11", |
||||
"vue-class-component": "^7.2.3", |
||||
"vue-property-decorator": "^8.4.2", |
||||
"vue-router": "^3.2.0", |
||||
"vuex": "^3.4.0" |
||||
}, |
||||
"devDependencies": { |
||||
"@babel/core": "^7.10.5", |
||||
"@typescript-eslint/eslint-plugin": "^2.33.0", |
||||
"@typescript-eslint/parser": "^2.33.0", |
||||
"@vue/cli-plugin-babel": "^4.4.0", |
||||
"@vue/cli-plugin-eslint": "^4.4.0", |
||||
"@vue/cli-plugin-router": "^4.4.6", |
||||
"@vue/cli-plugin-typescript": "^4.4.0", |
||||
"@vue/cli-plugin-vuex": "^4.4.6", |
||||
"@vue/cli-service": "^4.4.0", |
||||
"@vue/eslint-config-standard": "^5.1.2", |
||||
"@vue/eslint-config-typescript": "^5.0.2", |
||||
"axios": "^0.19.2", |
||||
"babel-loader": "^8.1.0", |
||||
"cache-loader": "^4.1.0", |
||||
"element-ui": "^2.15.6", |
||||
"eslint": "^6.7.2", |
||||
"eslint-plugin-import": "^2.20.2", |
||||
"eslint-plugin-node": "^11.1.0", |
||||
"eslint-plugin-promise": "^4.2.1", |
||||
"eslint-plugin-standard": "^4.0.0", |
||||
"eslint-plugin-vue": "^6.2.2", |
||||
"js-md5": "^0.7.3", |
||||
"node-sass": "^4.14.1", |
||||
"sass-loader": "^9.0.2", |
||||
"typescript": "~3.9.3", |
||||
"vue-cli-plugin-axios": "^0.0.4", |
||||
"vue-cli-plugin-element": "^1.0.1", |
||||
"vue-clipboard2": "^0.3.1", |
||||
"vue-template-compiler": "^2.6.11" |
||||
}, |
||||
"eslintConfig": { |
||||
"root": true, |
||||
"env": { |
||||
"node": true |
||||
}, |
||||
"extends": [ |
||||
"plugin:vue/recommended", |
||||
"@vue/standard", |
||||
"@vue/typescript/recommended" |
||||
], |
||||
"parserOptions": { |
||||
"ecmaVersion": 2020 |
||||
} |
||||
}, |
||||
"browserslist": [ |
||||
"> 1%", |
||||
"last 2 versions", |
||||
"not dead" |
||||
] |
||||
} |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
<!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>图床卅</title> |
||||
</head> |
||||
<body style="margin: 0px;"> |
||||
<noscript> |
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> 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> |
After Width: | Height: | Size: 8.6 KiB |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
@charset "UTF-8"; |
||||
body{ |
||||
background-color: cadetblue; |
||||
} |
||||
|
||||
.app-head{ |
||||
background-color: #00ffff; |
||||
} |
||||
|
||||
.app-main{ |
||||
// background-color: #5500ff; |
||||
} |
||||
|
||||
.main-table{ |
||||
background-color: #409EFF; |
||||
} |
||||
|
||||
.el-empty__description p{ |
||||
color: black !important; |
||||
} |
||||
.el-table__empty-text{ |
||||
color: black !important; |
||||
} |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
@charset "UTF-8"; |
||||
.app-head{ |
||||
background-color: #E4E7ED; |
||||
} |
||||
|
||||
.app-main{ |
||||
background-color: #EBEEF5; |
||||
} |
||||
|
||||
.main-table{ |
||||
background-color: #F2F6FC; |
||||
} |
@ -0,0 +1,166 @@
@@ -0,0 +1,166 @@
|
||||
@charset "UTF-8"; |
||||
* { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
html, |
||||
body { |
||||
font-size: 14px; |
||||
font-family: "Microsoft YaHei"; |
||||
width: 100%; |
||||
height: 100%; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.el-header, .main-head, .main-table{ |
||||
padding: 0; |
||||
} |
||||
|
||||
// 公共样式文件 |
||||
// 带阴影的表格外的div |
||||
div.table-warpper { |
||||
margin: 0 2.5%; |
||||
padding: 0 0.5%; |
||||
border: 1px solid #20A0FF; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.tabs-header { |
||||
margin-left: 1em; |
||||
} |
||||
|
||||
.cur-table-warpper { |
||||
margin-left: -1em; |
||||
} |
||||
|
||||
// input[type=number]在ff和chrome中会出现上下的小三角箭头 |
||||
input::-webkit-outer-spin-button, |
||||
input::-webkit-inner-spin-button { |
||||
-webkit-appearance: none !important; |
||||
} |
||||
|
||||
input[type="number"] { |
||||
-moz-appearance: textfield; |
||||
} |
||||
|
||||
// 修改element |
||||
.el-picker-panel__link-btn { |
||||
display: none; |
||||
} |
||||
|
||||
.el-pagination__editor { |
||||
width: 55px !important; |
||||
} |
||||
|
||||
|
||||
.query-mini { |
||||
width: 100px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-smart { |
||||
width: 120px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-short { |
||||
width: 150px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-medium { |
||||
width: 200px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-long { |
||||
width: 250px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-tree { |
||||
width: 300px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-longest { |
||||
width: 350px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-400 { |
||||
width: 400px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-450 { |
||||
width: 450px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.query-500 { |
||||
width: 500px !important; |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
.modify-dialog .el-dialog { |
||||
background-color: #edf2f7; |
||||
} |
||||
|
||||
.form-title { |
||||
font-size: 18px; |
||||
background-color: cadetblue; |
||||
padding: 10px; |
||||
height: 25px; |
||||
font-weight: bold; |
||||
margin-bottom: 20px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.full-item-form .el-select, |
||||
.full-item-form .el-date-editor, |
||||
.full-item-form .el-autocomplete { |
||||
width: 100% !important; |
||||
} |
||||
|
||||
.dialog-footer { |
||||
text-align: right; |
||||
} |
||||
|
||||
.infomation-form .el-form-item { |
||||
margin-top: 20px; |
||||
font-size: 1.5rem; |
||||
} |
||||
|
||||
.infomation-form .el-input { |
||||
width: 350px; |
||||
margin-right: 20px; |
||||
} |
||||
|
||||
.infomation-form .el-input__inner { |
||||
background-color: #4472c4 !important; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
// 表格背景透明, 便于定制整体背景样式 |
||||
.main-table .el-table, |
||||
.el-table__expanded-cell { |
||||
background-color: transparent; |
||||
border: none; |
||||
} |
||||
|
||||
.main-table .el-table tr { |
||||
background-color: transparent !important; |
||||
border: none; |
||||
} |
||||
|
||||
.main-table .el-table--enable-row-transition .el-table__header td, |
||||
.el-table .cell { |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.main-table .el-table--enable-row-transition .el-table__body td, |
||||
.el-table .cell { |
||||
background-color: transparent; |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
@charset "UTF-8"; |
||||
.main-table .el-table td, .main-table .el-table th{ |
||||
padding: 9px 0px; |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
@charset "UTF-8"; |
||||
.main-table .el-table td, .main-table .el-table th{ |
||||
padding: 3px 0px; |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
@charset "UTF-8"; |
||||
.main-table .el-table td, .main-table .el-table th{ |
||||
padding: 5px 0px; |
||||
} |
@ -0,0 +1,182 @@
@@ -0,0 +1,182 @@
|
||||
<template> |
||||
<div id="header"> |
||||
<el-row> |
||||
<el-col :span="12"> |
||||
<el-row class="menu-row"> |
||||
<el-menu class="el-menu-demo" :default-active="activeGroup" mode="horizontal" text-color="#000" |
||||
active-text-color="#4669e7"> |
||||
<el-menu-item v-for="item in $store.state.menuGroups" :key="item.id" :index="item.id" |
||||
@click="clickGroup(item)"> |
||||
{{ item.name }} |
||||
</el-menu-item> |
||||
</el-menu> |
||||
<el-radio-group :size="$store.state.size" v-model="active"> |
||||
<el-radio-button v-for="item in menus" :label="item.id"> |
||||
{{ item.name }} |
||||
</el-radio-button> |
||||
</el-radio-group> |
||||
</el-row> |
||||
</el-col> |
||||
<el-col :span="12"> |
||||
<el-row class="info" type="flex" justify="end" align="middle"> |
||||
<el-button class="info-btn" icon="el-icon-user-solid" type="text"> |
||||
{{ $store.state.userInfo.userId }} |
||||
</el-button> |
||||
<el-button :size="$store.state.size" icon="el-icon-setting" type="info" @click="update = true"> |
||||
修改密码 |
||||
</el-button> |
||||
<el-button :size="$store.state.size" icon="el-icon-switch-button" type="info" |
||||
@click="$store.commit('logout')"> |
||||
注销登录 |
||||
</el-button> |
||||
</el-row> |
||||
</el-col> |
||||
</el-row> |
||||
|
||||
<el-dialog title="修改密码" :visible.sync="update" width="40%" top="15vh" :close-on-click-modal="false" |
||||
@keydown.enter.native="confirm()"> |
||||
<el-form ref="update" :model="user" :rules="rules" label-width="180px"> |
||||
<el-form-item label="旧密码" prop="password"> |
||||
<el-input type="password" v-model="user.password"></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="新密码" prop="newPwd"> |
||||
<el-input type="password" v-model="user.newPwd"></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="重复新密码" prop="rePwd"> |
||||
<el-input type="password" v-model="user.rePwd" autocomplete="off"></el-input> |
||||
</el-form-item> |
||||
</el-form> |
||||
<div slot="footer" class="dialog-footer"> |
||||
<el-button @click="update = false;"> 取 消 </el-button> |
||||
<el-button type="primary" @click="confrim"> 确 定 </el-button> |
||||
</div> |
||||
</el-dialog> |
||||
|
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Vue, |
||||
Component, |
||||
Prop, |
||||
Watch |
||||
} from 'vue-property-decorator'; |
||||
import md5 from 'js-md5'; |
||||
import { |
||||
password |
||||
} from '@/static/tool/validate.js'; |
||||
|
||||
@Component |
||||
export default class NavHeader extends Vue { |
||||
menus = []; |
||||
active = 'home'; |
||||
activeGroup = 'home'; |
||||
|
||||
update = false; |
||||
user = {}; |
||||
rules = { |
||||
password: [{ |
||||
required: true, |
||||
message: '请输入密码', |
||||
trigger: 'blur' |
||||
}], |
||||
newPwd: [{ |
||||
validator: password, |
||||
trigger: 'blur' |
||||
}], |
||||
rePwd: [{ |
||||
validator: this.reKey, |
||||
trigger: 'blur' |
||||
}] |
||||
}; |
||||
|
||||
clickGroup(group) { |
||||
this.activeGroup = group.id |
||||
this.menus = group.child |
||||
const child = group.child |
||||
if (child.length == 0) { |
||||
this.active = group.id |
||||
} else { |
||||
this.active = child[0].id |
||||
} |
||||
} |
||||
|
||||
clickMenu(id) { |
||||
this.active = id |
||||
} |
||||
|
||||
toHome() { |
||||
this.clickGroup(this.$store.state.menuGroups[0]); |
||||
} |
||||
|
||||
confrim() { |
||||
const that = this |
||||
this.$refs.update.validate((valid) => { |
||||
if (valid) { |
||||
const param = JSON.parse(JSON.stringify(that.user)); |
||||
param.userId = that.$store.state.userInfo.userId; |
||||
param.password = md5(param.password) |
||||
param.newPwd = md5(param.newPwd) |
||||
delete param.rePwd; |
||||
that.$post('public/update/password', param).then(rsp => { |
||||
if (rsp) { |
||||
that.update = false; |
||||
that.user = {}; |
||||
that.$store.commit('logout') |
||||
} |
||||
}); |
||||
} else { |
||||
return false |
||||
} |
||||
}); |
||||
} |
||||
|
||||
reKey(rule, value, callback) { |
||||
if (!value) { |
||||
callback(new Error('请重复输入新密码')); |
||||
} else if (value != this.user.newPwd) { |
||||
callback(new Error('两次输入的新密码不一致')); |
||||
} else { |
||||
callback(); |
||||
} |
||||
} |
||||
|
||||
@Watch('active') |
||||
activeChang(n, o) { |
||||
this.$router.push('/' + n) |
||||
} |
||||
|
||||
created() {} |
||||
mounted() {} // 生命周期 - 挂载完成(可以访问DOM元素 |
||||
beforeCreate() {} // 生命周期 - 创建之前 |
||||
beforeMount() {} // 生命周期 - 挂载之前 |
||||
beforeUpdate() {} // 生命周期 - 更新之前 |
||||
updated() {} // 生命周期 - 更新之后 |
||||
beforeDestroy() {} // 生命周期 - 销毁之前 |
||||
destroyed() {} // 生命周期 - 销毁完成 |
||||
activated() {} // 如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
.info { |
||||
/* background-color: cadetblue; */ |
||||
height: 80px; |
||||
padding-right: 100px; |
||||
} |
||||
|
||||
.el-menu.el-menu--horizontal { |
||||
border-bottom: none; |
||||
} |
||||
|
||||
.info-btn { |
||||
font-size: 17px; |
||||
color: #2D3748; |
||||
margin-left: 30px !important; |
||||
} |
||||
|
||||
.menu-row { |
||||
background-color: #FFFFFF; |
||||
padding-left: 30px; |
||||
} |
||||
</style> |
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
<template> |
||||
<div id="mainHeader" class="main-head" :style="{ height: $store.state.sizes.mainHead }"> |
||||
<el-row> |
||||
<el-col :span="8" v-if="flag.title"> |
||||
<slot name="title"></slot> |
||||
</el-col> |
||||
<el-col :span="flag.title ? 16 : 24"> |
||||
<el-row type="flex" justify="end"> |
||||
<span v-for="term in terms"> |
||||
<el-date-picker :size="$store.state.size" v-if="term.datePicker" v-model="example[term.code]" |
||||
:value-format="term.valueFormat" :type="term.type" :class="term.claze ? term.claze : 'query-medium'" |
||||
:placeholder="term.desc"></el-date-picker> |
||||
<el-select :size="$store.state.size" v-if="term.dict" v-model="example[term.code]" |
||||
:class="term.claze ? term.claze : 'query-medium'" :placeholder="term.desc" :filterable="term.filterable" |
||||
clearable> |
||||
<el-option v-for="(val, key, i) in $store.state.dict[term.dict]" :key="key" :value="key" :label="val" /> |
||||
</el-select> |
||||
<el-input :size="$store.state.size" v-if="!term.datePicker && !term.dict" v-model="example[term.code]" |
||||
:class="term.claze ? term.claze : 'query-medium'" :placeholder="term.desc" clearable /> |
||||
</span> |
||||
<el-button :size="$store.state.size" type="primary" icon="el-icon-search" @click="$emit('query')" |
||||
v-if="flag.list"> 查询 |
||||
</el-button> |
||||
<el-button :size="$store.state.size" type="success" icon="el-icon-plus" @click="add()" v-if="flag.save"> |
||||
添加{{name}} |
||||
</el-button> |
||||
<slot name="header"></slot> |
||||
</el-row> |
||||
</el-col> |
||||
</el-row> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Vue, |
||||
Component, |
||||
Prop |
||||
} from "vue-property-decorator"; |
||||
|
||||
@Component |
||||
export default class MainHeader extends Vue { |
||||
@Prop({ |
||||
type: String |
||||
}) name; |
||||
|
||||
@Prop({ |
||||
type: Object |
||||
}) flag; |
||||
|
||||
@Prop({ |
||||
type: Array |
||||
}) terms; |
||||
|
||||
@Prop({ |
||||
type: Object |
||||
}) example; |
||||
|
||||
created() {} //生命周期 - 创建完成(可以访问当前this实例) |
||||
mounted() {} //生命周期 - 挂载完成(可以访问DOM元素) |
||||
beforeCreate() {} //生命周期 - 创建之前 |
||||
beforeMount() {} //生命周期 - 挂载之前 |
||||
beforeUpdate() {} //生命周期 - 更新之前 |
||||
updated() {} //生命周期 - 更新之后 |
||||
beforeDestroy() {} //生命周期 - 销毁之前 |
||||
destroyed() {} //生命周期 - 销毁完成 |
||||
activated() {} //如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
|
||||
</style> |
@ -0,0 +1,267 @@
@@ -0,0 +1,267 @@
|
||||
<template> |
||||
<div id="mamageTemp"> |
||||
<MainHead :name="name" :flag="flag" :terms="terms" :example="example" @query="query(1)"></MainHead> |
||||
<!-- <el-row class="main-head" :style="{ height: $store.state.sizes.mainHead }"> |
||||
<el-row type="flex" justify="end"> |
||||
<span v-for="term in terms"> |
||||
<el-date-picker :size="$store.state.size" v-if="term.datePicker" v-model="example[term.code]" |
||||
:value-format="term.valueFormat" :type="term.type" :class="term.claze ? term.claze : 'query-medium'" |
||||
:placeholder="term.desc"></el-date-picker> |
||||
<el-select :size="$store.state.size" v-if="term.dict" v-model="example[term.code]" |
||||
:class="term.claze ? term.claze : 'query-medium'" :placeholder="term.desc" :filterable="term.filterable" |
||||
clearable> |
||||
<el-option v-for="(val, key, i) in $store.state.dict[term.dict]" :key="key" :value="key" :label="val" /> |
||||
</el-select> |
||||
<el-input :size="$store.state.size" v-if="!term.datePicker && !term.dict" v-model="example[term.code]" |
||||
:class="term.claze ? term.claze : 'query-medium'" :placeholder="term.desc" clearable /> |
||||
</span> |
||||
<el-button :size="$store.state.size" type="primary" icon="el-icon-search" @click="query(1)" v-if="flag.list"> 查询 |
||||
</el-button> |
||||
<el-button :size="$store.state.size" type="success" icon="el-icon-plus" @click="add()" v-if="flag.save"> |
||||
添加{{name}} |
||||
</el-button> |
||||
<slot name="header"></slot> |
||||
</el-row> |
||||
</el-row> --> |
||||
<el-row class="main-table"> |
||||
<el-table :data="result.rows" :height="tableHeight ? tableHeight : $store.state.sizes.pTableHei" border> |
||||
<el-table-column v-for="prop in props" v-if="!prop.tableHide" :prop="prop.code" :label="prop.name" |
||||
:min-width="prop.width" :width="prop.type ? prop.width : ''" :type="prop.type" |
||||
:formatter="(row,column,value) => getValue(prop.dict,value)" show-overflow-tooltip> |
||||
</el-table-column> |
||||
<el-table-column v-if="flag.update || flag.del || actions" label="操作" :width="actionWidth" fixed="right"> |
||||
<template slot-scope="scope" v-if="!stateProp || scope.row[stateProp] != 'R'"> |
||||
<el-button v-if="flag.update" size="mini" type="primary" @click="modify(scope.row)"> 修改 </el-button> |
||||
<el-button v-if="flag.del" size="mini" type="danger" @click="delate(scope.row)"> 删除 </el-button> |
||||
<el-button v-for="action in actions" size="mini" :type="action.type" @click="$emit(action.emit,scope.row)"> |
||||
{{action.name}} |
||||
</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<el-pagination :current-page="example.page" :page-sizes="[10, 20, 50, 100]" :page-size="example.size" |
||||
layout="total, sizes, prev, pager, next, jumper" :total="result.total" @size-change="handleSizeChange" |
||||
@current-change="handleCurrentChange" /> |
||||
</el-row> |
||||
|
||||
<el-dialog append-to-body :title="(flag.add ? '添加':'修改') + name" :visible.sync="flag.modify" |
||||
:close-on-click-modal="false" top="15vh" :width="props.length > 8 ? '60%' : '40%'" |
||||
@keydown.enter.native="confirm()"> |
||||
<el-form ref="update" class="full-item-form" label-width="180px" :rules="rules" :model="param"> |
||||
<el-row v-if="props.length > 8"> |
||||
<el-col :span="12" v-for="prop in props"> |
||||
<ModifyItem :prop="prop" :flag="flag" :param="param"></ModifyItem> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row v-else> |
||||
<span v-for="prop in props"> |
||||
<ModifyItem :prop="prop" :flag="flag" :param="param"></ModifyItem> |
||||
</span> |
||||
</el-row> |
||||
</el-form> |
||||
<div slot="footer" class="dialog-footer"> |
||||
<el-button @click="flag.modify = false"> 取消 </el-button> |
||||
<el-button type="primary" @click="confirm"> 确认 </el-button> |
||||
</div> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Vue, |
||||
Component, |
||||
Prop, |
||||
Watch |
||||
} from 'vue-property-decorator'; |
||||
import ModifyItem from './modifyItem.vue'; |
||||
import MainHead from './mainHeader.vue'; |
||||
|
||||
@Component({ |
||||
components: { |
||||
ModifyItem, |
||||
MainHead |
||||
} |
||||
}) |
||||
export default class MamageTemp extends Vue { |
||||
@Prop({ |
||||
type: String |
||||
}) name; |
||||
|
||||
@Prop({ |
||||
type: String |
||||
}) url; |
||||
|
||||
@Prop({ |
||||
type: Object, |
||||
}) flag; |
||||
|
||||
@Prop({ |
||||
type: Array |
||||
}) terms; |
||||
|
||||
@Prop({ |
||||
type: Array |
||||
}) props; |
||||
|
||||
@Prop({ |
||||
type: Array |
||||
}) actions; |
||||
|
||||
@Prop({ |
||||
type: Object |
||||
}) rules; |
||||
|
||||
@Prop({ |
||||
type: String |
||||
}) stateProp; |
||||
|
||||
@Prop({ |
||||
type: String |
||||
}) size; |
||||
|
||||
@Prop({ |
||||
type: Number |
||||
}) tableHeight; |
||||
|
||||
actionWidth = 30; |
||||
example = { |
||||
page: 1, |
||||
size: 20 |
||||
}; |
||||
result = { |
||||
rows: [], |
||||
total: 0 |
||||
}; |
||||
param = {}; |
||||
|
||||
handleSizeChange(val) { |
||||
this.example.size = val |
||||
this.query() |
||||
} |
||||
handleCurrentChange(val) { |
||||
this.example.page = val |
||||
this.query() |
||||
} |
||||
query(page) { |
||||
const that = this |
||||
if (page != null) { |
||||
this.example.page = page |
||||
} |
||||
this.$get(that.url, that.example).then(function(response) { |
||||
if (response) { |
||||
that.result = response |
||||
} else { |
||||
that.result = { |
||||
rows: [], |
||||
total: 0 |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
add() { |
||||
if (this.$refs.update != null) { |
||||
this.$refs.update.clearValidate() |
||||
} |
||||
this.param = {}; |
||||
this.flag.add = true |
||||
this.flag.modify = true |
||||
} |
||||
modify(row) { |
||||
if (this.$refs.update != null) { |
||||
this.$refs.update.clearValidate() |
||||
} |
||||
this.flag.add = false |
||||
this.param = JSON.parse(JSON.stringify(row)) |
||||
this.flag.modify = true |
||||
} |
||||
|
||||
delate(row) { |
||||
const that = this |
||||
const msg = this.name ? this.name : "记录" |
||||
this.$confirm('确定要删除该' + msg + '吗?', '提示', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$delete(that.url, row).then(function(response) { |
||||
if (response) { |
||||
that.query() |
||||
that.$emit('change'); |
||||
} |
||||
}) |
||||
}).catch(() => { |
||||
that.showMessage('info', '已取消删除') |
||||
}) |
||||
} |
||||
|
||||
confirm() { |
||||
const that = this |
||||
this.$refs.update.validate((valid) => { |
||||
if (valid) { |
||||
const method = that.flag.add ? that.$post : that.$put; |
||||
method(that.url, that.param).then(function(response) { |
||||
if (response) { |
||||
that.query() |
||||
that.flag.modify = false |
||||
that.$emit('change'); |
||||
} |
||||
}) |
||||
} else { |
||||
return false |
||||
} |
||||
}) |
||||
} |
||||
|
||||
getValue(dictKey, value) { |
||||
if (!dictKey) { |
||||
return value; |
||||
} |
||||
const dict = this.$store.state.dict[dictKey] |
||||
if (dict == null) { |
||||
return value; |
||||
} |
||||
return dict[value] == null ? value : dict[value] |
||||
} |
||||
|
||||
created() { |
||||
this.$set(this.flag, 'add', false); |
||||
this.$set(this.flag, 'modify', false); |
||||
this.query(); |
||||
if (this.flag.update) { |
||||
this.actionWidth += 60; |
||||
} |
||||
if (this.flag.del) { |
||||
this.actionWidth += 60; |
||||
} |
||||
const that = this; |
||||
if (this.actions) { |
||||
this.actions.forEach(i => { |
||||
that.actionWidth += i.width; |
||||
}) |
||||
} |
||||
} |
||||
|
||||
@Watch('flag.modify') |
||||
modifyChang(n, o) { |
||||
if (!n) { |
||||
this.param = {}; |
||||
} |
||||
} |
||||
|
||||
mounted() {} // 生命周期 - 挂载完成(可以访问DOM元素) |
||||
beforeCreate() {} // 生命周期 - 创建之前 |
||||
beforeMount() {} // 生命周期 - 挂载之前 |
||||
beforeUpdate() {} // 生命周期 - 更新之前 |
||||
updated() {} // 生命周期 - 更新之后 |
||||
beforeDestroy() {} // 生命周期 - 销毁之前 |
||||
destroyed() {} // 生命周期 - 销毁完成 |
||||
activated() {} // 如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
/* #mamageTemp { |
||||
padding: 20px 20px 0px 20px; |
||||
} */ |
||||
</style> |
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
<template> |
||||
<div id="modifyItem"> |
||||
<!-- <el-form-item :label="prop.name" :prop="prop.code" v-if="!prop.hide && (!prop.addHide || !flag.add)"> --> |
||||
<el-form-item :label="prop.name" :prop="prop.code" |
||||
v-if="!(prop.hide || (flag.add && prop.addHide) || (!flag.add && prop.modifyHide))"> |
||||
<el-select v-if="prop.dict" v-model="param[prop.code]" :disabled="!flag.add && prop.readOnly" filterable |
||||
:placeholder="'请选择'+prop.name" clearable> |
||||
<el-option v-if="prop.dict == 'order'" v-for="index in 99" :key="index" :value="index+''" :label="index" /> |
||||
<el-option v-if="prop.dict != 'order'" v-for="(val, key, i) in $store.state.dict[prop.dict]" :key="key" |
||||
:value="prop.int ? parseInt(key):key+''" :label="val" /> |
||||
</el-select> |
||||
<el-select v-if="prop.state" :multiple="prop.multiple" v-model="param[prop.code]" |
||||
:disabled="!flag.add && prop.readOnly" :placeholder="'请选择'+prop.name" filterable clearable> |
||||
<el-option v-for="item in $store.state[prop.state]" :key="item.key" :value="item.key" :label="item.value" /> |
||||
</el-select> |
||||
<el-autocomplete v-if="prop.autocomplete" v-model="param[prop.code]" :fetch-suggestions="prop.getData" onKeypress="return(event.keyCode != 32)" |
||||
:placeholder="'请输入'+prop.name" clearable> |
||||
<template slot-scope="{ item }"> |
||||
<div>{{ item.value + '--' + item[prop.labelKey] }}</div> |
||||
</template> |
||||
</el-autocomplete> |
||||
<el-input v-if="!prop.dict && !prop.state && !prop.autocomplete" v-model="param[prop.code]" onKeypress="return(event.keyCode != 32)" |
||||
:disabled="!flag.add && prop.readOnly" :placeholder="prop.desc ? prop.desc : '请输入'+prop.name" clearable /> |
||||
</el-form-item> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Vue, |
||||
Component, |
||||
Prop |
||||
} from "vue-property-decorator"; |
||||
|
||||
@Component |
||||
export default class ModifyItem extends Vue { |
||||
@Prop({ |
||||
type: Object |
||||
}) prop; |
||||
|
||||
@Prop({ |
||||
type: Object |
||||
}) flag; |
||||
|
||||
@Prop({ |
||||
type: Object |
||||
}) param; |
||||
|
||||
created() {} //生命周期 - 创建完成(可以访问当前this实例) |
||||
mounted() {} //生命周期 - 挂载完成(可以访问DOM元素) |
||||
beforeCreate() {} //生命周期 - 创建之前 |
||||
beforeMount() {} //生命周期 - 挂载之前 |
||||
beforeUpdate() {} //生命周期 - 更新之前 |
||||
updated() {} //生命周期 - 更新之后 |
||||
beforeDestroy() {} //生命周期 - 销毁之前 |
||||
destroyed() {} //生命周期 - 销毁完成 |
||||
activated() {} //如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
|
||||
</style> |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
import Vue from 'vue' |
||||
import './static/plugins/axios' |
||||
import App from './views/main/App.vue' |
||||
import './static/plugins/element' |
||||
import router from './router' |
||||
import store from './store' |
||||
import VueClipboard from 'vue-clipboard2' |
||||
|
||||
Vue.config.productionTip = false |
||||
Vue.use(VueClipboard) |
||||
|
||||
const vue = new Vue({ |
||||
router, |
||||
store, |
||||
render: h => h(App) |
||||
}).$mount('#app') |
||||
export default vue |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
import Vue from 'vue' |
||||
import VueRouter, { RouteConfig } from 'vue-router' |
||||
|
||||
Vue.use(VueRouter) |
||||
|
||||
const routes: Array<RouteConfig> = [ |
||||
{ |
||||
path: '/', |
||||
redirect: '/home' |
||||
},{ |
||||
path: '/home', |
||||
name: 'home', |
||||
component: () => import('../views/biz/picture.vue') |
||||
},{ |
||||
path: '/login', |
||||
name: 'Login', |
||||
component: () => import('../views/main/login.vue') |
||||
},{ |
||||
path: '/config', |
||||
name: 'Config', |
||||
component: () => import('../views/sys/config.vue') |
||||
} |
||||
] |
||||
|
||||
const originalPush = VueRouter.prototype.push |
||||
VueRouter.prototype.push = function push (location) { |
||||
return originalPush.call(this, location).catch(err => err) |
||||
} |
||||
|
||||
const router = new VueRouter({ |
||||
routes |
||||
}) |
||||
|
||||
router.afterEach((to, from) => { |
||||
// ...
|
||||
}) |
||||
export default router |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
import Vue, { VNode } from 'vue' |
||||
|
||||
declare global { |
||||
namespace JSX { |
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {} |
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {} |
||||
interface IntrinsicElements { |
||||
[elem: string]: any; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
declare module '*.vue' { |
||||
import Vue from 'vue' |
||||
export default Vue |
||||
} |
@ -0,0 +1,289 @@
@@ -0,0 +1,289 @@
|
||||
/* eslint-disable */ |
||||
import Vue from "vue"; |
||||
import { Message } from "element-ui"; |
||||
import axios from "axios"; |
||||
import store from "@/store"; |
||||
import loading from "./element" |
||||
|
||||
const config = { |
||||
// baseURL: process.env.VUE_APP_BASE_URL || process.env.apiUrl || "",
|
||||
baseURL: process.env.VUE_APP_BASE_URL ? "/api" : "", |
||||
timeout: 60 * 1000, |
||||
withCredentials: true // Check cross-site Access-Control
|
||||
}; |
||||
|
||||
|
||||
const _axios = axios.create(config); |
||||
let curMsg: any; |
||||
|
||||
// Add a request interceptor
|
||||
_axios.interceptors.request.use( |
||||
function(config) { |
||||
const time = new Date().getTime().toString(); |
||||
if(config.params){ |
||||
delEmpty(config.params); |
||||
config.params.t = time; |
||||
} |
||||
if (config.data && typeof config.data === Object) { |
||||
delEmpty(config.params); |
||||
config.data.t = time; |
||||
} |
||||
return config; |
||||
}, |
||||
function(error) { |
||||
return Promise.reject(error); |
||||
} |
||||
); |
||||
|
||||
function delEmpty(data){ |
||||
if(data){ |
||||
for (const item in data) { |
||||
if (data.hasOwnProperty(item)) { |
||||
const val = data[item]; |
||||
if ((val == null || val == "null" || val == "") && val !== 0) { |
||||
delete data[item]; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Add a response interceptor
|
||||
_axios.interceptors.response.use( |
||||
function(response) { |
||||
if (!response.data.message) { |
||||
return { success: true, data: response.data }; |
||||
} |
||||
return response.data; |
||||
}, |
||||
function(error) { |
||||
return Promise.reject(error); |
||||
} |
||||
); |
||||
|
||||
function post(url, data = {}, noMsg, noLoading) { |
||||
return new Promise((resolve, reject) => { |
||||
if(!noLoading){ |
||||
loading.start(); |
||||
} |
||||
_axios.post(url, data).then( |
||||
(response: any) => { |
||||
handResponse(response, resolve, noMsg, noLoading); |
||||
}, |
||||
err => { |
||||
handError(err, reject, noMsg, noLoading); |
||||
} |
||||
); |
||||
}); |
||||
} |
||||
|
||||
function get(url, data = {}, noMsg, noLoading) { |
||||
return new Promise((resolve, reject) => { |
||||
if(!noLoading){ |
||||
loading.start(); |
||||
} |
||||
_axios.get(url, {params:data}).then( |
||||
(response: any) => { |
||||
handResponse(response, resolve, noMsg, noLoading); |
||||
}, |
||||
err => { |
||||
handError(err, reject, noMsg, noLoading); |
||||
} |
||||
); |
||||
}); |
||||
} |
||||
|
||||
function put(url, data = {}, noMsg, noLoading) { |
||||
return new Promise((resolve, reject) => { |
||||
if(!noLoading){ |
||||
loading.start(); |
||||
} |
||||
console.log(url); |
||||
_axios.put(url, data).then( |
||||
(response: any) => { |
||||
handResponse(response, resolve, noMsg, noLoading); |
||||
}, |
||||
err => { |
||||
handError(err, reject, noMsg, noLoading); |
||||
} |
||||
); |
||||
}); |
||||
} |
||||
|
||||
function delate(url, data = {}, noMsg, noLoading) { |
||||
return new Promise((resolve, reject) => { |
||||
if(!noLoading){ |
||||
loading.start(); |
||||
} |
||||
_axios({ |
||||
method: 'delete', |
||||
url: url, |
||||
data: data |
||||
}).then( |
||||
(response: any) => { |
||||
handResponse(response, resolve, noMsg, noLoading); |
||||
}, |
||||
err => { |
||||
handError(err, reject, noMsg, noLoading); |
||||
} |
||||
); |
||||
}); |
||||
} |
||||
|
||||
function handResponse(response, resolve, noMsg, noLoading){ |
||||
if(!noLoading){ |
||||
loading.stop(); |
||||
} |
||||
if (response.success) { |
||||
if (response.message) { |
||||
showMessage("success", response.message, false, noMsg); |
||||
resolve(true); |
||||
} else { |
||||
resolve(response.data); |
||||
} |
||||
} else { |
||||
if (response.message == "session timeout") { |
||||
store.commit("logout"); |
||||
} |
||||
if (response.message == "no permission") { |
||||
response.message = "您暂无权访问,请联系管理员添加"; |
||||
} |
||||
if (response.message.indexOf("no permission for ") == 0) { |
||||
response.message = "此权限尚未开放,请勿越权访问"; |
||||
} |
||||
showMessage("error", response.message, false, noMsg); |
||||
console.log(response.error); |
||||
resolve(false); |
||||
} |
||||
} |
||||
|
||||
function handError(err, reject, noMsg, noLoading){ |
||||
if(!noLoading){ |
||||
loading.stop(); |
||||
} |
||||
showMessage("error", "后台连接失败,网络异常!", false, noMsg); |
||||
reject(err); |
||||
} |
||||
|
||||
function upload(file, url){ |
||||
return new Promise((resolve, reject) => { |
||||
let param = new FormData() // 创建form对象
|
||||
param.append('file', file) // 通过append向form对象添加数据
|
||||
param.append('chunk', '0') // 添加form表单中其他数据
|
||||
let config = { |
||||
headers: {'Content-Type': 'multipart/form-data'} |
||||
} |
||||
_axios.post(url, param, config).then( |
||||
response => { |
||||
handResponse(response, resolve, false, false); |
||||
}, |
||||
err => { |
||||
handError(err, reject, false, false); |
||||
} |
||||
); |
||||
}); |
||||
} |
||||
|
||||
function download(fileName, url, data = {}, callBack) { |
||||
loading.start(); |
||||
_axios({ |
||||
method: "post", |
||||
url: url, // 请求地址
|
||||
data: data, // 参数
|
||||
responseType: "blob" // 表明返回服务器返回的数据类型
|
||||
}).then( |
||||
response => { |
||||
loading.stop(); |
||||
const data = response.data; |
||||
const reader = new FileReader() as any; |
||||
reader.readAsText(data); |
||||
reader.onload = function() { |
||||
try { |
||||
const result = JSON.parse(reader.result); |
||||
if (typeof result === "object") { |
||||
showMessage("error", result.message, false, false); |
||||
if (callBack != null) { |
||||
callBack(false); |
||||
} |
||||
return; |
||||
} |
||||
} catch (err) {} |
||||
const blob = new Blob([data], { |
||||
type: "application/vnd.ms-excel" |
||||
}); |
||||
if (window.navigator.msSaveOrOpenBlob) { |
||||
navigator.msSaveBlob(blob, fileName); |
||||
} else { |
||||
const link = document.createElement("a"); |
||||
link.href = window.URL.createObjectURL(blob); |
||||
link.download = fileName; |
||||
link.click(); |
||||
window.URL.revokeObjectURL(link.href); |
||||
} |
||||
if (callBack != null) { |
||||
callBack(true); |
||||
} |
||||
}; |
||||
}, |
||||
err => { |
||||
loading.stop(); |
||||
showMessage("error", "下载失败,网络异常!", false, false); |
||||
if (callBack != null) { |
||||
callBack(false); |
||||
} |
||||
} |
||||
); |
||||
} |
||||
|
||||
function showMessage(type, info, unClose, noMsg) { |
||||
const vue = Vue as any; |
||||
if (noMsg) { |
||||
return; |
||||
} |
||||
if (curMsg != null) { |
||||
curMsg.close(); |
||||
} |
||||
const tmp = Message({ |
||||
type: type, |
||||
showClose: true, |
||||
message: info, |
||||
duration: 3000 |
||||
}); |
||||
if (!unClose) { |
||||
curMsg = tmp; |
||||
} |
||||
} |
||||
|
||||
function showNotify(type, title, message, position) { |
||||
const vue = Vue as any; |
||||
if (position == null) { |
||||
position = "top-right"; |
||||
} |
||||
vue.$notify({ |
||||
title: title, |
||||
type: type, |
||||
message: message, |
||||
position: position, |
||||
duration: 0 |
||||
}); |
||||
} |
||||
|
||||
Vue.prototype.$post = post; |
||||
Vue.prototype.$get = get; |
||||
Vue.prototype.$put = put; |
||||
Vue.prototype.$delete = delate; |
||||
Vue.prototype.$upload = upload; |
||||
Vue.prototype.$download = download; |
||||
Vue.prototype.$showMessage = showMessage; |
||||
Vue.prototype.$showNotify = showNotify; |
||||
|
||||
export default { |
||||
post, |
||||
get, |
||||
put, |
||||
delate, |
||||
upload, |
||||
download, |
||||
showMessage, |
||||
showNotify |
||||
} |
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
import Vue from 'vue' |
||||
import Element from 'element-ui' |
||||
import 'element-ui/lib/theme-chalk/index.css' |
||||
|
||||
let count = 0 |
||||
let ld = null |
||||
|
||||
const start = () => { |
||||
if (count === 0) { |
||||
ld = Element.Loading.service({ |
||||
lock: true, |
||||
text: 'Loading', |
||||
spinner: 'el-icon-loading', |
||||
background: 'rgba(0, 0, 0, 0.3)' |
||||
}) |
||||
} |
||||
count++ |
||||
} |
||||
|
||||
const stop = () => { |
||||
if (count <= 0) { |
||||
return |
||||
} |
||||
count-- |
||||
if (count === 0) { |
||||
ld.close() |
||||
} |
||||
} |
||||
Vue.prototype.$start = start |
||||
Vue.prototype.$stop = stop |
||||
Vue.use(Element) |
||||
|
||||
const icons = [ |
||||
'el-icon-s-platform', 'el-icon-user-solid', 'el-icon-user', 'el-icon-unlock', 'el-icon-notebook-2', 'el-icon-school', |
||||
'el-icon-check', 'el-icon-video-play', 'el-icon-s-tools', 'el-icon-setting', 'el-icon-message-solid', 'el-icon-bell', |
||||
'el-icon-mobile-phone', 'el-icon-map-location', 'el-icon-location', 'el-icon-document', 'el-icon-s-check', 'el-icon-data-analysis', |
||||
'el-icon-view', 'el-icon-s-home', 'el-icon-office-building', 'el-icon-picture', 'el-icon-odometer', 'el-icon-s-data', |
||||
'el-icon-tickets', 'el-icon-delete-solid', 'el-icon-phone-outline', 'el-icon-phone', 'el-icon-star-on', 'el-icon-star-off', |
||||
'el-icon-warning', 'el-icon-upload', 'el-icon-download', 'el-icon-s-custom', 'el-icon-house', 'el-icon-message', 'el-icon-thumb', |
||||
'el-icon-search', 'el-icon-collection' |
||||
] |
||||
|
||||
export default { |
||||
start, |
||||
stop, |
||||
icons |
||||
} |
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
import store from "@/store"; |
||||
import {showMessage} from "./axios"; |
||||
let websock = null; |
||||
let onMessage = ""; |
||||
let connect = false; |
||||
|
||||
function init(url, cb) { |
||||
if (typeof(WebSocket) === "undefined") { |
||||
showMessage("error", "您的浏览器不支持socket"); |
||||
return; |
||||
} |
||||
onMessage = cb; |
||||
websock = new WebSocket(url); |
||||
websock.onopen = websockOpen; |
||||
websock.onclose = websockClose; |
||||
websock.onerror = websockError; |
||||
websock.onmessage = websockMessage; |
||||
} |
||||
|
||||
function send(msg) { |
||||
if (websock == null || !connect) { |
||||
setTimeout(() => send(msg), 500) |
||||
}else{ |
||||
websock.send(JSON.stringify(msg)); |
||||
} |
||||
} |
||||
|
||||
function close(){ |
||||
if(websock){ |
||||
websock.close(); |
||||
} |
||||
} |
||||
|
||||
function websockOpen() { |
||||
connect = true; |
||||
} |
||||
|
||||
function websockClose() { |
||||
connect = false; |
||||
store.commit("logout"); |
||||
} |
||||
|
||||
function websockError() { |
||||
showMessage("error", "后台通讯失败,请联系相关人员处理"); |
||||
} |
||||
|
||||
function websockMessage(e) { |
||||
const data = JSON.parse(e.data); |
||||
store.commit(onMessage, data); |
||||
} |
||||
|
||||
export default { |
||||
init, |
||||
send, |
||||
close |
||||
} |
@ -0,0 +1,139 @@
@@ -0,0 +1,139 @@
|
||||
import http from "../plugins/axios"; |
||||
|
||||
const fakePath = require("@/assets/image/fake.png"); |
||||
const fakeIcon = new BMap.Icon(fakePath, new BMap.Size(21, 31), { |
||||
offset: new BMap.Size(10, 25) |
||||
}); |
||||
const locatePath = require("@/assets/image/locate.png"); |
||||
const locateIcon = new BMap.Icon(locatePath, new BMap.Size(21, 31), { |
||||
offset: new BMap.Size(10, 25) |
||||
}); |
||||
const dronePath = require("@/assets/drone/drone.gif"); |
||||
const droneIcon = new BMap.Icon(dronePath, new BMap.Size(80, 80), { |
||||
offset: new BMap.Size(10, 25) |
||||
}); |
||||
const circleOptions = { |
||||
strokeColor: 'yellow', |
||||
strokeWeight: 1, |
||||
strokeOpacity: 0.5, |
||||
fillColor: 'yellow', |
||||
fillOpacity: 0.1 |
||||
}; |
||||
//圆的半径,单位为米
|
||||
let radius = 100; |
||||
http.get("public/get/circle/conf").then(rsp => { |
||||
if (rsp) { |
||||
radius = rsp[0]; |
||||
circleOptions.fillOpacity = rsp[1]; |
||||
} |
||||
}) |
||||
|
||||
function paintLocation(map, data) { |
||||
for (let i = 0; i < data.length; i++) { |
||||
const loc = data[i]; |
||||
if (loc.lng == 0 || loc.lat == 0) { |
||||
continue; |
||||
} |
||||
const point = new BMap.Point(loc.lng, loc.lat); |
||||
const marker = createMarker(loc); |
||||
const text = "手机号码:--<br\>采集时间:" + loc.time + "<br\>经纬度:" + loc.lng + ", " + loc.lat + "<br\>场强:" + loc.rssi; |
||||
marker.addEventListener("click", function() { |
||||
map.closeInfoWindow(); |
||||
openInfo(map, loc, text) |
||||
}); |
||||
map.addOverlay(marker); |
||||
} |
||||
|
||||
} |
||||
|
||||
function paintTrack(map, data) { |
||||
for (let i = 0; i < data.length; i++) { |
||||
const track = data[i]; |
||||
const point = new BMap.Point(track.lng, track.lat); |
||||
const marker = createMarker(track, i); |
||||
const text = "手机号码:--<br\>采集时间:" + track.time + "<br\>经度:" + track.lng + "<br\>纬度:" + track.lat; |
||||
marker.addEventListener("click", function() { |
||||
map.closeInfoWindow(); |
||||
openInfo(map, track, text) |
||||
}); |
||||
if (marker.label) { |
||||
marker.label.addEventListener("click", function() { |
||||
map.closeInfoWindow(); |
||||
openInfo(map, track, text) |
||||
}); |
||||
map.addOverlay(marker.label); |
||||
} |
||||
map.addOverlay(marker); |
||||
if (i == data.length - 1) { |
||||
map.centerAndZoom(point, 18); |
||||
openInfo(map, track, text) |
||||
} |
||||
} |
||||
} |
||||
|
||||
function createMarker(row, i) { |
||||
const point = new BMap.Point(row.lng, row.lat); |
||||
let marker; |
||||
if (row.rssi) { |
||||
marker = new BMap.Marker(point, { |
||||
icon: locateIcon |
||||
}); |
||||
setLabel(marker, row.rssi - 1); |
||||
} else if (row.trust == 0) { |
||||
// marker = new BMap.Circle(point, radius, circleOptions);
|
||||
// marker.label = new BMap.Marker(marker.getCenter(), {
|
||||
// icon: fakeIcon
|
||||
// });
|
||||
marker = new BMap.Marker(point, { |
||||
icon: fakeIcon |
||||
}); |
||||
marker.label = new BMap.Circle(marker.getPosition(), radius, circleOptions); |
||||
setLabel(marker, i); |
||||
} else { |
||||
marker = new BMap.Marker(point); |
||||
setLabel(marker, i); |
||||
} |
||||
return marker; |
||||
} |
||||
|
||||
function addLable(marker, i) { |
||||
setLabel(marker.label, i); |
||||
} |
||||
|
||||
function setLabel(marker, i) { |
||||
const label = new BMap.Label(i + 1, { |
||||
offset: new BMap.Size(2, 5) |
||||
}); |
||||
label.setStyle({ |
||||
backgroundColor: "none", |
||||
color: "black", |
||||
border: '0px', |
||||
borderRadius: "50%", |
||||
height: "13px", |
||||
width: "13px" |
||||
}); |
||||
marker.setLabel(label); |
||||
} |
||||
|
||||
function openInfo(map, row, text) { |
||||
const center = new BMap.Point(row.lng, row.lat) |
||||
map.setCenter(center); |
||||
const opts = { |
||||
width: 250, |
||||
height: 100, |
||||
title: 'IMSI:' + row.imsi |
||||
} |
||||
if (!text) { |
||||
text = "手机号码:--<br\>初次上报时间:" + row.firstTime + "<br\>最近上报时间:" + row.time + "<br\>经纬度:" + row.lng + "," + row.lat; |
||||
} |
||||
const infoWindow = new BMap.InfoWindow(text, opts); |
||||
map.openInfoWindow(infoWindow, center); |
||||
} |
||||
|
||||
export { |
||||
createMarker, |
||||
paintTrack, |
||||
openInfo, |
||||
droneIcon, |
||||
paintLocation |
||||
} |
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
const weeks = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'] |
||||
|
||||
const formatterDateTime = function (date, type) { |
||||
if (date == null) { |
||||
date = new Date() |
||||
} |
||||
const month = date.getMonth() < 9 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 |
||||
const day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() |
||||
const hour = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() |
||||
const minute = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() |
||||
const second = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() |
||||
switch (type) { |
||||
case 0: |
||||
return date.getFullYear() + '年' + month + '月' + day + '日' + hour + '⑩' + minute + '分' + second + '秒' |
||||
} |
||||
return date.getFullYear() + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second |
||||
} |
||||
|
||||
const formatterDate = function (date, type) { |
||||
if (date == null) { |
||||
date = new Date() |
||||
} |
||||
const month = date.getMonth() < 9 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 |
||||
const day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() |
||||
switch (type) { |
||||
case 0: |
||||
return date.getFullYear() + '年' + month + '月' + day + '日' |
||||
} |
||||
return date.getFullYear() + '-' + month + '-' + day |
||||
} |
||||
|
||||
const formatterTime = function (date, type) { |
||||
if (date == null) { |
||||
date = new Date() |
||||
} |
||||
const month = date.getMonth() < 9 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 |
||||
switch (type) { |
||||
case 0: |
||||
return hour + '⑩' + minute + '分' + second + '秒' |
||||
} |
||||
return date.getFullYear() + '-' + month |
||||
} |
||||
|
||||
const formatterWeekDay = function (date, type) { |
||||
if (date == null) { |
||||
date = new Date() |
||||
} |
||||
return weeks[date.getDay()] |
||||
} |
||||
export { |
||||
formatterDateTime, |
||||
formatterDate, |
||||
formatterTime, |
||||
formatterWeekDay |
||||
} |
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
import * as validate from './validate' |
||||
|
||||
function getValidator(required, validateName, number) { |
||||
const arr = [] |
||||
if (required != null) { |
||||
arr.push({ |
||||
required: true, |
||||
message: required, |
||||
trigger: 'blur' |
||||
}) |
||||
} |
||||
if (validateName != null) { |
||||
arr.push({ |
||||
validator: validate[validateName], |
||||
trigger: 'blur' |
||||
}) |
||||
} |
||||
if (number) { |
||||
arr.push({ |
||||
type: 'number', |
||||
min: 0, |
||||
message: '请输入正确的数字', |
||||
trigger: 'blur' |
||||
}) |
||||
} |
||||
return arr |
||||
} |
||||
|
||||
const login = { |
||||
userId: getValidator('请输入用户名'), |
||||
password: getValidator('请输入密码') |
||||
} |
||||
|
||||
const dictionary = { |
||||
code: getValidator('请输入字典编号'), |
||||
name: getValidator('请输入字典名称'), |
||||
visitedNetworkAddress: getValidator('请选择字典状态') |
||||
} |
||||
|
||||
const app = { |
||||
name : getValidator('请输入APP名称'), |
||||
itemId : getValidator('请输入授权项编号'), |
||||
type : getValidator('请选择授权项类型') |
||||
} |
||||
|
||||
const customer = { |
||||
code : getValidator('请输入客户编号'), |
||||
name : getValidator('请输入客户名称'), |
||||
contacter : getValidator('请输入联系人'), |
||||
phone : getValidator('请输入联系人号码') |
||||
} |
||||
|
||||
const author = { |
||||
custCode : getValidator('请选择客户'), |
||||
fingerprint : getValidator('请输入指纹信息'), |
||||
key1 : getValidator('请选择Code1'), |
||||
key1 : getValidator('请选择Code2') |
||||
} |
||||
|
||||
const client = { |
||||
authorize : getValidator('请选择授权中心'), |
||||
appId : getValidator('请选择授权APP'), |
||||
num : getValidator('请输入授权数量'), |
||||
keyId : getValidator('请选择户端秘钥') |
||||
} |
||||
|
||||
const key = { |
||||
type : getValidator('请选择秘钥类型'), |
||||
remark : getValidator('请输入秘钥名称') |
||||
} |
||||
|
||||
export { |
||||
login, |
||||
dictionary, |
||||
app, |
||||
customer, |
||||
author, |
||||
client, |
||||
key |
||||
} |
@ -0,0 +1,233 @@
@@ -0,0 +1,233 @@
|
||||
function password (rule, value, callback) { |
||||
if (value == null || value === '') { |
||||
callback(new Error('请输入密码')) |
||||
} else if (value.length < 8 || value.length > 16) { |
||||
callback(new Error('密码长度为:8~16位')) |
||||
} else if (!new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).*$').test(value)) { |
||||
callback(new Error('密码至少包含大小写字母和数字')) |
||||
} else if (!new RegExp('^[^ ]+$').test(value)) { |
||||
callback(new Error('密码不能包含空格')) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function code (rule, value, callback) { |
||||
if (value == null || value == '') { |
||||
callback(new Error('验证码不能为空')) |
||||
} else if (!new RegExp('^[0-9]+$').test(value)) { |
||||
callback(new Error('验证码只能为数字')) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function email (rule, value, callback) { |
||||
if (value != null && value.length != 0) { |
||||
if ( |
||||
!new RegExp( |
||||
/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/ |
||||
).test(value) |
||||
) { |
||||
callback(new Error('请输入正确的电子邮箱')) |
||||
} |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function phone (rule, value, callback) { |
||||
if (value != null && value.length != 0) { |
||||
if ( |
||||
!new RegExp( |
||||
'^(0|86|17951)?(13[0-9]|15[012356789]|17[0135678]|18[0-9]|14[57])[0-9]{8}$' |
||||
).test(value) |
||||
) { |
||||
callback(new Error('请输入正确的手机号码')) |
||||
} |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function imsi (rule, value, callback) { |
||||
// if(value != null && value.length != 0){
|
||||
// }
|
||||
callback() |
||||
} |
||||
|
||||
function userName (rule, value, callback) { |
||||
if (value != null && value.length != 0) { |
||||
if (!new RegExp('^[a-zA-Z0-9]{6,16}$').test(value)) { |
||||
callback(new Error('用户名由字母,数字组成,长度6-16之间')) |
||||
} |
||||
if (/(^\_)|(\__)|(\_+$)/.test(value)) { |
||||
callback(new Error("用户名首尾不能出现下划线'_'")) |
||||
} |
||||
if (!new RegExp('^[^ ]+$').test(value)) { |
||||
callback(new Error('用户名不能包含空格')) |
||||
} |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function name (rule, value, callback) { |
||||
if (value != null && value.length != 0) { |
||||
if (!new RegExp('^[a-zA-Z\u4e00-\u9fa5]{1,10}$').test(value)) { |
||||
callback(new Error('姓名由汉字或字母组成,且长度不超过10')) |
||||
} |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function idCard (rule, value, callback) { |
||||
if (value != null && value.length != 0) { |
||||
let iSum = 0 |
||||
const aCity = { |
||||
11: '北京', |
||||
12: '天津', |
||||
13: '河北', |
||||
14: '山西', |
||||
15: '内蒙古', |
||||
21: '辽宁', |
||||
22: '吉林', |
||||
23: '黑龙江', |
||||
31: '上海', |
||||
32: '江苏', |
||||
33: '浙江', |
||||
34: '安徽', |
||||
35: '福建', |
||||
36: '江西', |
||||
37: '山东', |
||||
41: '河南', |
||||
42: '湖北', |
||||
43: '湖南', |
||||
44: '广东', |
||||
45: '广西', |
||||
46: '海南', |
||||
50: '重庆', |
||||
51: '四川', |
||||
52: '贵州', |
||||
53: '云南', |
||||
54: '西藏', |
||||
61: '陕西', |
||||
62: '甘肃', |
||||
63: '青海', |
||||
64: '宁夏', |
||||
65: '新疆', |
||||
71: '台湾', |
||||
81: '香港', |
||||
82: '澳门', |
||||
91: '国外' |
||||
} |
||||
if (!/^\d{17}(\d|x)$/i.test(value)) { |
||||
callback(new Error('你输入的身份证长度或格式错误')) |
||||
} |
||||
value = value.replace(/x$/i, 'a') |
||||
if (aCity[parseInt(value.substr(0, 2))] == null) { |
||||
callback(new Error('你的身份证地区非法')) |
||||
} |
||||
|
||||
const sBirthday = |
||||
value.substr(6, 4) + |
||||
'-' + |
||||
Number(value.substr(10, 2)) + |
||||
'-' + |
||||
Number(value.substr(12, 2)) |
||||
const d = new Date(sBirthday.replace(/-/g, '/')) |
||||
if ( |
||||
sBirthday != |
||||
d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() |
||||
) { |
||||
callback(new Error('身份证上的出生日期非法')) |
||||
} |
||||
for (let i = 17; i >= 0; i--) { iSum += (Math.pow(2, i) % 11) * parseInt(value.charAt(17 - i), 11) } |
||||
if (iSum % 11 != 1) { |
||||
callback(new Error('你输入的身份证号非法')) |
||||
} |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function devName (rule, value, callback) { |
||||
console.log(rule) |
||||
if (value == null || value.length == 0 || value == '') { |
||||
callback(new Error('请输入设备名称')) |
||||
} |
||||
if (!new RegExp('^[a-zA-Z0-9\u4e00-\u9fa5]{1,10}$').test(value)) { |
||||
callback(new Error('设备名称由汉字,字母,数字组成,且长度不能超过10')) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function devId (rule, value, callback) { |
||||
if (value == null || value.length == 0 || value == '') { |
||||
callback(new Error('请输入设备编号')) |
||||
} |
||||
if (!new RegExp(/^[1-9]\d{0,8}$/).test(value)) { |
||||
callback(new Error('设备编号由数字组成,且长度不能超过9,首位不能为0')) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function ipv4 (rule, value, callback) { |
||||
if (value != null && value.length != 0) { |
||||
if ( |
||||
!new RegExp(/^((25[0-5]|2[0-4]\d|[01]?\d\d?)($|(?!\.$)\.)){4}$/).test( |
||||
value |
||||
) |
||||
) { |
||||
callback(new Error('错误的IPV4地址格式')) |
||||
} |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function lon (rule, value, callback) { |
||||
if ( |
||||
!new RegExp( |
||||
/^-?((0|1?[0-7]?[0-9]?)(([.][0-9]{1,6})?)|180(([.][0]{1,6})?))$/ |
||||
).test(value) |
||||
) { |
||||
callback(new Error('请输入正确的经度')) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function lat (rule, value, callback) { |
||||
if ( |
||||
!new RegExp( |
||||
/^-?((0|[1-8]?[0-9]?)(([.][0-9]{1,6})?)|90(([.][0]{1,6})?))$/ |
||||
).test(value) |
||||
) { |
||||
callback(new Error('请输入正确的纬度')) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
function number (rule, value, callback) { |
||||
if (!new RegExp(/^[1-9][0-9]*$/).test(value)) { |
||||
callback(new Error('请输入正整数')) |
||||
} |
||||
const num = parseInt(value) |
||||
if (rule.min != null && num < rule.min) { |
||||
callback(new Error('输入最小值为' + rule.min)) |
||||
} |
||||
if (rule.max != null && num > rule.max) { |
||||
callback(new Error('输入最大值为' + rule.max)) |
||||
} |
||||
callback() |
||||
} |
||||
|
||||
export { |
||||
password, |
||||
code, |
||||
email, |
||||
phone, |
||||
imsi, |
||||
userName, |
||||
name, |
||||
idCard, |
||||
devName, |
||||
devId, |
||||
ipv4, |
||||
lon, |
||||
lat, |
||||
number |
||||
} |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
export default { |
||||
|
||||
init(context){ |
||||
context.commit('getUserInfo'); |
||||
context.commit('getCfg'); |
||||
context.commit('updateState', { |
||||
prop: 'showHeader', |
||||
value: true |
||||
}) |
||||
context.commit('initSizes') |
||||
} |
||||
|
||||
} |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
import Vue from 'vue' |
||||
import Vuex from 'vuex' |
||||
import state from './state' |
||||
import mutations from './mutations.js' |
||||
import actions from './actions.js' |
||||
import modules from './modules.js' |
||||
|
||||
Vue.use(Vuex) |
||||
|
||||
export default new Vuex.Store({ |
||||
state, |
||||
mutations, |
||||
actions, |
||||
modules |
||||
}) |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
export default class { |
||||
|
||||
} |
@ -0,0 +1,175 @@
@@ -0,0 +1,175 @@
|
||||
import http from '../static/plugins/axios' |
||||
import websocket from '../static/plugins/websocket' |
||||
import vue from '../main' |
||||
import Vue from 'vue' |
||||
|
||||
let interval = null; |
||||
const urls = { |
||||
info: 'public/info', |
||||
dict: 'public/get/dict', |
||||
logout: 'public/logout', |
||||
host: 'public/host' |
||||
} |
||||
|
||||
function stop() { |
||||
if (interval == null) { |
||||
return |
||||
} |
||||
clearInterval(interval) |
||||
interval = null |
||||
} |
||||
|
||||
function start() { |
||||
stop() |
||||
interval = setInterval(() => { |
||||
http.get(urls.info, null, true, true).then(rsp => { |
||||
if (!rsp) { |
||||
stop() |
||||
vue.$router.push('/login') |
||||
} |
||||
}) |
||||
}, 5000) |
||||
} |
||||
|
||||
function open(userName) { |
||||
let url = "ws://"; |
||||
if (process.env.VUE_APP_BASE_URL) { |
||||
url += process.env.VUE_APP_BASE_URL; |
||||
} else { |
||||
url += window.location.hostname; |
||||
const port = window.location.port; |
||||
if (port != null && port != '') { |
||||
url += (":" + port); |
||||
} |
||||
} |
||||
url = url + "/webSocket/" + userName; |
||||
websocket.init(url, "websockMessage"); |
||||
} |
||||
|
||||
export default { |
||||
updateState(state, param) { |
||||
state[param.prop] = param.value; |
||||
}, |
||||
|
||||
initSizes(state) { |
||||
const height = window.innerHeight; |
||||
const width = window.innerWidth; |
||||
const loginHeight = 350; |
||||
const loginWidth = 450; |
||||
const navHead = state.showHeader ? 80 : 0; |
||||
const map = { |
||||
medium: 50, |
||||
small: 42, |
||||
mini: 35 |
||||
}; |
||||
const head = map[state.size] ? map[state.size] : 60; |
||||
const pd = 0; |
||||
const page = 37; |
||||
Vue.set(state.sizes, 'fullHeight', height + 'px'); |
||||
Vue.set(state.sizes, 'loginHeight', loginHeight + 'px'); |
||||
Vue.set(state.sizes, 'loginWidth', loginWidth + 'px'); |
||||
Vue.set(state.sizes, 'loginTop', (height - loginHeight) * 0.4 + 'px'); |
||||
Vue.set(state.sizes, 'loginLeft', (width - loginWidth) * 0.49 + 'px'); |
||||
Vue.set(state.sizes, 'headHeight', navHead + 'px'); |
||||
Vue.set(state.sizes, 'mainHead', head + 'px'); |
||||
Vue.set(state.sizes, 'mainHeight', height - navHead + 'px'); |
||||
Vue.set(state.sizes, 'tableHei', height - navHead - head - pd); |
||||
Vue.set(state.sizes, 'pTableHei', state.sizes.tableHei - page); |
||||
}, |
||||
|
||||
getUserInfo(state) { |
||||
http.get(urls.info).then(response => { |
||||
if (response) { |
||||
state.userInfo = response; |
||||
state.menuGroups = [{ |
||||
name: '主页', |
||||
id: 'home', |
||||
child: [] |
||||
}]; |
||||
if (response.permission == '1') { |
||||
state.menuGroups.push({ |
||||
name: '系统管理', |
||||
id: 'sys', |
||||
child: [{ |
||||
name: '配置管理', |
||||
id: 'config' |
||||
}, { |
||||
name: '用户管理', |
||||
id: 'user' |
||||
}] |
||||
}) |
||||
} |
||||
start() |
||||
// open(response.userId);
|
||||
} else { |
||||
vue.$router.push('/login') |
||||
} |
||||
}) |
||||
.catch(() => { |
||||
vue.$router.push('/login') |
||||
}) |
||||
}, |
||||
|
||||
websockMessage(state, data) { |
||||
const handler = state.handlers[data.type]; |
||||
if (handler != null) { |
||||
handler(data.data); |
||||
} |
||||
}, |
||||
|
||||
getCfg(state) { |
||||
http.get(urls.host).then(rsp => { |
||||
state.host = rsp; |
||||
}); |
||||
}, |
||||
|
||||
getDictMap(state, codes, callBack) { |
||||
if (codes == null) { |
||||
return |
||||
} |
||||
const arr = [] |
||||
for (let i = 0; i < codes.length; i++) { |
||||
if (Object.keys(state.dict).indexOf(codes[i]) == -1) { |
||||
arr.push(codes[i]) |
||||
} |
||||
} |
||||
if (arr.length == 0) { |
||||
return |
||||
} |
||||
http.post(urls.dict, arr).then(function(response) { |
||||
if (response) { |
||||
for (let i = 0; i < arr.length; i++) { |
||||
const key = arr[i] |
||||
state.dict[key] = {} |
||||
const dicts = response[key] |
||||
if (dicts == null) { |
||||
continue |
||||
} |
||||
for (let j = 0; j < dicts.length; j++) { |
||||
const tmp = dicts[j] |
||||
const num = parseInt(tmp.code) |
||||
if (!isNaN(num)) { |
||||
state.dict[key][num] = tmp.name |
||||
} else { |
||||
state.dict[key][tmp.code] = tmp.name |
||||
} |
||||
} |
||||
} |
||||
if (callBack != null) { |
||||
callBack() |
||||
} |
||||
} |
||||
}) |
||||
}, |
||||
|
||||
logout(state) { |
||||
http.get(urls.logout).then(response => { |
||||
if (response) { |
||||
vue.$router.push('/login') |
||||
state.userInfo = {} |
||||
} |
||||
}); |
||||
websocket.close(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
export default { |
||||
menuGroups: [], |
||||
sizes: {}, |
||||
userInfo: {}, |
||||
showHeader: true, |
||||
size: 'small', |
||||
dict: {}, |
||||
handlers: {}, |
||||
host: {}, |
||||
network: "traHost" |
||||
} |
@ -0,0 +1,243 @@
@@ -0,0 +1,243 @@
|
||||
<template> |
||||
<div id="picture"> |
||||
<MainHead name="图片" :flag="flag" :terms="terms" :example="example" @query="query(1)"> |
||||
<template slot="title"> |
||||
<span class="network-switch"> |
||||
<div class="switch-label">网络环境:</div> |
||||
<el-switch v-model="$store.state.network" active-value="tertHost" inactive-value="traHost" :width="60" active-text="外网" |
||||
inactive-text="内网"></el-switch> |
||||
</span> |
||||
</template> |
||||
<template slot="header"> |
||||
<el-upload class="upload-btn" :action="uploadUrl" :on-error="onError" :on-success="onSuccess" :multiple="false" |
||||
:show-file-list="false"> |
||||
<el-button :size="$store.state.size" type="success" icon="el-icon-upload"> |
||||
上传图片 |
||||
</el-button> |
||||
</el-upload> |
||||
</template> |
||||
</MainHead> |
||||
<el-row class="image-list" :style="{ height: $store.state.sizes.pTableHei + 'px' }"> |
||||
<el-col v-for="(item, index) in result.rows" :xs="8" :sm="7" :md="6" :xl="4"> |
||||
<el-result icon="success" :title="item.remark ? item.remark : (index + 1).toString()" |
||||
:subTitle="item.time + ' ' + item.space + ' ' + item.remark"> |
||||
<template slot="icon"> |
||||
<el-image :src="'http//'+ $store.state.host[$store.state.network] + '/' + item.path"> |
||||
</el-image> |
||||
</template> |
||||
<template slot="extra"> |
||||
<el-button type="primary" size="mini" @click="copy(item)">复制</el-button> |
||||
<el-button type="info" size="mini" @click="remark(item)">备注</el-button> |
||||
<el-button type="danger" size="mini" @click="delate(item)">删除</el-button> |
||||
</template> |
||||
</el-result> |
||||
</el-col> |
||||
</el-row> |
||||
<el-pagination :current-page="example.page" :page-sizes="[10, 20, 50, 100]" :page-size="example.size" |
||||
layout="total, sizes, prev, pager, next, jumper" :total="result.total" @size-change="handleSizeChange" |
||||
@current-change="handleCurrentChange" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Vue, |
||||
Component, |
||||
Prop |
||||
} from "vue-property-decorator"; |
||||
import Template from '@/components/template/manage.vue'; |
||||
import MainHead from '@/components/template/mainHeader.vue'; |
||||
|
||||
@Component({ |
||||
components: { |
||||
Template, |
||||
MainHead |
||||
} |
||||
}) |
||||
export default class Picture extends Vue { |
||||
url = 'picture'; |
||||
uploadUrl = (process.env.VUE_APP_BASE_URL ? "/api/" : "/") + this.url; |
||||
flag = { |
||||
list: true, |
||||
save: false, |
||||
update: false, |
||||
del: true, |
||||
title: true |
||||
} |
||||
terms = [{ |
||||
code: 'remark', |
||||
desc: '备注' |
||||
}, { |
||||
code: 'startTime', |
||||
datePicker: true, |
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss', |
||||
type: 'datetime', |
||||
desc: '开始时间' |
||||
}, { |
||||
code: 'endTime', |
||||
datePicker: true, |
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss', |
||||
type: 'datetime', |
||||
desc: '结束时间' |
||||
}] |
||||
|
||||
example = { |
||||
page: 1, |
||||
size: 20 |
||||
}; |
||||
result = { |
||||
rows: [], |
||||
total: 0 |
||||
}; |
||||
handleSizeChange(val) { |
||||
this.example.size = val |
||||
this.query() |
||||
} |
||||
handleCurrentChange(val) { |
||||
this.example.page = val |
||||
this.query() |
||||
} |
||||
query(page) { |
||||
const that = this |
||||
if (page != null) { |
||||
this.example.page = page |
||||
} |
||||
this.$get(that.url, that.example).then(function(response) { |
||||
if (response) { |
||||
that.result = response |
||||
} else { |
||||
that.result = { |
||||
rows: [], |
||||
total: 0 |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
copy(row) { |
||||
const that = this; |
||||
const host = this.$store.state.host[this.$store.state.network]; |
||||
const path = 'http://' + host + "/" + row.path; |
||||
this.$copyText(path).then(e => { |
||||
that.$showMessage("success", "复制成功"); |
||||
}, e => { |
||||
that.$showMessage("success", "复制失败"); |
||||
}) |
||||
} |
||||
|
||||
remark(row) { |
||||
const that = this |
||||
this.$prompt('请输入备注信息', '备注', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
inputPattern: /^[\S]{1,64}$/, |
||||
inputErrorMessage: '备注不能输入空格,且长度不超过64位', |
||||
distinguishCancelAndClose: true, |
||||
showClose: false, |
||||
beforeClose: (action, instance, done) => { |
||||
if (action === 'close') { |
||||
return |
||||
} |
||||
done() |
||||
} |
||||
}).then(({ |
||||
value |
||||
}) => { |
||||
console.log(value); |
||||
const param = JSON.parse(JSON.stringify(row)); |
||||
param.remark = value; |
||||
that.$put(that.url, param).then(rsp => { |
||||
if (rsp) { |
||||
row.remark = value; |
||||
} |
||||
}); |
||||
}).catch(() => {}) |
||||
} |
||||
|
||||
delate(row) { |
||||
const that = this |
||||
this.$confirm('确定要删除该图片吗?', '提示', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$delete(that.url, row).then(function(response) { |
||||
if (response) { |
||||
that.query() |
||||
} |
||||
}) |
||||
}).catch(() => { |
||||
that.showMessage('info', '已取消删除') |
||||
}) |
||||
} |
||||
|
||||
onError(err, file, fileList) { |
||||
that.$showMessage('error', file.name + "上传失败", true) |
||||
console.log(err); |
||||
} |
||||
onSuccess(response, file, fileList) { |
||||
const that = this; |
||||
if (response.success == false) { |
||||
that.$showMessage('error', response.message, true); |
||||
} else { |
||||
that.$showMessage('success', response.message, true) |
||||
} |
||||
this.$refs.upload.clearFiles(); |
||||
} |
||||
|
||||
getClipboardFiles(event) { |
||||
let items = event.clipboardData && event.clipboardData.items; |
||||
let file = null |
||||
if (items && items.length) { |
||||
// 检索剪切板items |
||||
for (var i = 0; i < items.length; i++) { |
||||
if (items[i].type.indexOf('image') !== -1) { |
||||
file = items[i].getAsFile() |
||||
} |
||||
} |
||||
} |
||||
if (file) { |
||||
this.$confirm('是否要上传剪切板中复制的图片?', '提示', { |
||||
confirmButtonText: '是的', |
||||
cancelButtonText: '不用', |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$upload(file, this.url); |
||||
}).catch(() => {}) |
||||
} |
||||
} |
||||
|
||||
created() { |
||||
this.query(1); |
||||
document.addEventListener('paste', this.getClipboardFiles); |
||||
} //生命周期 - 创建完成(可以访问当前this实例) |
||||
mounted() {} //生命周期 - 挂载完成(可以访问DOM元素) |
||||
beforeCreate() {} //生命周期 - 创建之前 |
||||
beforeMount() {} //生命周期 - 挂载之前 |
||||
beforeUpdate() {} //生命周期 - 更新之前 |
||||
updated() {} //生命周期 - 更新之后 |
||||
beforeDestroy() { |
||||
document.removeEventListener('paste', this.getClipboardFiles); |
||||
} //生命周期 - 销毁之前 |
||||
destroyed() {} //生命周期 - 销毁完成 |
||||
activated() {} //如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
.upload-btn { |
||||
padding-left: 10px; |
||||
} |
||||
|
||||
.network-switch { |
||||
padding-left: 20px; |
||||
} |
||||
.switch-label { |
||||
float: left; |
||||
font-size: 16px; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.image-list { |
||||
overflow-y: auto; |
||||
} |
||||
</style> |
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
<template> |
||||
<div id="app" :style="{ height: $store.state.sizes.height }"> |
||||
<NavHeader v-show="$store.state.showHeader" class="app-head" :style="{ height: $store.state.sizes.headHeight+'px' }" |
||||
ref="header" /> |
||||
<router-view class="app-main" :style="{ height: $store.state.sizes.mainHeight }" @init="init" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Component, |
||||
Prop, |
||||
Vue, |
||||
Watch |
||||
} from 'vue-property-decorator' |
||||
import NavHeader from '@/components/main/NavHeader'; |
||||
import websoct from '@/static/plugins/websocket'; |
||||
|
||||
@Component({ |
||||
components: { |
||||
NavHeader |
||||
} |
||||
}) |
||||
export default class App extends Vue { |
||||
initSize() { |
||||
this.$store.commit('initSizes') |
||||
} |
||||
|
||||
init() { |
||||
this.$store.dispatch('init'); |
||||
this.$router.push('/home') |
||||
if (this.$refs.header) { |
||||
this.$refs.header.toHome() |
||||
} |
||||
} |
||||
|
||||
|
||||
created() { |
||||
this.init() |
||||
this.initSize() |
||||
window.onresize = this.initSize |
||||
} |
||||
|
||||
mounted() {} // 生命周期 - 挂载完成(可以访问DOM元素) |
||||
beforeCreate() {} // 生命周期 - 创建之前 |
||||
beforeMount() {} // 生命周期 - 挂载之前 |
||||
beforeUpdate() {} // 生命周期 - 更新之前 |
||||
updated() {} // 生命周期 - 更新之后 |
||||
beforeDestroy() {} // 生命周期 - 销毁之前 |
||||
destroyed() {} // 生命周期 - 销毁完成 |
||||
activated() {} // 如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style lang="scss"> |
||||
@import '~@/assets/styles/base.scss'; |
||||
@import '~@/assets/styles/size_small.scss'; |
||||
// @import '~@/assets/styles/back_blue.scss'; |
||||
|
||||
.app-head { |
||||
padding: 0px !important; |
||||
} |
||||
|
||||
.app-main { |
||||
padding: 0px 20px !important; |
||||
} |
||||
</style> |
@ -0,0 +1,124 @@
@@ -0,0 +1,124 @@
|
||||
<template> |
||||
<div id="login"> |
||||
<div class="loginForm" :style="{ height:$store.state.sizes.loginHeight,width:$store.state.sizes.loginWidth, |
||||
'margin-top': $store.state.sizes.loginTop,'margin-left':$store.state.sizes.loginLeft}"> |
||||
<el-form ref="login" class="login-form" :model="user" :rules="rules" hide-required-asterisk label-width="30px"> |
||||
<div class="login-title"> |
||||
图床卅 |
||||
</div> |
||||
<br><br> |
||||
<el-form-item prop="userId"> |
||||
<el-input v-model="user.userId" placeholder="用户名"> |
||||
<el-button slot="prepend" icon="el-icon-user" /> |
||||
</el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="password"> |
||||
<el-input v-model="user.password" type="password" placeholder="密码"> |
||||
<el-button slot="prepend" icon="el-icon-key" /> |
||||
</el-input> |
||||
</el-form-item> |
||||
<br> |
||||
<el-form-item> |
||||
<el-button class="login-btn" type="primary" @click="loginSubmit">登录</el-button> |
||||
<el-button style="float: right;" class="login-btn" type="primary" @click="reset">重置</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts"> |
||||
import { |
||||
Component, |
||||
Prop, |
||||
Vue |
||||
} from 'vue-property-decorator' |
||||
import md5 from 'js-md5' |
||||
import { |
||||
login |
||||
} from '@/static/tool/ruleControl.js' |
||||
|
||||
@Component |
||||
export default class Login extends Vue { |
||||
marginTop = (window.innerHeight - 350) * 0.4 + 'px'; |
||||
user = { |
||||
userId: null, |
||||
password: null |
||||
}; |
||||
|
||||
rules = login; |
||||
|
||||
loginSubmit() { |
||||
const that = this |
||||
this.$refs.login.validate((valid) => { |
||||
if (valid) { |
||||
const param = JSON.parse(JSON.stringify(that.user)) |
||||
param.password = md5(param.password) |
||||
that.$post('public/login', param).then(function(response) { |
||||
if (response == true) { |
||||
setTimeout(() => { |
||||
that.$emit("init"); |
||||
}, 300) |
||||
} |
||||
}) |
||||
} else { |
||||
return false |
||||
} |
||||
}) |
||||
} |
||||
|
||||
reset() { |
||||
this.user = { |
||||
userId: null, |
||||
password: null |
||||
} |
||||
} |
||||
|
||||
init(b) { |
||||
this.$store.commit('updateState', { |
||||
prop: 'showHeader', |
||||
value: b |
||||
}) |
||||
this.$store.commit('initSizes') |
||||
} |
||||
|
||||
created() { |
||||
this.init(false); |
||||
const that = this; |
||||
document.onkeydown = function(e) { |
||||
let ev = e || event; |
||||
let key = ev.keyCode; |
||||
if (key == 13) { |
||||
that.loginSubmit(); |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
#login { |
||||
align-items: center; |
||||
background: none; |
||||
} |
||||
|
||||
.loginForm { |
||||
background: none; |
||||
height: 350px; |
||||
width: 500px; |
||||
box-shadow: 0 0 25px #cac6c6 !important; |
||||
padding: 30px 30px 20px 0px; |
||||
} |
||||
|
||||
.login-title { |
||||
margin: 0px 70px 20px; |
||||
font-size: 1.8rem; |
||||
text-align: center; |
||||
color: #2d3748; |
||||
} |
||||
|
||||
.login-btn { |
||||
margin: 0px 30px; |
||||
width: 100px; |
||||
} |
||||
</style> |
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
<template> |
||||
<div id="config"> |
||||
<Template ref="template" name="配置" :url="url" :flag="flag" :terms="terms" :props="props" :rules="rules" |
||||
:actions="actions"></template> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
Vue, |
||||
Component, |
||||
Prop |
||||
} from "vue-property-decorator"; |
||||
import Template from '@/components/template/manage.vue'; |
||||
|
||||
@Component({ |
||||
components: { |
||||
Template |
||||
} |
||||
}) |
||||
export default class Config extends Vue { |
||||
url = "sys/config"; |
||||
flag = { |
||||
list: true, |
||||
save: false, |
||||
update: true, |
||||
del: false |
||||
} |
||||
rules = {}; |
||||
terms = [{ |
||||
code: 'cfgName', |
||||
desc: '配置名称' |
||||
}]; |
||||
props = [{ |
||||
code: 'cfgKey', |
||||
name: '配置key', |
||||
width: 150, |
||||
readOnly: true |
||||
}, { |
||||
code: 'cfgName', |
||||
name: '配置名称', |
||||
width: 150 |
||||
}, { |
||||
code: 'cfgValue', |
||||
name: '配置值', |
||||
width: 150 |
||||
}, { |
||||
code: 'cfgType', |
||||
name: '配置类型', |
||||
width: 150, |
||||
readOnly: true |
||||
}, { |
||||
code: 'cfgDesc', |
||||
name: '配置描述', |
||||
width: 200 |
||||
}, { |
||||
code: 'updateTime', |
||||
name: '最近更新时间', |
||||
width: 170, |
||||
hide: true |
||||
}, { |
||||
code: 'updateUser', |
||||
name: '最近更新用户', |
||||
width: 160, |
||||
hide: true |
||||
// }, { |
||||
// code: 'cfgStatus', |
||||
// name: '配置状态', |
||||
// dict: 'active_status', |
||||
// width: 120 |
||||
}]; |
||||
actions = []; |
||||
created() { |
||||
// this.$store.commit('getDictMap', ['active_status']); |
||||
} //生命周期 - 创建完成(可以访问当前this实例) |
||||
mounted() {} //生命周期 - 挂载完成(可以访问DOM元素) |
||||
beforeCreate() {} //生命周期 - 创建之前 |
||||
beforeMount() {} //生命周期 - 挂载之前 |
||||
beforeUpdate() {} //生命周期 - 更新之前 |
||||
updated() {} //生命周期 - 更新之后 |
||||
beforeDestroy() {} //生命周期 - 销毁之前 |
||||
destroyed() {} //生命周期 - 销毁完成 |
||||
activated() {} //如果页面有keep-alive缓存功能,这个函数会触发 |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
|
||||
</style> |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
{ |
||||
"compilerOptions": { |
||||
"target": "esnext", |
||||
"module": "esnext", |
||||
"strict": false, |
||||
"jsx": "preserve", |
||||
"importHelpers": true, |
||||
"moduleResolution": "node", |
||||
"experimentalDecorators": true, |
||||
"esModuleInterop": true, |
||||
"allowSyntheticDefaultImports": true, |
||||
"sourceMap": true, |
||||
"baseUrl": ".", |
||||
"types": [ |
||||
"webpack-env" |
||||
], |
||||
"paths": { |
||||
"@/*": [ |
||||
"src/*" |
||||
] |
||||
}, |
||||
"lib": [ |
||||
"esnext", |
||||
"dom", |
||||
"dom.iterable", |
||||
"scripthost" |
||||
] |
||||
}, |
||||
"include": [ |
||||
"src/**/*.ts", |
||||
"src/**/*.tsx", |
||||
"src/**/*.vue", |
||||
"tests/**/*.ts", |
||||
"tests/**/*.tsx" |
||||
], |
||||
"exclude": [ |
||||
"node_modules" |
||||
] |
||||
} |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
module.exports = { |
||||
lintOnSave: false, |
||||
publicPath: '/', |
||||
chainWebpack: config => { |
||||
config.module |
||||
.rule('images') |
||||
.use('url-loader') |
||||
.loader('url-loader') |
||||
.tap(options => Object.assign(options, { limit: 1 })) |
||||
}, |
||||
configureWebpack: { |
||||
externals: { |
||||
'BMap': "BMap" |
||||
}, |
||||
resolve: { |
||||
alias: { |
||||
'assets': '@/assets', |
||||
'common': '@/common', |
||||
'components': '@/components', |
||||
'network': '@/network', |
||||
'views': '@/views', |
||||
'plugins': '@/plugins', |
||||
} |
||||
} |
||||
}, |
||||
devServer: { |
||||
proxy: { |
||||
'/api': { |
||||
target: 'http://'+process.env.VUE_APP_BASE_URL, |
||||
// 允许跨域
|
||||
changeOrigin: true, |
||||
ws: true, |
||||
pathRewrite: { |
||||
'^/api': '' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue