Commit 2efd82d5 by HlQ

[add] 项目代码提交

1 parent ee3b94fe
Showing 119 changed files with 3105 additions and 2275 deletions
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
src/main/test/
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NodePackageJsonFileManager">
<packageJsonPaths />
</component>
</project>
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="Vion-DevOps" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="Vion-DevOps" options="-parameters" />
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="vion-nexus" />
<option name="name" value="vion-nexus" />
<option name="url" value="http://maven.vionyun.com:8081/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="aliyun-nexus" />
<option name="name" value="aliyun-nexus" />
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
......@@ -8,34 +8,23 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<version>2.7.17</version>
</parent>
<artifactId>Vion-DevOps</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.8</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
<version>42.6.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
......@@ -43,91 +32,64 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
<dependency>
<groupId>com.mks.api</groupId>
<artifactId>mksapi-jar</artifactId>
<version>4.10.9049</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>2.0.14</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.0</version>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
</dependencies>
<build>
<finalName>VVAS-Task</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>vion.Application</mainClass>
<layout>JAR</layout>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>application-*.properties</exclude>
</excludes>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>1.3.5</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package vion;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import vion.controller.UserController;
import java.util.concurrent.CountDownLatch;
import vion.ding.DingMod;
@SpringBootApplication
@MapperScan("vion.mapper")
@EnableScheduling
public class Application implements CommandLineRunner {
public class Application {
public static void main(String[] args) {
try {
SpringApplication.run(Application.class, args);
new CountDownLatch(1).await();
} catch (Exception e) {
e.printStackTrace();
}
}
@Autowired
private UserController userController;
private DingMod dingMod;
private final static Logger logger = LoggerFactory.getLogger(Application.class);
//@Scheduled(fixedDelay=1000*60*10,initialDelay=1000)
@Scheduled(cron="${third.run.cron:0 0 2 * * ?}")
public void startJob(){
@Scheduled(cron = "${third.run.cron:0 0 2 * * ?}")
public void startJob() {
try {
logger.info("启动");
//定时获取钉钉用户列表
userController.getDingUserList();
//USERNAME_MAP
dingMod.getDeptList();
dingMod.getDingUserList();
logger.info("启动完成");
} catch (Exception e) {
e.printStackTrace();
// System.exit(-1);
}
}
@Override
public void run(String... args) throws Exception {
}
}
......@@ -2,7 +2,6 @@ package vion;
import vion.model.User;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
......@@ -13,5 +12,4 @@ public class Global {
public static final String WORK_URL = "/api/work";
public static final String INSPECT_URL = "/api/inspect";
public static final Map<String, User> USERNAME_MAP = new ConcurrentHashMap<>();
public static final Map<String, String> IP_MALL_MAP = new HashMap<>();
}
package vion.advice;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import vion.utils.ResultUtil;
import vion.vo.ResultVO;
/**
* @author HlQ
* @date 2023/11/2
*/
@Component
@RestControllerAdvice("vion.controller")
@Slf4j
public class ResBodyAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return !returnType.getMethod().getReturnType().isAssignableFrom(Void.TYPE);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof ResultVO || body instanceof ModelAndView) {
return body;
}
ResultVO resultVO = ResultUtil.success(body);
if (returnType.getParameterType().isAssignableFrom(String.class)) {
// 字符串类型特殊处理
try {
return new ObjectMapper().writeValueAsString(resultVO);
} catch (JsonProcessingException e) {
}
}
return resultVO;
}
@ExceptionHandler(Exception.class)
public Object exceptionHandler(Exception e) {
log.error("接口调用出错", e);
return ResultUtil.error(e.getMessage());
}
@ExceptionHandler(IllegalArgumentException.class)
public Object argExceptionHandler(Exception e) {
log.error("参数异常", e);
return ResultUtil.error(e.getMessage());
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public Object methodArgExceptionHandler(Exception e) {
log.error("方法参数异常", e);
return ResultUtil.error("Method parameter error.");
}
}
package vion.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
/**
* @author HlQ
* @date 2022/7/20
*/
@Configuration
public class MyBatisPlusConfig implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.fillHasGetter(metaObject, "createTime", new Date());
this.fillHasGetter(metaObject, "modifyTime", new Date());
this.fillHasGetter(metaObject, "updateTime", new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
this.fillHasGetter(metaObject, "modifyTime", new Date());
this.fillHasGetter(metaObject, "updateTime", new Date());
}
protected void fillHasGetter(MetaObject metaObject, String fieldName, Object fieldVal) {
if (metaObject.hasGetter(fieldName)) {
this.fillStrategy(metaObject, fieldName, fieldVal);
}
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
return interceptor;
}
}
package vion.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.Account;
import vion.model.Store;
import vion.service.IAccountSerrvice;
import vion.utils.ResultUtil;
import vion.service.IAccountService;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@Controller
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class AccountController {
@Autowired
private IAccountSerrvice accountSerrvice;
private final IAccountService accountService;
@GetMapping("/accounts")
@ResponseBody
public Object getAccountList(@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
List<Account> accountList=accountSerrvice.list();
accountList.sort(Comparator.comparing(Account::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(accountList);
if (accountList != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<Account> getAccountList(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
return accountService.page(Page.of(pageNum, pageSize));
}
@GetMapping("/account")
@ResponseBody
public Object getProductByID(@RequestParam(name = "id")Integer id){
Account account=accountSerrvice.getById(id);//accountDao.getAccountById(id);
if (account != null) {
return ResultUtil.success(account);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Account getProductByID(Integer id) {
return accountService.getById(id);
}
@PostMapping("/accounts")
@ResponseBody
public Object saveOrUpdate(@RequestBody Account data) {
try {
if(data.getId()==null){
data.setCreateTime(new Date());
}else{
data.setModifyTime(new Date());
}
Account account= accountSerrvice.saveAndReturn(data);
return ResultUtil.success(account);
}catch (Exception e) {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Account saveOrUpdate(@RequestBody Account data) {
accountService.save(data);
return data;
}
}
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vion.Global;
import vion.enums.ResultEnum;
import vion.dto.DictionaryDTO;
import vion.dto.DictionaryTypeDTO;
import vion.model.Dictionary;
import vion.model.DictionaryType;
import vion.model.Store;
import vion.service.IDictionarySerrvice;
import vion.service.IDictionaryTypeSerrvice;
import vion.utils.ResultUtil;
import java.util.Comparator;
import java.util.List;
import vion.service.IDictionaryService;
import vion.service.IDictionaryTypeService;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class DictionaryController {
@Autowired
private IDictionarySerrvice dictionarySerrvice;
@Autowired
private IDictionaryTypeSerrvice dictionaryTypeSerrvice;
private final IDictionaryService dictionaryService;
private final IDictionaryTypeService dictionaryTypeService;
private final Converter converter;
@GetMapping("/dictionarys")
@ResponseBody
public Object getDictionaryList(@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize,
@RequestParam(name = "type",required=false)String type){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Dictionary> wrapper=new QueryWrapper<>();
if(type!=null)
wrapper.eq("type",type);
List<Dictionary> dictionaryList=dictionarySerrvice.list(wrapper);
dictionaryList.sort(Comparator.comparing(Dictionary::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(dictionaryList);
if (dictionaryList != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<Dictionary> getDictionaryList(DictionaryDTO data) {
return dictionaryService.lambdaQuery(converter.convert(data, new Dictionary()))
.page(Page.of(data.getPageNum(), data.getPageSize()));
}
@GetMapping("/dictionary")
@ResponseBody
public Object getDictionaryByID(@RequestParam(name = "id")Integer id){
Dictionary dictionary=dictionarySerrvice.getById(id);
public Object getDictionaryByID(@RequestParam(name = "id") Integer id) {
return dictionaryService.getById(id);
if (dictionary != null) {
return ResultUtil.success(dictionary);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
}
@PostMapping("/dictionarys")
@ResponseBody
public Object saveOrUpdateDictionary(@RequestBody Dictionary data) {
try {
dictionarySerrvice.saveOrUpdate(data);
return ResultUtil.success();
}catch (Exception e) {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
@PostMapping("/dictionary")
public String saveOrUpdateDictionary(@RequestBody DictionaryDTO data) {
Dictionary dictionary = converter.convert(data, new Dictionary());
return dictionaryService.saveOrUpdate(dictionary) ? "成功" : "失败";
}
@GetMapping("/dictionaryTypes")
@ResponseBody
public Object getDictionaryTypeList(@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
PageHelper.startPage(pageNum,pageSize);
List<DictionaryType> dictionaryTypeList=dictionaryTypeSerrvice.list();
PageInfo pageInfo=new PageInfo(dictionaryTypeList,10);
if (dictionaryTypeList != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<DictionaryType> getDictionaryTypeList(DictionaryTypeDTO data) {
return dictionaryTypeService.lambdaQuery(converter.convert(data, new DictionaryType()))
.page(Page.of(data.getPageNum(), data.getPageSize()));
}
@GetMapping("/dictionaryType")
@ResponseBody
public Object getDictionaryTypeByID(@RequestParam(name = "id")Integer id){
DictionaryType dictionaryType=dictionaryTypeSerrvice.getById(id);
if (dictionaryType != null) {
return ResultUtil.success(dictionaryType);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Object getDictionaryTypeByID(@RequestParam Integer id) {
return dictionaryTypeService.getById(id);
}
@PostMapping("/dictionaryTypes")
@ResponseBody
public Object saveOrUpdateDictionaryType(@RequestBody DictionaryType data) {
try {
dictionaryTypeSerrvice.saveOrUpdate(data);
return ResultUtil.success();
}catch (Exception e) {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
@PostMapping("/dictionaryType")
public String saveOrUpdateDictionaryType(@RequestBody DictionaryTypeDTO data) {
DictionaryType dictionaryType = converter.convert(data, new DictionaryType());
return dictionaryTypeService.saveOrUpdate(dictionaryType) ? "成功" : "失败";
}
}
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.File;
import vion.model.Inspect;
import vion.model.Store;
import vion.service.IFileSerrvice;
import vion.dto.FileInfoDTO;
import vion.model.FileInfo;
import vion.service.IFileService;
import vion.utils.ResultUtil;
import vion.vo.StoreVO;
import vion.vo.ResultVO;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Date;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class FileController {
@Autowired
private IFileSerrvice fileSerrvice;
private final IFileService fileService;
private final Converter converter;
@Value("${fileurl:}")
@Value("${fileUrl:}")
private String fileurl;
@GetMapping("/files")
@ResponseBody
public Object getFiles(@RequestParam(name = "storeId",required=false)Integer store_id,
@RequestParam(name = "sourceId",required=false)Integer source_id,
@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<File> wrapper=new QueryWrapper<>();
if(store_id!=null)
wrapper.eq("store_id",store_id);
if(source_id!=null)
wrapper.eq("source_id",source_id);
List<File> fileList=fileSerrvice.list(wrapper);
fileList.sort(Comparator.comparing(File::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(fileList);
if (pageInfo != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
public Page<FileInfo> getFiles(FileInfoDTO data) {
return fileService.lambdaQuery(converter.convert(data, new FileInfo()))
.page(Page.of(data.getPageNum(), data.getPageSize()));
}
}
@PostMapping("/files")
@ResponseBody
public Map<String, Object> getFile(@RequestBody File file){
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
//添加文件附件
File tempFile=new File();
tempFile.setStoreId(file.getStoreId());
tempFile.setSourceId(file.getSourceId());
tempFile.setSourceType(file.getSourceType());//1项目、2工单预处理,3工单操作,4巡检
tempFile.setName(file.getName());
tempFile.setUrl(file.getUrl());
tempFile.setType(file.getType());
fileSerrvice.save(tempFile);
resultMap.put("msg_code", 200);
} catch (Exception e) {
e.printStackTrace();
resultMap.put("msg_code", 500);
}
return resultMap;
}
@GetMapping("/deleteFile")
@ResponseBody
public Map<String, Object> deleteFile(@RequestParam(name = "id")Integer id){
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
//解除文件关系
fileSerrvice.lambdaUpdate()
.setSql("id="+id)
.eq(File::getSourceId,-1)
.update();
resultMap.put("msg_code", 200);
} catch (Exception e) {
e.printStackTrace();
resultMap.put("msg_code", 500);
@DeleteMapping("/file/{id}")
public String remove(@PathVariable(name = "id") Integer id) {
FileInfo file = fileService.getById(id);
if (FileUtil.del(file.getUrl())) {
fileService.removeById(id);
return "文件删除成功";
} else {
return "文件删除失败";
}
return resultMap;
}
/*
* todo
* 手机端工单预处理提交
* 项目阶段修改,待联调 sourceType=1 这里的附件查询
* 工单处理上传附件
*/
@PostMapping("/upLoadFile")
public Map<String, Object> uploadFile(@RequestParam(name="file") MultipartFile file){
Map<String, Object> resultMap = new HashMap<String, Object>();
public ResultVO uploadFile(Long storeId, Long sourceId, FileInfo fileInfo, @RequestParam(name = "file") MultipartFile infile) {
try {
//上传url地址
String path=fileurl+"/"+file.getOriginalFilename();
java.io.File fileinfo=new java.io.File(path);
file.transferTo(fileinfo);
resultMap.put("msg_code", 200);
resultMap.put("fileUrl",path);
String filename = infile.getOriginalFilename() + "_" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
// String path = fileurl + FileUtil.FILE_SEPARATOR + storeId + FileUtil.FILE_SEPARATOR + sourceId + FileUtil.FILE_SEPARATOR + filename;
String path = fileurl + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
infile.transferTo(file);
String sha256 = SecureUtil.sha256(file).toUpperCase();
String extName = FileUtil.extName(file);
return ResultUtil.success(path);
} catch (IOException e) {
e.printStackTrace();
resultMap.put("msg_code", 500);
resultMap.put("message",e.getMessage());
}
return resultMap;
}
return ResultUtil.success();
@GetMapping("/downLoadFile")
public void downLoadFile(@RequestParam(name="fileurl")String fileurl,
@RequestParam(name="filename")String filename,
HttpServletResponse response){
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename="+filename);
java.io.File file=new java.io.File(fileurl);
/*String filename = infile.getOriginalFilename() + "_" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
String path = fileurl + FileUtil.FILE_SEPARATOR + fileInfo.getStoreId() + FileUtil.FILE_SEPARATOR + fileInfo.getSourceId() + FileUtil.FILE_SEPARATOR + filename;
// String path = fileurl + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
try {
FileInputStream fis=new FileInputStream(file);
OutputStream os=response.getOutputStream();
byte[] buffer=new byte[1024];
int length;
while((length=fis.read(buffer))>0){
os.write(buffer,0,length);
}
fis.close();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
infile.transferTo(file);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
fileInfo.setName(filename);
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
// 如果是预工单的话,可能是客户上传的文件
// fileInfo.setUploader();
fileService.save(fileInfo);
return ResultUtil.success();*/
}
public List<File> getFileList(Integer store_id,Integer source_id){
QueryWrapper<File> wrapper=new QueryWrapper<>();
if(store_id!=null)
wrapper.eq("store_id",store_id);
if(source_id!=null)
wrapper.eq("source_id",source_id);
List<File> fileList=fileSerrvice.list(wrapper);
return fileList;
@PostMapping("/uploadFile1")
public String uploadFile1(FileInfo fileInfo, @RequestParam(name = "files") MultipartFile[] files) throws IOException {
for (MultipartFile infile : files) {
String orgName = infile.getOriginalFilename();
String fileName = orgName.substring(0, orgName.lastIndexOf("."));
String fileExt = orgName.substring(orgName.lastIndexOf("."));
String filename = fileName + "_" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss") + fileExt;
String path = fileurl + FileUtil.FILE_SEPARATOR + fileInfo.getStoreId() + FileUtil.FILE_SEPARATOR + fileInfo.getSourceId() + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
infile.transferTo(file);
FileInfo tempFileInfo = new FileInfo();
tempFileInfo.setStoreId(fileInfo.getStoreId());
tempFileInfo.setSourceId(fileInfo.getSourceId());
tempFileInfo.setSourceType(fileInfo.getSourceType());
tempFileInfo.setName(filename);
tempFileInfo.setUrl(path);
tempFileInfo.setType(FileUtil.extName(file));
tempFileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
tempFileInfo.setUploader(fileInfo.getUploader());
fileService.save(tempFileInfo);
}
return "文件保存成功";
}
}
\ No newline at end of file
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import vion.Global;
import vion.enums.ResultEnum;
import vion.dto.InspectDTO;
import vion.model.Inspect;
import vion.model.Store;
import vion.service.IInspectSerrvice;
import vion.utils.ResultUtil;
import vion.service.IInspectService;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class InspectController {
@Autowired
private IInspectSerrvice inspectSerrvice;
private final IInspectService inspectService;
private final Converter converter;
@GetMapping("/inspects")
@ResponseBody
public Object getProductList(@RequestParam(name = "storeId",required=false)Integer store_id,
@RequestParam(name = "status",required=false)Integer status,
@RequestParam(name = "startdate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date startdate,
@RequestParam(name = "enddate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date enddate,
@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Inspect> wrapper=new QueryWrapper<>();
if(store_id!=null)
wrapper.eq("store_id",store_id);
if(status!=null)
wrapper.eq("status",status);
if(startdate!=null)
wrapper.between("inspect_date",startdate,enddate);
List<Inspect> inspectList=inspectSerrvice.list(wrapper);
inspectList.sort(Comparator.comparing(Inspect::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(inspectList);
if (inspectList != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<Inspect> getInspectList(InspectDTO data) {
return inspectService.getInspectList(data);
}
@GetMapping("/inspect")
@ResponseBody
public Object getProductByID(@RequestParam(name = "id")Integer id){
Inspect inspect=inspectSerrvice.getById(id);
if (inspect != null) {
return ResultUtil.success(inspect);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Inspect getProductByID(@RequestParam(name = "id") Integer id) {
return inspectService.getById(id);
}
@PostMapping("/inspects")
@ResponseBody
public Object saveOrUpdate(@RequestBody Inspect data) {
try {
if(data.getId()==null){
inspectSerrvice.save(data);
return ResultUtil.success();
}else{
data.setModifyTime(new Date());
Inspect inspect=inspectSerrvice.saveAndReturn(data);
return ResultUtil.success(inspect);
}
}catch (Exception e) {
// return ResultUtil.error(ResultEnum.SELECT_ERROR);
return e.getMessage().toString();
}
public String saveOrUpdate(@RequestBody InspectDTO data) {
Inspect inspect = converter.convert(data, new Inspect());
return inspectService.saveOrUpdate(inspect) ? "成功" : "失败";
}
@PostMapping("/updateInspectStatus")
@ResponseBody
public Object UpdateStatus(@RequestBody Inspect data) {
Date current=new Date();
UpdateWrapper updateWrapper=new UpdateWrapper();
updateWrapper.eq("id",data.getId());
updateWrapper.set("status",data.getStatus());
updateWrapper.set("modify_time",current);
updateWrapper.set("audit_date",current);
updateWrapper.set("reviewer",data.getReviewer());
public String UpdateStatus(@RequestBody InspectDTO data) {
boolean result = inspectService.lambdaUpdate()
.eq(Inspect::getId, data.getId())
.set(Inspect::getStatus, data.getStatus())
.set(Inspect::getAuditTime, new Date())
.set(Inspect::getReviewer, data.getReviewer())
//审核状态为已完成的时候更新完成时间(0进行中、1待审核、2已完成、3、驳回)
if(data.getStatus()==2){
updateWrapper.set("finish_date",current);
}else{
updateWrapper.set("finish_date",null);
}
boolean result= inspectSerrvice.update(updateWrapper);
if(result){
return ResultUtil.success();
}else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
.set(data.getStatus() == 2, Inspect::getFinishTime, new Date())
.update();
if (result) {
return "更新巡检状态成功";
} else {
return "更新巡检状态失败";
}
}
}
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vion.Global;
import vion.enums.ResultEnum;
import vion.dto.ProductDTO;
import vion.model.Product;
import vion.model.Store;
import vion.service.IProductSerrvice;
import vion.service.IStoreSerrvice;
import vion.utils.ResultUtil;
import vion.service.IProductService;
import vion.vo.ProductVO;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class ProductController {
@Autowired
private IProductSerrvice productSerrvice;
@Autowired
private IStoreSerrvice storeSerrvice;
private final IProductService productService;
private final Converter converter;
@GetMapping("/products")
@ResponseBody
public Object getProductList(@RequestParam(name = "accountId",required=false)Integer account_id,
@RequestParam(name = "storeId",required=false)Integer store_id,
@RequestParam(name = "name",required=false)String name,
@RequestParam(name = "brand",required=false)Integer brand,
@RequestParam(name = "functionary",required=false)Integer functionary,
@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Product> wrapper=new QueryWrapper<>();
if(store_id!=null){
wrapper.eq("store_id",store_id);
}
if(account_id!=null)
wrapper.eq("account_id",account_id);
if(name!=null)
wrapper.eq("name",name);
if(brand!=null)
wrapper.eq("brand",brand);
if(functionary!=null)
wrapper.eq("functionary",functionary);
List<Product> productList=productSerrvice.list(wrapper);
List<Store> storeList=storeSerrvice.list();
List<ProductVO> productVOS=new ArrayList<>();
ProductVO productVO;
for(Product pro:productList){
productVO=new ProductVO();
productVO.setStoreName(storeList.stream().filter(store -> store.getId().equals(pro.getStoreId())).collect(Collectors.toList()).get(0).getName());
productVO.setId(pro.getId());
productVO.setStoreId(pro.getStoreId());
productVO.setMaterialNo(pro.getMaterialNo());
productVO.setName(pro.getName());
productVO.setFunctionary(pro.getFunctionary());
productVO.setBrand(pro.getBrand());
productVO.setProductCount(pro.getProductCount());
productVO.setProductPrice(pro.getProductPrice());
productVO.setProductTotalPrice(pro.getProductTotalPrice());
productVO.setProductSubtotal(pro.getProductSubtotal());
productVO.setCreateTime(pro.getCreateTime());
productVO.setModifyTime(pro.getModifyTime());
productVO.setRemark(pro.getRemark());
productVO.setAccountId(pro.getAccountId());
productVOS.add(productVO);
}
productVOS.sort(Comparator.comparing(ProductVO::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(productList);
if (pageInfo != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<ProductVO> getProductList(ProductDTO productDTO) {
return productService.getProductList(productDTO);
}
@GetMapping("/product")
@ResponseBody
public Object getProductByID(@RequestParam(name = "projectId")Integer project_id){
Product product=productSerrvice.getById(project_id);
if (product != null) {
return ResultUtil.success(product);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Product getProductByID(@RequestParam Long projectId) {
return productService.getById(projectId);
}
@PostMapping("/products")
@ResponseBody
public Object saveOrUpdate(@RequestBody Product data) {
try {
if(data.getId()==null){
productSerrvice.save(data);
return ResultUtil.success();
}else{
data.setModifyTime(new Date());
Product product=productSerrvice.saveAndReturn(data);
return ResultUtil.success(product);
}
}catch (Exception e) {
//return ResultUtil.error(ResultEnum.SELECT_ERROR);
return e.getMessage().toString();
}
public String saveOrUpdate(@RequestBody ProductDTO productDTO) {
Product data = converter.convert(productDTO, new Product());
return productService.saveOrUpdate(data) ? "成功" : "失败";
}
}
\ No newline at end of file
package vion.controller;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vion.dto.ServiceOrderDTO;
import vion.model.Dictionary;
import vion.model.ServiceOrder;
import vion.service.IDictionaryService;
import vion.service.IServiceOrderService;
import vion.vo.ServiceOrderVO;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 服务单
*
* @author HlQ
* @date 2023/11/21
*/
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ServiceOrderController {
private final IServiceOrderService serviceOrderService;
private final IDictionaryService dictionaryService;
private final Converter converter;
@GetMapping("/order/{id}")
public ServiceOrder getOrderById(@PathVariable Long id) {
return serviceOrderService.getById(id);
}
@PostMapping("/order")
private Object save(@RequestBody ServiceOrderDTO serviceOrderDTO) {
Long count = serviceOrderService.lambdaQuery().eq(ServiceOrder::getTaskId, serviceOrderDTO.getTaskId()).count();
Assert.isFalse(count > 0, "该工单已存在服务单,不能重复创建!");
ServiceOrder serviceOrder = converter.convert(serviceOrderDTO, new ServiceOrder());
serviceOrder.setUnid(IdUtil.nanoId());
return serviceOrderService.save(serviceOrder) ? serviceOrder.getId() : "创建失败";
}
@PostMapping("/order/{id}")
private String update(@PathVariable Long id, @RequestBody ServiceOrderDTO serviceOrderDTO) {
ServiceOrder serviceOrder = converter.convert(serviceOrderDTO, new ServiceOrder());
serviceOrder.setId(id);
return serviceOrderService.updateById(serviceOrder) ? "更新成功" : "更新失败";
}
@DeleteMapping("/order/{id}")
private String remove(@PathVariable Long id) {
return serviceOrderService.removeById(id) ? "删除成功" : "删除失败";
}
@GetMapping("/order/sign/{unid}")
public ServiceOrderVO getOrderByUnid(@PathVariable String unid) {
// todo 字典加入缓存
List<Dictionary> dictionaryList = dictionaryService.lambdaQuery().eq(Dictionary::getType, "service_type").list();
Map<Integer, String> serviceTypeMap = dictionaryList.stream().collect(Collectors.toMap(Dictionary::getKey, Dictionary::getValue));
ServiceOrder order = serviceOrderService.lambdaQuery().eq(ServiceOrder::getUnid, unid).one();
ServiceOrderVO vo = converter.convert(order, new ServiceOrderVO());
vo.setServiceType(serviceTypeMap.get(order.getServiceType()));
return vo;
}
/**
* 签字专用更新接口
*
* @param unid 服务单unid
* @param serviceOrderDTO dto
* @return java.lang.String
*/
@PostMapping("/order/sign/{unid}")
public String updateByUnid(@PathVariable String unid, @RequestBody ServiceOrderDTO serviceOrderDTO) {
ServiceOrder serviceOrder = converter.convert(serviceOrderDTO, new ServiceOrder());
return serviceOrderService.lambdaUpdate().eq(ServiceOrder::getUnid, unid).update(serviceOrder) ? "提交成功" : "提交失败";
}
@GetMapping("/order/pushWechat")
public String sendOrder(Long id) {
return serviceOrderService.sendOrder(id);
}
}
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.*;
import vion.service.IAddressSerrvice;
import vion.service.IFileSerrvice;
import vion.service.IStoreSerrvice;
import vion.utils.ResultUtil;
import vion.vo.StatusVO;
import vion.vo.StoreListVO;
import vion.dto.StatusDTO;
import vion.dto.StoreDTO;
import vion.model.Store;
import vion.model.User;
import vion.service.IStoreService;
import vion.vo.StoreVO;
import java.util.*;
import java.util.List;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class StoreController {
@Autowired
private IStoreSerrvice storeSerrvice;
@Autowired
private IFileSerrvice fileSerrvice;
@Autowired
private IAddressSerrvice addressSerrvice;
@GetMapping("/stores")
@ResponseBody
public Object getStoreList(@RequestParam(name = "accountId",required=false)Integer account_id,
@RequestParam(name = "storeId",required=false)Integer store_id,
@RequestParam(name = "storenum",required=false)String storenum,
@RequestParam(name = "projectState",required=false)Integer project_state,
@RequestParam(name = "salesperson",required=false)String salesperson,
@RequestParam(name = "implementType",required=false)Integer implement_type,
@RequestParam(name = "startdate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date startdate,
@RequestParam(name = "enddate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date enddate,
@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Store> wrapper=new QueryWrapper<>();
if(store_id!=null){
wrapper.eq("id",store_id);
}
if(account_id!=null)
wrapper.eq("account_id",account_id);
if(storenum!=null)
wrapper.eq("storenum",storenum);
if(project_state!=null)
wrapper.eq("project_state",project_state);
if(salesperson!=null)
wrapper.eq("salesperson",salesperson);
if(implement_type!=null)
wrapper.eq("implement_type",implement_type);
if(startdate!=null)
wrapper.between("orderdate",startdate,enddate);
private final IStoreService storeService;
private final Converter converter;
List<Store> storeList=storeSerrvice.list(wrapper);
storeList.sort(Comparator.comparing(Store::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(storeList);
if (pageInfo != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
@GetMapping("/stores")
public Page<StoreVO> getStoreList(StoreDTO data) {
return storeService.getStoreList(data);
}
@GetMapping("/store")
@ResponseBody
public Object getStoreByID(@RequestParam(name = "id")Integer id){
StoreVO storeVo=new StoreVO();
Store store=storeSerrvice.getById(id);
storeVo.setId(store.getId());
storeVo.setNumber(store.getNumber());
storeVo.setName(store.getName());
storeVo.setStorenum(store.getStorenum());
storeVo.setAmount(store.getAmount());
storeVo.setOrderdate(store.getOrderdate());
storeVo.setSalesperson(store.getSalesperson());
storeVo.setWarrantyPeriod(store.getWarrantyPeriod());
storeVo.setCustomerName(store.getCustomerName());
storeVo.setProjectStage(store.getProjectStage());
storeVo.setProjectState(store.getProjectState());
storeVo.setContacts(store.getContacts());
storeVo.setRemark(store.getRemark());
storeVo.setAccountId(store.getAccountId());
storeVo.setContractCode(store.getContractCode());
storeVo.setImplementType(store.getImplementType());
//获取地址信息
Address address=addressSerrvice.getOne(Wrappers.<Address>lambdaQuery()
.eq(Address::getStoreId,id));
if(address!=null){
storeVo.setConsigneeName(address.getConsigneeName());
storeVo.setConsigneePhone(address.getConsigneePhone());
storeVo.setConsigneeAddress(address.getConsigneeAddress());
storeVo.setContractName(address.getContractName());
storeVo.setContractPhone(address.getContractPhone());
storeVo.setContractAddress(address.getContractAddress());
storeVo.setInvoiceName(address.getInvoiceName());
storeVo.setInvoicePhone(address.getInvoicePhone());
storeVo.setInvoiceAddress(address.getInvoiceAddress());
storeVo.setInvoiceInfo(address.getInvoiceInfo());
public StoreVO getStoreByID(@RequestParam(name = "id") Integer id) {
Store store = storeService.getById(id);
return converter.convert(store, StoreVO.class);
}
if (storeVo != null) {
return ResultUtil.success(storeVo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
}
@GetMapping("/storeList")
@ResponseBody
public Object getStoreList(@RequestParam(name = "accountId",required=false)Integer account_id){
QueryWrapper<Store> wrapper=new QueryWrapper<>();
if(account_id!=null)
wrapper.eq("account_id",account_id);
List<Store> storeList=storeSerrvice.list(wrapper);
List<StoreListVO> storeListVOS=new ArrayList<>();
for (Store store : storeList){
StoreListVO storeListVO=new StoreListVO();
storeListVO.setId(store.getId());
storeListVO.setName(store.getName());
storeListVOS.add(storeListVO);
}
storeListVOS.sort(Comparator.comparing(StoreListVO::getId));
if (storeListVOS != null) {
return ResultUtil.success(storeListVOS);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public List<StoreVO> getStoreList(Integer accountId) {
List<Store> storeList = storeService.lambdaQuery()
.eq(accountId != null, Store::getAccountId, accountId)
.list();
return converter.convert(storeList, StoreVO.class);
}
@PostMapping("/stores")
@ResponseBody
public Object saveOrUpdate(@RequestBody StoreVO storeVo,@RequestAttribute String userid) {
public String saveOrUpdate(@RequestBody StoreDTO data, @RequestHeader String token) {
User user = Global.USERNAME_MAP.get(token);
User user=Global.USERNAME_MAP.get(userid);
Store store=new Store();
store.setId(storeVo.getId());
store.setNumber(storeVo.getNumber());
store.setName(storeVo.getName());
store.setStorenum(storeVo.getStorenum());
store.setAmount(storeVo.getAmount());
store.setOrderdate(storeVo.getOrderdate());
store.setSalesperson(storeVo.getSalesperson());
store.setWarrantyPeriod(storeVo.getWarrantyPeriod());
store.setCustomerName(storeVo.getCustomerName());
store.setProjectStage(storeVo.getProjectStage());
store.setProjectState(storeVo.getProjectState());
store.setContacts(storeVo.getContacts());
store.setContractCode(storeVo.getContractCode());
store.setImplementType(storeVo.getImplementType());
store.setRemark(storeVo.getRemark());
store.setAccountId(storeVo.getAccountId());
if(storeVo.getId()!=null) {
Store store = converter.convert(data, Store.class);
if (data.getId() != null) {
store.setModifyUser(user.getId());
}else{
} else {
store.setCreateUser(user.getId());
}
try {
Store store1= storeSerrvice.saveAndReturn(store);
Address address=addressSerrvice.getOne(Wrappers.<Address>lambdaQuery()
.eq(Address::getStoreId,store1.getId()));
if(address==null){
address=new Address();
address.setStoreId(store1.getId());
}
address.setConsigneeName(storeVo.getConsigneeName());
address.setConsigneePhone(storeVo.getConsigneePhone());
address.setConsigneeAddress(storeVo.getConsigneeAddress());
address.setContractName(storeVo.getContractName());
address.setContractPhone(storeVo.getContractPhone());
address.setContractAddress(storeVo.getContractAddress());
address.setInvoiceName(storeVo.getInvoiceName());
address.setInvoicePhone(storeVo.getInvoicePhone());
address.setInvoiceAddress(storeVo.getInvoiceAddress());
address.setInvoiceInfo(storeVo.getInvoiceInfo());
addressSerrvice.saveOrUpdate(address);
return ResultUtil.success();
}catch (Exception e) {
// return ResultUtil.error(ResultEnum.SELECT_ERROR);
return e.getMessage().toString();
}
return storeService.saveOrUpdate(store) ? "成功" : "失败";
}
@PostMapping("/updateStoreStatus")
@ResponseBody
public Object updateStoreStage(@RequestBody StatusVO statusVo) {
try {
//更新项目阶段
//storeDao.updateStoreStage(statusVo.getSource_id(),statusVo.getProject_stage());
UpdateWrapper updateWrapper=new UpdateWrapper();
updateWrapper.eq("id",statusVo.getSourceId());
updateWrapper.set("project_stage",statusVo.getProjectStage());
storeSerrvice.update(updateWrapper);
//添加文件附件
File file=new File();
file.setStoreId(statusVo.getStoreId());
file.setSourceId(statusVo.getSourceId());
file.setSourceType(statusVo.getSourceType());//1项目、2工单预处理,3工单操作,4巡检
file.setName(statusVo.getName());
file.setUrl(statusVo.getUrl());
file.setType(statusVo.getType());
fileSerrvice.save(file);
return ResultUtil.success();
}catch (Exception e) {
// return ResultUtil.error(ResultEnum.SELECT_ERROR);
return e.getMessage().toString();
}
public Object updateStoreStage(StatusDTO statusDTO, @RequestHeader String token) {
return storeService.updateStoreStage(statusDTO, token);
}
}
package vion.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.*;
import vion.service.*;
import vion.service.impl.UserServiceImpl;
import vion.utils.ResultUtil;
import vion.vo.FaultLogVO;
import vion.vo.ProductVO;
import vion.dto.TaskDTO;
import vion.model.FaultLog;
import vion.service.IFaultLogService;
import vion.service.ITaskService;
import vion.vo.TaskVO;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class TaskController {
@Autowired
private ITaskTempSerrvice taskTempSerrvice;
@Autowired
private ITaskSerrvice taskSerrvice;
@Autowired
private IFileSerrvice fileSerrvice;
@Autowired
private IFaultLogSerrvice faultLogSerrvice;
@Autowired
private FileController fileController;
@Autowired
private IStoreSerrvice storeSerrvice;
@Autowired
private UserController userController;
@Autowired
private IUserSerrvice iUserSerrvice;
private final ITaskService taskService;
private final IFaultLogService faultLogService;
@GetMapping("/tasks")
@ResponseBody
public Object gettaskList(@RequestParam(name = "accountId",required=false)Integer account_id,
@RequestParam(name = "storeId",required=false)Integer store_id,
@RequestParam(name = "faultType",required=false)Integer fault_type,
@RequestParam(name = "status",required=false)Integer status,
@RequestParam(name = "startdate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date startdate,
@RequestParam(name = "enddate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date enddate,
@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<Task> wrapper=new QueryWrapper<>();
if(store_id!=null){
wrapper.eq("store_id",store_id);
}
if(account_id!=null)
wrapper.eq("account_id",account_id);
if(fault_type!=null)
wrapper.eq("fault_type",fault_type);
if(status!=null)
wrapper.eq("status",status);
if(startdate!=null)
wrapper.between("repair_date",startdate,enddate);
List<Task> taskList=taskSerrvice.list(wrapper);
List<Store> storeList=storeSerrvice.list();
List<TaskVO> taskVOS=new ArrayList<>();
TaskVO taskVO;
for(Task task:taskList){
taskVO=new TaskVO();
taskVO.setStoreName(storeList.stream().filter(store -> store.getId().equals(task.getStoreId())).collect(Collectors.toList()).get(0).getName());
taskVO.setId(task.getId());
taskVO.setStoreId(task.getStoreId());
taskVO.setRepairDate(task.getRepairDate());
taskVO.setFaultType(task.getFaultType());
taskVO.setFaultDescription(task.getFaultDescription());
taskVO.setRepairPeople(task.getRepairPeople());
taskVO.setRepairPhone(task.getRepairPhone());
taskVO.setStatus(task.getStatus());
taskVO.setFaultReason(task.getFaultReason());
taskVO.setSolveDate(task.getSolveDate());
taskVO.setSolveType(task.getSolveType());
taskVO.setSolveDescription(task.getSolveDescription());
taskVO.setCreateUser(task.getCreateUser());
taskVO.setActiveUser(task.getActiveUser());
taskVO.setCreateTime(task.getCreateTime());
taskVO.setModifyTime(task.getModifyTime());
taskVO.setRemark(task.getRemark());
taskVO.setAccountId(task.getAccountId());
taskVOS.add(taskVO);
}
taskVOS.sort(Comparator.comparing(TaskVO::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(taskVOS);
if (pageInfo != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<TaskVO> getTaskList(TaskDTO data) {
return taskService.getTaskList(data);
}
@GetMapping("/task")
@ResponseBody
public Object getTaskByID(@RequestParam(name = "taskId")Integer task_id){
Task task=taskSerrvice.getById(task_id);
List<File> files=fileController.getFileList(task.getStoreId(),task.getId());
TaskVO taskVO=new TaskVO();
taskVO.setId(task.getId());
taskVO.setStoreId(task.getStoreId());
taskVO.setRepairDate(task.getRepairDate());
taskVO.setFaultType(task.getFaultType());
taskVO.setFaultDescription(task.getFaultDescription());
taskVO.setRepairPeople(task.getRepairPeople());
taskVO.setRepairPhone(task.getRepairPhone());
taskVO.setStatus(task.getStatus());
taskVO.setFaultReason(task.getFaultReason());
taskVO.setSolveDate(task.getSolveDate());
taskVO.setSolveType(task.getSolveType());
taskVO.setSolveDescription(task.getSolveDescription());
taskVO.setCreateUser(task.getCreateUser());
taskVO.setActiveUser(task.getActiveUser());
taskVO.setCreateTime(task.getCreateTime());
taskVO.setModifyTime(task.getModifyTime());
taskVO.setRemark(task.getRemark());
taskVO.setAccountId(task.getAccountId());
taskVO.setFileList(files);
if (taskVO != null) {
return ResultUtil.success(taskVO);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public TaskVO getTaskById(Long taskId) {
return taskService.getTaskById(taskId);
}
@PostMapping("/tasks")
@ResponseBody
public Object saveOrUpdate(@RequestBody TaskVO data,@RequestAttribute String userid) {
try {
User user=Global.USERNAME_MAP.get(userid);
Task task=new Task();
task.setAccountId(data.getAccountId());
task.setStoreId(data.getStoreId());
task.setFaultType(data.getFaultType());
task.setFaultDescription(data.getFaultDescription());
task.setRepairDate(data.getRepairDate());
task.setRepairPeople(data.getRepairPeople());
task.setRepairPhone(data.getRepairPhone());
task.setStatus(data.getStatus());
if(task.getId()==null){
task.setCreateUser(user.getId());
}
task.setActiveUser(data.getActiveUser());
if(data.getTasktempId()!=null){
//得到预处理工单
TaskTemp taskTemp= taskTempSerrvice.getById(data.getTasktempId());
//更新预处理工单状态
taskTemp.setStatus(2);//状态(1待确认、2已确认)
taskTemp.setModifyTime(new Date());
taskTemp.setOperator(data.getActiveUser());
taskTemp.setStoreId(data.getStoreId());
taskTemp.setModifyTime(new Date());
taskTempSerrvice.saveOrUpdate(taskTemp);
//根据预处理工单更新附件的门店ID
fileSerrvice.lambdaUpdate()
.setSql("store_id="+data.getStoreId())
.eq(File::getSourceId,data.getId())
.update();
}
if(data.getId()==null){
//添加新工单
Task work=taskSerrvice.saveAndReturn(task);
if(data.getFileList()!=null){
//添加新工单的附件信息
if(work!=null){
File file;
for(File fileModel:data.getFileList()){
file=new File();
file.setId(fileModel.getId());
file.setStoreId(work.getStoreId());
file.setSourceId(work.getId());
file.setSourceType(3);//1项目、2工单预处理,3工单操作,4巡检
file.setName(fileModel.getName());
file.setUrl(fileModel.getUrl());
file.setType(fileModel.getType());
fileSerrvice.saveOrUpdate(file);
}
}
}
//添加工单处理日志
FaultLog faultLog=new FaultLog();
faultLog.setTaskId(work.getId());
faultLog.setStoreId(work.getStoreId());
faultLog.setOperator(user.getId());
faultLog.setContent("创建工单");
faultLog.setRemark("");
faultLogSerrvice.saveOrUpdate(faultLog);
//发送钉钉提醒
User activeUser= iUserSerrvice.getById(work.getActiveUser());
userController.sendMessage(activeUser.getUserid(),work.getId());
}
else{
task.setId(data.getId());
task.setSolveDate(data.getSolveDate());
task.setFaultReason(data.getFaultReason());
task.setSolveType(data.getSolveType());
task.setSolveDescription(data.getSolveDescription());
task.setRemark(data.getRemark());
taskSerrvice.saveOrUpdate(task);
//根据状态判断是否要添加工单处理日志(//状态:0待确认1进行中2已完成3挂起)
if(data.getStatus()==1){
FaultLog faultLog=new FaultLog();
faultLog.setTaskId(data.getId());
faultLog.setStoreId(data.getStoreId());
faultLog.setOperator(user.getId());
faultLog.setContent("工单正在处理中");
faultLog.setRemark(data.getSolveDescription());
faultLogSerrvice.saveOrUpdate(faultLog);
}
if(data.getStatus()==2){
FaultLog faultLog=new FaultLog();
faultLog.setTaskId(data.getId());
faultLog.setStoreId(data.getStoreId());
faultLog.setOperator(user.getId());
faultLog.setContent("工单处理完成");
faultLog.setRemark(data.getSolveDescription());
faultLogSerrvice.saveOrUpdate(faultLog);
}
if(data.getStatus()==3){
FaultLog faultLog=new FaultLog();
faultLog.setTaskId(data.getId());
faultLog.setStoreId(data.getStoreId());
faultLog.setOperator(user.getId());
faultLog.setContent("工单挂起");
faultLog.setRemark(data.getSolveDescription());
faultLogSerrvice.saveOrUpdate(faultLog);
}
//判断是否要添加工单处理文件
if(data.getFileList()!=null){
//添加新工单的附件信息
for(File fileModel:data.getFileList()){
File file=new File();
file.setId(fileModel.getId());
file.setStoreId(data.getStoreId());
file.setSourceId(data.getId());
file.setSourceType(3);//1项目、2工单预处理,3工单操作,4巡检
file.setName(fileModel.getName());
file.setUrl(fileModel.getUrl());
file.setType(fileModel.getType());
fileSerrvice.saveOrUpdate(file);
}
//判断是否有要删除的文件信息
}
}
return ResultUtil.success();
}catch (Exception e) {
return e.getMessage();
}
public Long saveOrUpdate(TaskDTO data, @RequestHeader String token) {
return taskService.circTask(data, token);
}
@GetMapping("/faultLogs")
@ResponseBody
public Object getFaultLogByID(@RequestParam(name = "storeId")Integer store_id,
@RequestParam(name = "taskId")Integer task_id){
List<FaultLog> faultLogs=faultLogSerrvice.list(Wrappers.<FaultLog>lambdaQuery()
.eq(FaultLog::getStoreId,store_id)
.eq(FaultLog::getTaskId,task_id));
if (faultLogs != null) {
return ResultUtil.success(faultLogs);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
}
@PostMapping("/faultLogs")
@ResponseBody
public Object saveAddFaultLog(@RequestBody FaultLogVO data,@RequestAttribute String userid) {
try {
User user=Global.USERNAME_MAP.get(userid);
FaultLog faultLog=new FaultLog();
faultLog.setTaskId(data.getTaskId());
faultLog.setStoreId(data.getStoreId());
faultLog.setOperator(user.getId());
faultLog.setContent(data.getContent());
faultLog.setRemark(data.getRemark());
faultLogSerrvice.saveOrUpdate(faultLog);
if(data.getFilename()!=null){
//添加文件附件
File file=new File();
file.setStoreId(data.getStoreId());
file.setSourceId(data.getTaskId());
file.setSourceType(3);//1项目、2工单预处理,3工单操作,4巡检
file.setName(data.getFilename());
file.setUrl(data.getFileurl());
file.setType(1);
//fileDao.addFile(file);
fileSerrvice.save(file);
public List<FaultLog> getFaultLogById(Integer storeId, Integer taskId) {
return faultLogService.lambdaQuery()
.eq(FaultLog::getStoreId, storeId)
.eq(FaultLog::getTaskId, taskId)
.orderByAsc(FaultLog::getCreateTime)
.list();
}
return ResultUtil.success();
}catch (Exception e) {
// return ResultUtil.error(ResultEnum.SELECT_ERROR);
return e.getMessage().toString();
}
}
}
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.test.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.File;
import vion.model.Store;
import vion.model.TaskTemp;
import vion.service.IFileSerrvice;
import vion.service.ITaskTempSerrvice;
import vion.utils.ResultUtil;
import vion.dto.TaskTempDTO;
import vion.service.ITaskTempService;
import vion.vo.TaskTempVO;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class TaskTempController {
@Autowired
private ITaskTempSerrvice taskTempSerrvice;
@Autowired
private IFileSerrvice fileSerrvice;
@Autowired
private FileController fileController;
private final ITaskTempService taskTempService;
@GetMapping("/taskTemps")
@ResponseBody
public Object getTaskTempList(@RequestParam(name = "storeName",required=false)String store_name,
@RequestParam(name = "storeId",required=false)Integer store_id,
@RequestParam(name = "startdate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date startdate,
@RequestParam(name = "enddate",required=false)
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date enddate,
@RequestParam(name = "status",required=false)Integer status,
@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
QueryWrapper<TaskTemp> wrapper=new QueryWrapper<>();
if(store_id!=null)
wrapper.eq("store_id",store_id);
if(store_name!=null)
wrapper.like("store_name",store_name);
if(status!=null)
wrapper.eq("status",status);
if(startdate!=null)
wrapper.between("repair_date",startdate,enddate);
List<TaskTemp> taskTempList= taskTempSerrvice.list(wrapper);
taskTempList.sort(Comparator.comparing(TaskTemp::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(taskTempList);
if (pageInfo != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<TaskTempVO> getTaskTempList(TaskTempDTO data) {
return taskTempService.getTaskTempList(data);
}
@GetMapping("/taskTemp")
@ResponseBody
public Object getTaskTempByID(@RequestParam(name = "id")Integer id){
TaskTemp taskTemp = taskTempSerrvice.getById(id);
TaskTempVO taskTempVO=new TaskTempVO();
List<File> files=fileController.getFileList(taskTemp.getStoreId(),taskTemp.getId());
taskTempVO.setId(taskTemp.getId());
taskTempVO.setStoreName(taskTemp.getStoreName());
taskTempVO.setRepairDate(taskTemp.getRepairDate());
taskTempVO.setFaultDescription(taskTemp.getFaultDescription());
taskTempVO.setRepairPeople(taskTemp.getRepairPeople());
taskTempVO.setRepairPhone(taskTemp.getRepairPhone());
taskTempVO.setStatus(taskTemp.getStatus());
taskTempVO.setCreateTime(taskTemp.getCreateTime());
taskTempVO.setFileList(files);
if (taskTempVO != null) {
return ResultUtil.success(taskTempVO);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public TaskTempVO getTaskTempById(Long id) {
return taskTempService.getTaskTempById(id);
}
@PostMapping("/taskTemps")
@ResponseBody
public Object saveOrUpdateTaskTemp(@RequestBody TaskTempVO data) {
try {
TaskTemp taskTemp=new TaskTemp();
taskTemp.setStoreName(data.getStoreName());
taskTemp.setRepairPeople(data.getRepairPeople());
taskTemp.setRepairPhone(data.getRepairPhone());
taskTemp.setRepairDate(data.getRepairDate());
taskTemp.setFaultDescription(data.getFaultDescription());
TaskTemp saveTaskTemp= taskTempSerrvice.saveAndReturn(taskTemp);
if(saveTaskTemp!=null){
if(data.getFileList()!=null){
File file;
for(File fileModel:data.getFileList()){
file=new File();
file.setId(fileModel.getId());
file.setStoreId(0);
file.setSourceId(saveTaskTemp.getId());
file.setSourceType(2);//1项目、2工单预处理,3工单操作,4巡检
file.setName(fileModel.getName());
file.setUrl(fileModel.getUrl());
file.setType(fileModel.getType());
fileSerrvice.saveOrUpdate(file);
}
}
}
return ResultUtil.success();
}catch (Exception e) {
//return ResultUtil.error(ResultEnum.SELECT_ERROR);
return e.getMessage();
}
@PostMapping("/taskTemp")
public String saveOrUpdateTaskTemp(TaskTempDTO data) {
return taskTempService.saveOrUpdTaskTemp(data);
}
@PostMapping("/updateTaskTempStatus")
@ResponseBody
public Object updateStoreStage(@RequestBody TaskTemp taskTemp) {
//更新预处理工单状态
UpdateWrapper updateWrapper=new UpdateWrapper();
updateWrapper.eq("id", taskTemp.getId());
updateWrapper.set("status",2);//状态(1待确认、2已确认)
updateWrapper.set("operator",taskTemp.getOperator());
updateWrapper.set("store_id",taskTemp.getStoreId());
updateWrapper.set("modify_time",new Date());
boolean result= taskTempSerrvice.update(updateWrapper);
//根据预处理工单跟新附件的门店ID
fileSerrvice.lambdaUpdate()
.setSql("store_id="+taskTemp.getStoreId())
.eq(File::getSourceId,taskTemp.getId())
.update();
if(result){
return ResultUtil.success();
}else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
}
}
package vion.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taobao.api.ApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.Store;
import vion.model.Task;
import vion.ding.DingMod;
import vion.ding.WechatMod;
import vion.dto.BaseDTO;
import vion.dto.DingDTO;
import vion.model.TaskTemp;
import vion.model.User;
import vion.service.IStoreSerrvice;
import vion.service.ITaskSerrvice;
import vion.service.IUserSerrvice;
import vion.utils.ResultUtil;
import vion.service.ITaskTempService;
import vion.service.IUserService;
import java.util.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@RestController
@RequestMapping(Global.BASE_URL)
@RequiredArgsConstructor
@Slf4j
public class UserController {
@Value("${appkey:}")
private String appkey;
@Value("${appsecret:}")
private String appsecret;
@Value("${agentid:}")
private Long agentid;
@Value("${dingurl:}")
private String dingurl;
@Value("${CorpId:}")
private String CorpId;
@Value("${SSOsecret:}")
private String SSOsecret;
@Autowired
private IUserSerrvice userSerrvice;
@Autowired
private ITaskSerrvice taskSerrvice;
@Autowired
private IStoreSerrvice storeSerrvice;
private final IUserService userService;
private final ITaskTempService taskTempService;
private final DingMod dingMod;
private final WechatMod wechatMod;
@GetMapping("/users")
@ResponseBody
public Object getUserList(@RequestParam(name = "pageNum")Integer pageNum,
@RequestParam(name = "pageSize")Integer pageSize){
//pageNum当前页,pageSize每页条数
Page page= PageHelper.startPage(pageNum,pageSize);
List<User> userList =userSerrvice.list();
userList.sort(Comparator.comparing(User::getId));
PageInfo pageInfo=new PageInfo<>(page);
pageInfo.setList(userList);
if (pageInfo != null) {
return ResultUtil.success(pageInfo);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
public Page<User> getUserList(BaseDTO dto) {
return userService.page(Page.of(dto.getPageNum(), dto.getPageSize()));
}
@GetMapping("/user")
@ResponseBody
public Object getUserByID(@RequestParam(name = "id")Integer id){
User user=userSerrvice.getById(id);
if (user != null) {
return ResultUtil.success(user);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
}
@PostMapping("/login")
@ResponseBody
public Object getUser(@RequestBody User data){
try {
QueryWrapper<User> wrapper=new QueryWrapper<>();
wrapper.eq("username",data.getUsername());
wrapper.eq("password",data.getPassword());
User user=userSerrvice.getOne(wrapper);
if (user != null) {
Global.USERNAME_MAP.put(user.getUserid(),user);
return ResultUtil.success(user);
} else {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
public User getUserByID(@RequestParam(name = "id") Integer id) {
return userService.getById(id);
}
} catch (Exception e) {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
}
}
@PostMapping("/users")
@ResponseBody
public Object getUserByID(@RequestBody User data){
try {
if(data.getId()==null){
userSerrvice.save(data);
return ResultUtil.success();
}else{
data.setModifyTime(new Date());
User user1=userSerrvice.saveAndReturn(data);
return ResultUtil.success(user1);
}
}catch (Exception e) {
return ResultUtil.error(ResultEnum.SELECT_ERROR);
@PostMapping("/user")
public String update(@RequestBody List<User> data) {
return Opt.ofEmptyAble(data).map(userService::updateBatchById).orElse(false) ? "更新成功" : "更新失败";
}
@GetMapping("/user/{token}")
public User getUserByToken(@PathVariable String token) {
return Global.USERNAME_MAP.get(token);
}
//获取钉钉token
public String getToken(){
DingTalkClient client=new DefaultDingTalkClient(dingurl+"/gettoken");
OapiGettokenRequest req=new OapiGettokenRequest();
req.setAppkey(appkey);
req.setAppsecret(appsecret);
try {
OapiGettokenResponse rep=client.execute(req);
return rep.getAccessToken();
} catch (ApiException e) {
e.printStackTrace();
return null;
}
@GetMapping("/orgTree")
public List<Tree<String>> getOrgTree(String deptId) {
return userService.getOrgTree(deptId);
}
//获取钉钉在职员工列表
public void getDingUserList(){
//获取token
String access_token=getToken();
String userIds="";
Long offset=0L;//分页游标,从0开始
Boolean flag=true;
//一次最多获取50个。所以多次获取
while(flag){
//获取在职员工id集合
DingTalkClient client=new DefaultDingTalkClient(dingurl+"/topapi/smartwork/hrm/employee/queryonjob");
OapiSmartworkHrmEmployeeQueryonjobRequest req=new OapiSmartworkHrmEmployeeQueryonjobRequest();
req.setStatusList("2,3,5,-1");
req.setOffset(offset);
req.setSize(50L);
try {
OapiSmartworkHrmEmployeeQueryonjobResponse rep=client.execute(req,access_token);
if(rep.getSuccess()==true){
List<String> userList= rep.getResult().getDataList();
if(rep.getResult().getNextCursor()!=null){
//设置下一页的游标
offset=rep.getResult().getNextCursor();
}else{
flag=false;
}
//用户ID拼接
for(int j=0;j<userList.size();j++){
userIds+=userList.get(j)+",";
}
}
} catch (ApiException e) {
e.printStackTrace();
}
@GetMapping("/ding/callback/{target}")
public Object dingCallback(@PathVariable String target, DingDTO dto, HttpServletResponse res) {
return dingMod.dingCallback(target, dto, res);
}
//根据在职员工id获取员工信息
DingTalkClient client = new DefaultDingTalkClient(dingurl+"/topapi/smartwork/hrm/employee/v2/list");
OapiSmartworkHrmEmployeeV2ListRequest req = new OapiSmartworkHrmEmployeeV2ListRequest();
req.setUseridList(userIds.substring(0,userIds.length()-1));
req.setFieldFilterList("sys00-name,sys00-mobile");//用户名,手机号
req.setAgentid(agentid);
try {
OapiSmartworkHrmEmployeeV2ListResponse rep=client.execute(req,access_token);
if(rep.getSuccess()==true){
//用户信息
User user=new User();
//钉钉用户集合
List<OapiSmartworkHrmEmployeeV2ListResponse.EmpRosterFieldVo> empRosterFieldVoList= rep.getResult();
for(int m=0;m<empRosterFieldVoList.size();m++){
OapiSmartworkHrmEmployeeV2ListResponse.EmpRosterFieldVo empRosterFieldVo=empRosterFieldVoList.get(m);
user.setUserid(empRosterFieldVo.getUserid());
List<OapiSmartworkHrmEmployeeV2ListResponse.EmpFieldDataVo> empFieldDataVoList= empRosterFieldVo.getFieldDataList();
for(int n=0;n<empFieldDataVoList.size();n++){
OapiSmartworkHrmEmployeeV2ListResponse.EmpFieldDataVo empFieldDataVo=empFieldDataVoList.get(n);
//根据fieldcode判断用户属性
if(empFieldDataVo.getFieldCode().equals("sys00-name")){
user.setUsername(empFieldDataVo.getFieldValueList().get(0).getValue());
}
else if(empFieldDataVo.getFieldCode().equals("sys00-mobile")){
user.setPhone(empFieldDataVo.getFieldValueList().get(0).getValue());
}
}
//判断用户是否已经添加过
//User userInfo=userDao.getUserByUserid(empRosterFieldVo.getUserid());
User userInfo=userSerrvice.getOne(
Wrappers.<User>lambdaQuery()
.eq(User::getUserid,empRosterFieldVo.getUserid()));
if(userInfo!=null){
user.setModifyTime(new Date());
// userDao.updateUserByUserid(user);
userSerrvice.saveOrUpdate(user);
}else {
userSerrvice.save(user);
}
}
}
} catch (ApiException e) {
e.printStackTrace();
}
}
//钉钉消息推送
public String sendMessage(String userid,Integer task_id){
DingTalkClient client=new DefaultDingTalkClient(dingurl+"/topapi/message/corpconversation/asyncsend_v2");
try {
//获取token
String access_token= getToken();
//获取工单信息
// Task task=taskDao.getTaskByID(task_id);
Task task=taskSerrvice.getById(task_id);
// User user=userDao.getUserById(task.getRepair_people());
User user=userSerrvice.getById(task.getRepairPeople());
//获取门店信息
Store store=storeSerrvice.getById(task.getStoreId());
OapiMessageCorpconversationAsyncsendV2Request request=new OapiMessageCorpconversationAsyncsendV2Request();
request.setAgentId(agentid);
request.setUseridList(userid);
request.setToAllUser(false);
OapiMessageCorpconversationAsyncsendV2Request.Msg msg=new OapiMessageCorpconversationAsyncsendV2Request.Msg();
msg.setMsgtype("text");
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
msg.setActionCard(new OapiMessageCorpconversationAsyncsendV2Request.ActionCard());
msg.getActionCard().setTitle("工单派单");
msg.getActionCard().setMarkdown("门店信息:"+store.getName());//标题
msg.getActionCard().setSingleTitle(
"报修人:"+user.getUsername()+
"\\n联系方式:"+task.getRepairPhone()+
"\\n故障描述:"+task.getFaultDescription());//工单派件内容
msg.getActionCard().setSingleUrl("https://www.dingtalk.com");
msg.setMsgtype("action_card");
request.setMsg(msg);
OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(request, access_token);
System.out.println(rsp.getBody());
return null;
} catch (ApiException e) {
e.printStackTrace();
return null;
}
}
/**
* 应用管理后台免登
* @author openapi@dingtalk
*
*/
@RequestMapping(value = "/getAdminInfo", method = RequestMethod.GET)
public Object getAdminInfo(@RequestParam("code")String requestAuthCode) {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sso/gettoken");
OapiSsoGettokenRequest request = new OapiSsoGettokenRequest();
// 企业Id
request.setCorpid(CorpId);
//秘钥SSOsecret
//这里必须填写专属的SSOsecret。
request.setCorpsecret(SSOsecret);
request.setHttpMethod("GET");
OapiSsoGettokenResponse response = null;
try {
response = client.execute(request);
} catch (ApiException e) {
e.printStackTrace();
return null;
}
// 获取企业的access_token
String access_token = response.getAccessToken();
// 获取应用管理员的身份信息
OapiSsoGetuserinfoResponse getAdminInfo = getAdminUserInfo(requestAuthCode, access_token);
Map<String, Object> returnMap = new HashMap<String, Object>();
returnMap.put("info", getAdminInfo);
return returnMap;
}
/**
* 根据保存的code值和获取的access_token,获取应用管理身份信息
* openapi@dingtalk
* @param code
* @param access_token
* @return
* OapiSsoGetuserinfoResponse
* 2020-11-3
*/
public OapiSsoGetuserinfoResponse getAdminUserInfo(String code,String access_token) {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sso/getuserinfo");
OapiSsoGetuserinfoRequest request = new OapiSsoGetuserinfoRequest();
request.setCode(code);
request.setHttpMethod("GET");
OapiSsoGetuserinfoResponse response;
try {
response = client.execute(request, access_token);
} catch (ApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
@GetMapping("/wechat/callback")
public Object wechatCallback(String code, Long taskTempId) {
Object obj = wechatMod.wechatCallback(code);
if (obj instanceof String) {
return taskTempService.lambdaUpdate().set(TaskTemp::getOpenid, obj).eq(TaskTemp::getId, taskTempId).update() ? new ModelAndView("weChatNeedAttention") : new ModelAndView("weChatError");
} else {
return obj;
}
return response;
}
}
package vion.cron;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import vion.ding.DingMod;
import vion.model.Task;
import vion.model.User;
import vion.service.ITaskService;
import vion.service.IUserService;
import java.util.List;
/**
* @author HlQ
* @date 2023/11/13
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class TaskRunner {
private final IUserService userService;
private final ITaskService taskService;
private final DingMod dingMod;
@Scheduled(cron = "0 0 17 * * ?")
void pushUndoneTask() {
log.info("开始推送未完成工单");
List<Task> taskList = taskService.list(Wrappers.<Task>lambdaQuery().notIn(Task::getStatus, 3, 5));
// todo 需要异步发送吗?
taskList.forEach(task -> {
Long activeUser = task.getActiveUser();
User user = userService.lambdaQuery().eq(User::getId, activeUser).one();
dingMod.sendMessage(buildMsg(user));
});
log.info("推送未完成工单完成");
}
JSONObject buildMsg(User user) {
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
jsonObj.set("userid_list", user.getUserid());
JSONObject msg = new JSONObject();
JSONObject content = new JSONObject();
content.set("title", "请查看您未完成的工单~_~");
content.set("markdown", "请查看您未完成的工单" +
" \n 发送时间:" + DateUtil.now());
content.set("btn_orientation", "1");
JSONArray jsonArray = new JSONArray();
jsonArray.add(new JSONObject().set("title", "查看详情").set("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FuserId%3D" + user.getId()));
content.set("btn_json_list", jsonArray);
msg.set("msgtype", "action_card");
msg.set("action_card", content);
jsonObj.set("msg", msg);
return jsonObj;
}
}
\ No newline at end of file
package vion.ding;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import vion.Global;
import vion.dto.DingDTO;
import vion.model.Dept;
import vion.model.User;
import vion.service.IDeptService;
import vion.service.IUserService;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @author HlQ
* @date 2023/11/13
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class DingMod {
@Value("${appkey:}")
private String appKey;
@Value("${appsecret:}")
private String appSecret;
private final IUserService userService;
private final IDeptService deptService;
private final TimedCache<String, String> timedCache = CacheUtil.newTimedCache(7000 * 1000);
/**
* 获取钉钉token
*
* @return java.lang.String
*/
public String getToken() {
if (timedCache.containsKey("accessToken")) {
return timedCache.get("accessToken", false);
}
String res = HttpUtil.get("https://oapi.dingtalk.com/gettoken?appkey=" + appKey + "&appsecret=" + appSecret);
JSONObject jsonObj = JSONUtil.parseObj(res);
if (jsonObj.containsKey("access_token")) {
String accessToken = jsonObj.getStr("access_token");
timedCache.put("accessToken", accessToken);
return accessToken;
} else {
return "";
}
}
/**
* 获取钉钉员工列表
*/
public void getDingUserList() {
String accessToken = getToken();
List<String> userIdList = new ArrayList<>();
Long offset = 0L;
boolean flag = true;
while (flag) {
JSONObject paramJson = new JSONObject();
// 2:试用期 3:正式 5:待离职 -1:无状态
paramJson.set("status_list", "2,3,5,-1");
paramJson.set("size", 50);
paramJson.set("offset", offset);
String res = HttpUtil.post("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob?access_token=" + accessToken, paramJson.toString());
JSONObject jsonObject = JSONUtil.parseObj(res);
if (jsonObject.getBool("success", false)) {
JSONArray jsonArray = jsonObject.getJSONObject("result").getJSONArray("data_list");
List<String> list = jsonArray.toList(String.class);
userIdList.addAll(list);
Long nextCursor = jsonObject.getJSONObject("result").getLong("next_cursor");
if (ObjUtil.isNotNull(nextCursor)) {
offset = nextCursor;
} else {
flag = false;
}
}
}
if (CollUtil.isEmpty(userIdList)) {
log.error("获取钉钉用户id列表为空");
return;
}
List<List<String>> userIdListSplit = ListUtil.split(userIdList, 90);
userIdListSplit.forEach(tmpList -> {
JSONObject paramJson = new JSONObject();
paramJson.set("agentid", 2358374016L);
paramJson.set("userid_list", String.join(",", tmpList));
paramJson.set("field_filter_list", "sys00-name,sys00-mobile,sys00-mainDeptId,sys00-mainDept,sys01-employeeStatus");
String res = HttpUtil.post("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list?access_token=" + accessToken, paramJson.toString());
JSONObject jsonObject = JSONUtil.parseObj(res);
if (jsonObject.getBool("success", false)) {
JSONArray resArr = jsonObject.getJSONArray("result");
for (Object o : resArr) {
User user = new User();
JSONObject jsonObj = JSONUtil.parseObj(o);
String userid = jsonObj.getStr("userid");
user.setUserid(userid);
JSONArray dataArr = jsonObj.getJSONArray("field_data_list");
for (Object o1 : dataArr) {
JSONObject tmpObj = JSONUtil.parseObj(o1);
if (StrUtil.equals("sys00-name", tmpObj.getStr("field_code"))) {
user.setUsername(tmpObj.getJSONArray("field_value_list").getByPath("[0].value", String.class));
} else if (StrUtil.equals("sys00-mobile", tmpObj.getStr("field_code"))) {
user.setPhone(Opt.ofNullable(tmpObj.getJSONArray("field_value_list").getByPath("[0].value", String.class)).orElse(""));
} else if (StrUtil.equals("sys00-mainDeptId", tmpObj.getStr("field_code"))) {
user.setDeptId(tmpObj.getJSONArray("field_value_list").getByPath("[0].value", Long.class));
} else if (StrUtil.equals("sys01-employeeStatus", tmpObj.getStr("field_code"))) {
user.setEmployeeStatus(tmpObj.getJSONArray("field_value_list").getByPath("[0].value", Integer.class));
}
}
userService.saveOrUpdate(user, Wrappers.<User>lambdaUpdate().eq(User::getUserid, userid));
}
}
});
}
/**
* 获取钉钉部门列表
*/
public void getDeptList() {
String accessToken = getToken();
List<Long> deptIdList = ListUtil.toList(1L);
int idx = 0;
while (idx < deptIdList.size()) {
JSONObject paramJson = new JSONObject();
// 2:试用期 3:正式 5:待离职 -1:无状态
Long value = deptIdList.get(idx++);
paramJson.set("dept_id", value);
String res = HttpUtil.post("https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=" + accessToken, paramJson.toString());
JSONObject jsonObject = JSONUtil.parseObj(res);
if (StrUtil.equals("ok", jsonObject.getStr("errmsg"))) {
JSONArray resArr = jsonObject.getJSONArray("result");
if (CollUtil.isNotEmpty(resArr)) {
for (Object o : resArr) {
Dept dept = new Dept();
JSONObject jsonObj = JSONUtil.parseObj(o);
Long deptId = jsonObj.getLong("dept_id");
dept.setDeptId(deptId);
deptIdList.add(deptId);
dept.setParentId(jsonObj.getLong("parent_id"));
dept.setDeptName(jsonObj.getStr("name"));
deptService.saveOrUpdate(dept, Wrappers.<Dept>lambdaUpdate().eq(Dept::getDeptId, deptId));
}
}
}
}
}
/**
* 钉钉消息推送
*/
public String sendMessage(JSONObject msg) {
String token = getToken();
return HttpUtil.post("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=" + token, msg.toString());
}
/**
* 钉钉回调接口
*
* @param target login,inside 区分是钉钉扫码登录还是钉钉内打开链接
* @param dto dto
* @param res httpServletResponse
* @return java.lang.Object
*/
public Object dingCallback(String target, DingDTO dto, HttpServletResponse res) {
if (StrUtil.equals(target, "login")) {
JSONObject jsonObject = new JSONObject();
jsonObject.set("clientId", appKey);
jsonObject.set("clientSecret", appSecret);
jsonObject.set("code", dto.getAuthCode());
jsonObject.set("grantType", "authorization_code");
String tokenRes = HttpUtil.post("https://api.dingtalk.com/v1.0/oauth2/userAccessToken", jsonObject.toString());
JSONObject tokenObj = JSONUtil.parseObj(tokenRes);
if (!tokenObj.containsKey("accessToken")) {
log.error("钉钉回调接口获取accessToken失败:{}", tokenObj);
return tokenObj;
}
String accessToken = tokenObj.getStr("accessToken");
HttpResponse response = HttpRequest.get("https://api.dingtalk.com/v1.0/contact/users/me")
.header("x-acs-dingtalk-access-token", accessToken)
.execute();
if (!response.isOk()) {
log.error("钉钉回调接口获取unionid失败:{}", response.body());
return response.body();
}
JSONObject userInfoObj = JSONUtil.parseObj(response.body());
String unionId = userInfoObj.getStr("unionId");
String response1 = HttpUtil.post("https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=" + getToken(), "{\"unionid\":\"" + unionId + "\"}");
JSONObject useridObj = JSONUtil.parseObj(response1);
if (!useridObj.containsKey("result")) {
log.error("钉钉回调接口获取userid失败:{}", userInfoObj);
return useridObj;
}
String userid = useridObj.getJSONObject("result").getStr("userid");
User user = userService.lambdaQuery().select(User::getId, User::getUserid, User::getUsername, User::getPhone).eq(User::getUserid, userid).one();
user.setToken(accessToken);
Global.USERNAME_MAP.put(accessToken, user);
return user;
} else if (StrUtil.equals(target, "inside")) {
String response = HttpUtil.post(buildSignUrl(), "{\"tmp_auth_code\":\"" + dto.getCode() + "\"}");
JSONObject userInfoObj = JSONUtil.parseObj(response);
if (!userInfoObj.containsKey("user_info")) {
log.error("钉钉回调接口获取unionid失败:{}", userInfoObj);
return userInfoObj;
}
String unionId = userInfoObj.getJSONObject("user_info").getStr("unionid");
String response1 = HttpUtil.post("https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=" + getToken(), "{\"unionid\":\"" + unionId + "\"}");
JSONObject useridObj = JSONUtil.parseObj(response1);
if (!useridObj.containsKey("result")) {
log.error("钉钉回调接口获取userid失败:{}", useridObj);
return useridObj;
}
String userid = useridObj.getJSONObject("result").getStr("userid");
User user = userService.lambdaQuery().select(User::getId, User::getUserid, User::getUsername, User::getPhone).eq(User::getUserid, userid).one();
String token = IdUtil.simpleUUID();
user.setToken(token);
Global.USERNAME_MAP.put(token, user);
try {
if (ObjUtil.isAllNotEmpty(dto.getStoreId(), dto.getTaskId())) {
res.sendRedirect("https://yunwei.vionyun.com:8443/wap/workflow-process?token=" + token + "&storeId=" + dto.getStoreId() + "&taskId=" + dto.getTaskId());
} else if (ObjUtil.isNotEmpty(dto.getTaskTempId())) {
res.sendRedirect("https://yunwei.vionyun.com:8443/wap/workflow-assign?token=" + token + "&id=" + dto.getTaskTempId());
} else if (ObjUtil.isNotEmpty(dto.getUserId())) {
res.sendRedirect("https://yunwei.vionyun.com:8443/wap/workflow-list?token=" + token + "&activeUser=" + dto.getUserId());
}
} catch (IOException e) {
log.error("钉钉回调接口重定向失败!", e);
return "钉钉回调接口重定向失败,请联系相关人员";
}
return "success";
}
return "钉钉回调异常,请联系相关人员";
}
/**
* 构建获取用户信息url
*/
String buildSignUrl() {
try {
String appSecret = "Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt";
String timestamp = String.valueOf(System.currentTimeMillis());
HMac hMac = SecureUtil.hmacSha256(appSecret);
byte[] signBytes = hMac.digest(timestamp);
String sign = Base64.encode(signBytes);
String encode = null;
encode = URLEncoder.encode(sign, "UTF-8");
String encodeSign = encode.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F").replace("=", "%3D");
return StrUtil.format("https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=dingkrzwks0jpi2di3uo&timestamp={}&signature={}", timestamp, encodeSign);
} catch (UnsupportedEncodingException e) {
log.error("通过appSecret计算出来的签名值失败", e);
}
return "";
}
}
package vion.ding;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
/**
* @author HlQ
* @date 2023/11/21
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class WechatMod {
private final WxMpService wxMpService;
/**
* 微信扫码获取用户 openid
*
* @param code
* @return java.lang.Object
*/
public Object wechatCallback(String code) {
try {
WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(accessToken, null);
return wxMpUser.getOpenid();
} catch (WxErrorException e) {
log.error("调用微信接口异常!", e);
}
return new ModelAndView("weChatError");
}
/**
* 生成微信网页授权链接
* @param taskTempId 预工单 id
* @return java.lang.String
*/
public String genCodeUrl(Long taskTempId) {
String url = StrUtil.format("https://yunwei.vionyun.com/yunwei/api/wechat/callback?taskTempId={}", taskTempId);
return wxMpService.getOAuth2Service().buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
}
public String sendMsg(String templateId, String openId, List<WxMpTemplateData> wxMpTemplateDataList, String url) {
try {
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(openId)
.templateId(templateId)
.data(wxMpTemplateDataList)
.url(url)
.build();
String s = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
log.info("微信消息推送成功,msgid:{}", s);
return "微信公众号消息推送成功";
} catch (WxErrorException e) {
log.error("调用微信接口发送模板消息异常!", e);
}
return "微信公众号消息推送失败";
}
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
/**
* @author HlQ
* @date 2023/11/24
*/
@Getter
@Setter
public class BaseDTO {
private Integer pageNum = 1;
private Integer pageSize = 10;
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class DictionaryDTO extends BaseDTO {
private Long id;
private String type;
private Integer key;
private String value;
private String remark;
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class DictionaryTypeDTO extends BaseDTO {
private Long id;
private String name;
private String type;
private String remark;
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
/**
* @author HlQ
* @date 2023/11/25
*/
@Getter
@Setter
public class DingDTO {
/** 微信拼接的两个 code 参数 */
private String authCode;
private String code;
/** 项目id */
private Long storeId;
/** 工单id */
private Long taskId;
/** 预工单id */
private Long taskTempId;
/** 用户id */
private Long userId;
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FileInfoDTO extends BaseDTO {
private Long id;
/** 门店id */
private Long storeId;
/** 文件扩展名 */
private String type;
/** 文件来源(1项目、2工单预处理,3工单操作,4巡检) */
private Integer sourceType;
/** 文件来源id */
private Long sourceId;
/** 文件名称 */
private String name;
/** 文件地址 */
private String url;
/** 备注 */
private String remark;
/** sha256 */
private String sha256;
/** 上传人 */
private String uploader;
}
package vion.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Getter
@Setter
public class InspectDTO extends BaseDTO {
/** 自增列 */
private Long id;
/** 门店id */
private Long storeId;
/** 巡检时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date inspectTime;
/** 巡检方式(0远程、1现场) */
private Integer type;
/** 状态(0进行中、1待审核、2已完成、3、驳回) */
private Integer status;
/** 巡检人 */
private Integer inspectUser;
/** 审核人 */
private Integer reviewer;
/** 巡检时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date finishTime;
/** 审核时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date auditTime;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startdate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date enddate;
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ProductDTO extends BaseDTO {
private Long id;
/** 物料编号 */
private String materialNo;
/** 门店id */
private Long storeId;
/** 门店名称 */
private String storeName;
/** 产品名称 */
private String name;
/** 产品型号 */
private Integer functionary;
/** 品牌 */
private Integer brand;
/** 订货数量 */
private Integer productCount;
/** 订货单价 */
private Float productPrice;
/** 定后价小计(单价乘以数量) */
private Float productSubtotal;
/** 订货总价 */
private Float productTotalPrice;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
}
package vion.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* @author HlQ
* @date 2023/11/23
*/
@Getter
@Setter
public class ServiceOrderDTO extends BaseDTO {
/** 项目名称 */
private String projectName;
/** 报修人 */
private String submitter;
/** 报修人手机号码 */
private String submitPhone;
/** 报修时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date submitTime;
/** 维修人 */
private String repairPeople;
/** 维修人手机号码*/
private String repairPhone;
/** 部门 */
private String dept;
/** 服务方式(1.电话支持 2.远程服务 3.现场服务) */
private Integer serviceType;
/** 耗时 */
private Double time;
/** 故障内容 */
private String faultContent;
/** 维修结果 */
private String repairRes;
/** 客户评价 */
private String review;
/** 工单id */
private Long taskId;
/** 服务单状态 */
private Integer state;
/** 五星好评 */
private Integer stars;
/** 签字图片base64 */
private String signPic;
/** 签字时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date signTime;
/** 完成时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date finishTime;
}
package vion.dto;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Data
public class StatusDTO {
/** 门店id */
private Long storeId;
/** 阶段 */
private Integer projectStage;
/** 文件来源 */
private Integer sourceType;
/** 来源id */
private Long sourceId;
/** 文件类型 */
private Integer type;
/** 名称 */
private String name;
/** 地址 */
private String url;
private MultipartFile[] files;
}
package vion.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* 门店信息
*/
@Getter
@Setter
public class StoreDTO extends BaseDTO {
private Long id;
private String storenum;
/** 门店名称 */
private String name ;
/** 流水号 */
private String number;
/** 合同编码 */
private String contractCode;
/** 合同金额 */
private Float amount;
/** 签订日期 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date orderdate;
/** 销售人 */
private Integer salesperson;
/** 质保期 */
private Integer warrantyPeriod;
/** 客户姓名 */
private String customerName;
/** 实施类型:0纯供货、1供货+安装、3续保、4维修 */
private Integer implementType;
/** 项目状态:0待确认、1进行中、2已完成、3挂起 */
private Integer projectState;
/** 联系人(多个联系人逗号隔开) */
private String contacts;
/** 创建者 */
private Long createUser;
/** 修改者 */
private Long modifyUser;
/** 备注 */
private String remark;
/** 项目阶段 */
private Integer projectStage;
/** 集团id */
private Long accountId;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startdate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date enddate;
}
package vion.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;
@Getter
@Setter
public class TaskDTO extends BaseDTO {
private Long id;
/** 门店id */
private Long storeId;
/** 报修日期 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date repairTime;
/** 故障类型 */
private Integer faultType;
/** 故障说明 */
private String faultDescription;
/** 报修人 */
private String repairPeople;
/** 报修人联系方式 */
private String repairPhone;
/** 状态:0待确认1进行中2已完成3挂起 */
private Integer status;
/** 解决日期 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date solveDate;
/** 故障原因 */
private String faultReason;
/** 解决措施:0产品BUG、1使用问题、2需求问题 */
private Integer solveType;
/** 解决故障描述 */
private String solveDescription;
/** 创建者 */
private Long createUser;
/** 当前处理人 */
private Long activeUser;
/** 截止日期 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date expDate;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
private String uuid;
/** 预工单id */
private Long tasktempId;
private MultipartFile[] files;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startdate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date enddate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date curDate;
}
package vion.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.multipart.MultipartFile;
import vion.model.FileInfo;
import java.util.Date;
import java.util.List;
@Getter
@Setter
public class TaskTempDTO extends BaseDTO {
private Long id;
private Long storeId;
/** 项目名称 */
private String storeName;
/** 报修日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date repairTime;
/** 故障说明 */
private String faultDescription;
/** 报修人 */
private String repairPeople;
/** 联系方式 */
private String repairPhone;
/** 状态(1待确认、2已确认) */
private Integer status;
/** 附件信息 */
private List<FileInfo> fileList;
private String remark;
private MultipartFile[] files;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startdate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date enddate;
}
package vion.interceptor;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Opt;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import cn.hutool.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import vion.Global;
import vion.enums.ResultEnum;
import vion.model.User;
import vion.service.IUserSerrvice;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Interceptor extends HandlerInterceptorAdapter {
@Component
public class Interceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = request.getRequestURI();
System.out.println("拦截器");
if(url.indexOf("login") >= 0){
if (url.indexOf("login") >= 0) {
return true;
}
User user= Global.USERNAME_MAP.get(request.getHeader("userid"));
if(user==null){
User user = Opt.ofBlankAble(request.getHeader("token")).map(Global.USERNAME_MAP::get).orElse(null);
if (user == null) {
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
PrintWriter pw = response.getWriter();
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg_code", ResultEnum.ATOKEN_ERROR.getCode());
jsonObject.put("msg_info", "请先登陆再访问!");
pw.write(JSON.toJSONString(jsonObject));
jsonObject.set("code", ResultEnum.ATOKEN_ERROR.getCode());
jsonObject.set("msg", "请先登陆再访问!");
pw.write(jsonObject.toString());
pw.flush();
pw.close();
return false;
}
request.setAttribute("userid", user.getUserid());
} else {
request.setAttribute("start", System.currentTimeMillis());
return super.preHandle(request, response, handler);
return true;
}
}
}
package vion.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public Interceptor interceptor() {
return new Interceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry){
@Resource
private Interceptor interceptor;
registry.addInterceptor(interceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/login")
.excludePathPatterns("/error");//.excludePathPatterns("/api/downLoadFile");
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/taskTemp", "/api/upLoadFile", "/api/ding/callback/**", "/api/wechat/**", "/error")
.excludePathPatterns("/api/order/sign/*");
}
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Account;
@Mapper
public interface AccountMapper extends BaseMapper<Account> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Account;
import vion.model.Address;
@Mapper
public interface AddressMapper extends BaseMapper<Address> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vion.model.Dept;
/**
* @author HlQ
* @date 2023/11/10
*/
public interface DeptMapper extends BaseMapper<Dept> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Address;
import vion.model.Dictionary;
@Mapper
public interface DictionaryMapper extends BaseMapper<Dictionary> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Address;
import vion.model.DictionaryType;
@Mapper
public interface DictionaryTypeMapper extends BaseMapper<DictionaryType> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Address;
import vion.model.FaultLog;
@Mapper
public interface FaultLogMapper extends BaseMapper<FaultLog> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Address;
import vion.model.File;
@Mapper
public interface FileMapper extends BaseMapper<File> {
import vion.model.FileInfo;
public interface FileMapper extends BaseMapper<FileInfo> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Address;
import vion.model.Inspect;
@Mapper
public interface InspectMapper extends BaseMapper<Inspect> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Address;
import vion.model.Product;
@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vion.model.ServiceOrder;
/**
* @author HlQ
* @date 2023/11/21
*/
public interface ServiceOrderMapper extends BaseMapper<ServiceOrder> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Product;
import vion.model.Store;
@Mapper
public interface StoreMapper extends BaseMapper<Store> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Product;
import vion.model.Task;
@Mapper
public interface TaskMapper extends BaseMapper<Task> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import vion.model.TaskTemp;
@Mapper
public interface TaskTempMapper extends BaseMapper<TaskTemp> {
}
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vion.model.Product;
import vion.model.User;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
* 集团信息
*/
import java.util.Date;
@Data
@TableName(value="tbl_account_info")
public class Account {
/** 自增列 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private Long id;
private String name;//名称
/** 名称 */
private String name;
private Date createTime;//创建时间
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
private Date modifyTime;//修改时间
/** 修改时间 */
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
private String remark;//备注
/** 备注 */
private String remark;
}
......@@ -12,8 +12,8 @@ import lombok.Data;
@TableName(value="tbl_address_info")
public class Address {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private Integer storeId;//门店编码(外键)
private Long id;//自增列
private Long storeId;//门店编码
private String consigneeName;//收货名称
private String consigneePhone;//收货手机号
private String consigneeAddress;//收货地址
......
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
@TableName(value="tbl_dept_info")
public class Dept {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long deptId;
private String deptName;
private Long parentId;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import vion.dto.DictionaryDTO;
import java.util.Date;
@Data
@TableName(value="tbl_dictionary_info")
@AutoMappers({
@AutoMapper(target = DictionaryDTO.class),
})
public class Dictionary {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Long id;
private String type;
private Integer key;
private String value;
private String remark;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 更新时间 */
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import vion.dto.DictionaryTypeDTO;
import java.util.Date;
@Data
@TableName(value="tbl_dictionary_type")
@AutoMappers({
@AutoMapper(target = DictionaryTypeDTO.class),
})
public class DictionaryType {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Long id;
private String name;
private String type;
private String remark;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 更新时间 */
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import vion.vo.FaultLogVO;
import java.util.Date;
......@@ -10,13 +13,24 @@ import java.util.Date;
*/
@Data
@TableName(value="tbl_fault_log")
@AutoMapper(target = FaultLogVO.class)
public class FaultLog {
/** 自增列 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private Integer storeId;//门店id(外键)
private Integer taskId;//工单id(外键)
private Integer operator;//操作者
private String content;//操作内容
private Date createTime;//创建时间
private String remark;//备注
private Long id;
/** 门店id */
private Long storeId;
/** 工单id */
private Long taskId;
/** 操作者 */
private Long operator;
/** 操作内容 */
private String content;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 备注 */
private String remark;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
/**
* 文件信息
*/
@Data
@TableName(value="tbl_file_info")
public class File {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private Integer storeId;//门店id(外键)
private Integer type;//文件类型(1图片 2文件)
private Integer sourceType;//文件来源(项目、工单预处理,工单操作,巡检)
private Integer sourceId;//文件来源id
private String name;//文件名称
private String url;//文件地址
private Date createTime;//创建时间
private String remark;//备注
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import vion.dto.FileInfoDTO;
import java.util.Date;
/**
* 文件信息
*/
@Data
@TableName(value="tbl_file_info")
@AutoMappers({
@AutoMapper(target = FileInfoDTO.class),
})
public class FileInfo {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 门店id */
private Long storeId;
/** 文件扩展名 */
private String type;
/** 文件来源(1项目、2工单预处理,3工单操作,4巡检) */
private Integer sourceType;
/** 文件来源id */
private Long sourceId;
/** 文件名称 */
private String name;
/** 文件地址 */
private String url;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 备注 */
private String remark;
/** sha256 */
private String sha256;
/** 上传人 */
private String uploader;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import vion.dto.InspectDTO;
import java.util.Date;
......@@ -9,18 +14,57 @@ import java.util.Date;
* 巡检信息
*/
@Data
@TableName(value="tbl_inspect_info")
@TableName(value = "tbl_inspect_info")
@AutoMappers({
@AutoMapper(target = InspectDTO.class),
})
public class Inspect {
/** 自增列 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private Integer storeId;//门店id(外键)
private Date inspectDate;//巡检日期
private Integer type;//巡检方式(0远程、1现场)
private Integer status;//状态(0进行中、1待审核、2已完成、3、驳回)
private Integer inspectUser;//巡检人
private Integer reviewer;//审核人
private Date finishDate;//完成日期
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Long id;
/** 门店id */
private Long storeId;
/** 巡检时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@OrderBy
private Date inspectTime;
/** 巡检方式(0远程、1现场) */
private Integer type;
/** 状态(0进行中、1待审核、2已完成、3、驳回) */
private Integer status;
/** 巡检人 */
private Integer inspectUser;
/** 审核人 */
private Integer reviewer;
/** 巡检时间 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date finishTime;
/** 审核时间 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date auditTime;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 修改时间 */
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
@TableField(exist = false)
private String accountName;
@TableField(exist = false)
private String storeName;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import vion.dto.ProductDTO;
import vion.vo.ProductVO;
import java.util.Date;
......@@ -10,20 +15,44 @@ import java.util.Date;
*/
@Data
@TableName(value="tbl_product_info")
@AutoMappers({
@AutoMapper(target = ProductVO.class),
@AutoMapper(target = ProductDTO.class),
})
public class Product {
/** 自增列 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private String materialNo;//物料编号
private Integer storeId;//门店id(外键)
private String name;//产品名称
private Integer functionary;//产品型号
private Integer brand;//品牌
private Integer productCount;//订货数量
private Float productPrice;//订货单价
private Float productSubtotal;//定后价小计(单价乘以数量)
private Float productTotalPrice;//订货总价
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Integer accountId;//集团id
private Long id;
/** 物料编号 */
private String materialNo;
/** 门店id */
private Long storeId;
/** 产品名称 */
private String name;
/** 产品型号 */
private Integer functionary;
/** 品牌 */
private Integer brand;
/** 订货数量 */
private Integer productCount;
/** 订货单价 */
private Float productPrice;
//定后价小计(单价乘以数** ) */
private Float productSubtotal;
/** 订货总价 */
private Float productTotalPrice;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 修改时间 */
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import vion.dto.ServiceOrderDTO;
import vion.vo.ServiceOrderVO;
import java.util.Date;
@Data
@TableName("tbl_service_order")
@AutoMappers({
@AutoMapper(target = ServiceOrderVO.class),
@AutoMapper(target = ServiceOrderDTO.class),
})
public class ServiceOrder {
@TableId(type = IdType.AUTO)
private Long id;
/** 项目名称 */
private String projectName;
/** 报修人 */
private String submitter;
/** 报修人手机号码 */
private String submitPhone;
/** 报修时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date submitTime;
/** 维修人 */
private String repairPeople;
/** 维修人手机号码*/
private String repairPhone;
/** 部门 */
private String dept;
/** 服务方式(1.电话支持 2.远程服务 3.现场服务) */
private Integer serviceType;
/** 耗时 */
private Double time;
/** 故障内容 */
private String faultContent;
/** 维修结果 */
private String repairRes;
/** 客户评价 */
private String review;
/** 工单id */
private Long taskId;
/** 服务单状态 */
private Integer state;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 更新时间 */
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
/** 五星好评 */
private Integer stars;
/** 签字图片base64 */
private String signPic;
/** 签字时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date signTime;
/** 完成时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date finishTime;
/** 唯一id */
private String unid;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import vion.dto.StoreDTO;
import vion.vo.StoreVO;
import java.util.Date;
......@@ -10,26 +15,56 @@ import java.util.Date;
*/
@Data
@TableName(value="tbl_store_info")
@AutoMappers({
@AutoMapper(target = StoreVO.class),
@AutoMapper(target = StoreDTO.class),
})
public class Store {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Long id;
private String storenum;
private String name ;// 门店名称
private String number;// 流水号
private String contractCode;//合同编码
private Float amount;// 合同金额
private Date orderdate;//签订日期
private Integer salesperson;//销售人
private Integer warrantyPeriod;//质保期
private String customerName;//客户姓名
private Integer implementType;//实施类型:0纯供货、1供货+安装、3续保、4维修
private Integer projectState;//项目状态:0待确认、1进行中、2已完成、3挂起
private String contacts;//联系人(多个联系人逗号隔开)
private Integer createUser;//创建者
private Integer modifyUser;//修改者
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Integer projectStage;//项目阶段
private Integer accountId;//集团id
/** 门店名称 */
private String name;
/** 流水号 */
private String number;
/** 合同编码 */
private String contractCode;
/** 合同金额 */
private Float amount;
/** 签订日期 */
private Date orderdate;
/** 销售人 */
private Integer salesperson;
/** 质保期 */
private Integer warrantyPeriod;
/** 客户姓名 */
private String customerName;
/** 实施类型:0纯供货、1供货+安装、3续保、4维修 */
private Integer implementType;
/** 项目状态:0待确认、1进行中、2已完成、3挂起 */
private Integer projectState;
/** 联系人(多个联系人逗号隔开) */
private String contacts;
/** 创建者 */
private Long createUser;
/** 修改者 */
private Long modifyUser;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@OrderBy
private Date createTime;
/** 修改时间 */
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 项目阶段 */
private Integer projectStage;
/** 集团id */
private Long accountId;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import vion.dto.TaskDTO;
import vion.vo.TaskVO;
import java.util.Date;
@Data
@TableName(value="tbl_task_info")
@AutoMappers({
@AutoMapper(target = TaskVO.class),
@AutoMapper(target = TaskDTO.class),
})
public class Task {
/** 自增列 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;//自增列
private Integer storeId;//门店id(外键)
private Date repairDate;//报修日期
private Integer faultType;//故障类型
private String faultDescription;//故障说明
private Integer repairPeople;//报修人
private String repairPhone;//报修人联系方式
private Integer status;//状态:0待确认1进行中2已完成3挂起
private Date solveDate;//解决日期
private String faultReason;//故障原因
private Integer solveType;//解决措施:0产品BUG、1使用问题、2需求问题
private String solveDescription;//解决故障描述
private Integer createUser;//创建者
private Integer activeUser;//当前处理人
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Integer accountId;//集团id
private Long id;
/** 门店id */
private Long storeId;
/** 报修日期 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@OrderBy(sort = 2)
private Date repairTime;
/** 故障类型 */
private Integer faultType;
/** 故障说明 */
private String faultDescription;
/** 报修人 */
private String repairPeople;
/** 报修人联系方式 */
private String repairPhone;
/** 状态 */
@OrderBy(asc = true, sort = 1)
private Integer status;
/** 解决日期 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date solveDate;
/** 故障原因 */
private String faultReason;
/** 解决措施:0产品BUG、1使用问题、2需求问题 */
private Integer solveType;
/** 解决故障描述 */
private String solveDescription;
/** 创建者 */
private Long createUser;
/** 当前处理人 */
private Long activeUser;
/** 截止日期 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date expDate;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 修改时间 */
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
private String uuid;
/** 预工单id */
private Long taskTempId;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import vion.dto.TaskTempDTO;
import vion.vo.TaskTempVO;
import java.util.Date;
@Data
@TableName(value="tbl_task_temp")
@AutoMappers({
@AutoMapper(target = TaskTempVO.class),
@AutoMapper(target = TaskTempDTO.class),
})
public class TaskTemp {
@TableId(type= IdType.AUTO)
private Integer id;//自增列
private Integer storeId;//项目名称
private String storeName;//项目名称
private Date repairDate;//报修日期
private String faultDescription;//故障说明
private String repairPeople;//报修人
private String repairPhone;//联系方式
private Integer status;//状态(1待确认、2已确认)
private Integer operator;//操作人
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Long id;
/** 项目id */
private Long storeId;
/** 项目名称 */
private String storeName;
/** 报修时间 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@OrderBy(sort = 2)
private Date repairTime;
/** 故障说明 */
private String faultDescription;
/** 报修人 */
private String repairPeople;
/** 联系方式 */
private String repairPhone;
/** 状态(1待确认、2进行中、3已确认) */
@OrderBy(asc = true, sort = 1)
private Integer status;
/** 操作人 */
private Long operator;
/** 创建时间 */
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 修改时间 */
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 微信用户id */
private String openid;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
......@@ -12,12 +13,26 @@ import java.util.Date;
@TableName(value="tbl_user_info")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Long id;
private String userid;
private String username;
private String password;
private String phone;
private Date createTime;//创建时间
private Long deptId;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
private String remark;
/** 是否是预工单处理人 0:不是 1:是 */
private Integer preWorkOrder;
/** 员工状态 2:试用期 3:正式 5:待离职 -1:无状态 */
private Integer employeeStatus;
@TableField(exist = false)
private String token;
}
\ No newline at end of file
......@@ -3,7 +3,6 @@ package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Account;
public interface IAccountSerrvice extends IService<Account> {
public interface IAccountService extends IService<Account> {
Account saveAndReturn(Account account);
}
......@@ -3,5 +3,5 @@ package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Address;
public interface IAddressSerrvice extends IService<Address> {
public interface IAddressService extends IService<Address> {
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Dept;
/**
* @author HlQ
* @date 2023/11/10
*/
public interface IDeptService extends IService<Dept> {
}
......@@ -3,5 +3,5 @@ package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Dictionary;
public interface IDictionarySerrvice extends IService<Dictionary> {
public interface IDictionaryService extends IService<Dictionary> {
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Account;
import vion.model.DictionaryType;
public interface IDictionaryTypeSerrvice extends IService<DictionaryType> {
public interface IDictionaryTypeService extends IService<DictionaryType> {
}
......@@ -3,5 +3,5 @@ package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.FaultLog;
public interface IFaultLogSerrvice extends IService<FaultLog> {
public interface IFaultLogService extends IService<FaultLog> {
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.File;
import vion.model.FileInfo;
public interface IFileSerrvice extends IService<File> {
public interface IFileService extends IService<FileInfo> {
}
package vion.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.dto.InspectDTO;
import vion.model.Inspect;
public interface IInspectSerrvice extends IService<Inspect> {
public interface IInspectService extends IService<Inspect> {
Inspect saveAndReturn(Inspect inspect);
Page<Inspect> getInspectList(InspectDTO data);
}
package vion.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.dto.ProductDTO;
import vion.model.Product;
import vion.vo.ProductVO;
public interface IProductSerrvice extends IService<Product> {
public interface IProductService extends IService<Product> {
Product saveAndReturn(Product product);
Page<ProductVO> getProductList(ProductDTO productDTO);
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.ServiceOrder;
/**
* @author HlQ
* @date 2023/11/21
*/
public interface IServiceOrderService extends IService<ServiceOrder> {
String sendOrder(Long id);
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Store;
public interface IStoreSerrvice extends IService<Store> {
Store saveAndReturn(Store store);
}
package vion.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.dto.StatusDTO;
import vion.dto.StoreDTO;
import vion.model.Store;
import vion.vo.StoreVO;
public interface IStoreService extends IService<Store> {
Page<StoreVO> getStoreList(StoreDTO data);
String updateStoreStage(StatusDTO statusDTO, String token);
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Task;
public interface ITaskSerrvice extends IService<Task> {
Task saveAndReturn(Task task);
}
package vion.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.dto.TaskDTO;
import vion.model.Task;
import vion.vo.TaskVO;
public interface ITaskService extends IService<Task> {
Page<TaskVO> getTaskList(TaskDTO data);
TaskVO getTaskById(Long taskId);
Long circTask(TaskDTO data, String token);
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.TaskTemp;
public interface ITaskTempSerrvice extends IService<TaskTemp> {
TaskTemp saveAndReturn(TaskTemp taskTemp);
}
package vion.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.dto.TaskTempDTO;
import vion.model.TaskTemp;
import vion.vo.TaskTempVO;
public interface ITaskTempService extends IService<TaskTemp> {
Page<TaskTempVO> getTaskTempList(TaskTempDTO data);
TaskTempVO getTaskTempById(Long id);
String saveOrUpdTaskTemp(TaskTempDTO data);
}
package vion.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.User;
public interface IUserSerrvice extends IService<User> {
import java.util.List;
public interface IUserService extends IService<User> {
List<Tree<String>> getOrgTree(String deptId);
User saveAndReturn(User user);
}
......@@ -4,14 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.AccountMapper;
import vion.model.Account;
import vion.service.IAccountSerrvice;
import vion.service.IAccountService;
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements IAccountSerrvice {
@Override
public Account saveAndReturn(Account account) {
this.saveOrUpdate(account);
return account;
}
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements IAccountService {
}
\ No newline at end of file
......@@ -4,8 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.AddressMapper;
import vion.model.Address;
import vion.service.IAddressSerrvice;
import vion.service.IAddressService;
@Service
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements IAddressSerrvice {
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements IAddressService {
}
package vion.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.DeptMapper;
import vion.model.Dept;
import vion.service.IDeptService;
/**
* @author HlQ
* @date 2023/11/10
*/
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {
}
......@@ -4,8 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.DictionaryMapper;
import vion.model.Dictionary;
import vion.service.IDictionarySerrvice;
import vion.service.IDictionaryService;
@Service
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, Dictionary> implements IDictionarySerrvice {
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, Dictionary> implements IDictionaryService {
}
......@@ -4,8 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.DictionaryTypeMapper;
import vion.model.DictionaryType;
import vion.service.IDictionaryTypeSerrvice;
import vion.service.IDictionaryTypeService;
@Service
public class DictionaryTypeServiceImpl extends ServiceImpl<DictionaryTypeMapper, DictionaryType> implements IDictionaryTypeSerrvice {
public class DictionaryTypeServiceImpl extends ServiceImpl<DictionaryTypeMapper, DictionaryType> implements IDictionaryTypeService {
}
......@@ -4,8 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.FaultLogMapper;
import vion.model.FaultLog;
import vion.service.IFaultLogSerrvice;
import vion.service.IFaultLogService;
@Service
public class FaultLogServiceImpl extends ServiceImpl<FaultLogMapper, FaultLog> implements IFaultLogSerrvice {
public class FaultLogServiceImpl extends ServiceImpl<FaultLogMapper, FaultLog> implements IFaultLogService {
}
......@@ -3,9 +3,9 @@ package vion.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.FileMapper;
import vion.model.File;
import vion.service.IFileSerrvice;
import vion.model.FileInfo;
import vion.service.IFileService;
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IFileSerrvice {
public class FileServiceImpl extends ServiceImpl<FileMapper, FileInfo> implements IFileService {
}
package vion.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vion.dto.InspectDTO;
import vion.mapper.InspectMapper;
import vion.model.Account;
import vion.model.Inspect;
import vion.service.IInspectSerrvice;
import vion.model.Store;
import vion.service.IAccountService;
import vion.service.IInspectService;
import vion.service.IStoreService;
import java.util.List;
@Service
public class InspectServiceImpl extends ServiceImpl<InspectMapper, Inspect> implements IInspectSerrvice {
@RequiredArgsConstructor
public class InspectServiceImpl extends ServiceImpl<InspectMapper, Inspect> implements IInspectService {
private final IStoreService storeService;
private final IAccountService accountService;
private final Converter converter;
@Override
public Inspect saveAndReturn(Inspect inspect) {
this.saveOrUpdate(inspect);
return inspect;
public Page<Inspect> getInspectList(InspectDTO data) {
Page<Inspect> inspectList = this.lambdaQuery(converter.convert(data, new Inspect()))
.between(data.getStartdate() != null && data.getEnddate() != null, Inspect::getInspectTime, data.getStartdate(), data.getEnddate())
.page(Page.of(data.getPageNum(), data.getPageSize()));
List<Store> storeList = storeService.list();
List<Account> accountList = accountService.list();
inspectList.getRecords().forEach(item -> {
item.setAccountName(accountList.stream().filter(v -> v.getId().equals(item.getAccountId())).map(Account::getName).findFirst().orElse("--"));
item.setStoreName(storeList.stream().filter(v -> v.getId().equals(item.getStoreId())).map(Store::getName).findFirst().orElse("--"));
});
return inspectList;
}
}
package vion.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vion.dto.ProductDTO;
import vion.mapper.ProductMapper;
import vion.model.Product;
import vion.service.IProductSerrvice;
import vion.model.Store;
import vion.service.IProductService;
import vion.service.IStoreService;
import vion.vo.ProductVO;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductSerrvice {
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
private final IStoreService storeService;
private final Converter converter;
@Override
public Product saveAndReturn(Product product) {
this.saveOrUpdate(product);
return product;
public Page<ProductVO> getProductList(ProductDTO productDTO) {
Page<Product> productList = this.page(Page.of(productDTO.getPageNum(), productDTO.getPageSize()), Wrappers.<Product>lambdaQuery()
.eq(productDTO.getStoreId() != null, Product::getStoreId, productDTO.getStoreId())
.eq(productDTO.getAccountId() != null, Product::getAccountId, productDTO.getAccountId())
.like(productDTO.getName() != null, Product::getName, productDTO.getName())
.eq(productDTO.getBrand() != null, Product::getBrand, productDTO.getBrand())
.eq(productDTO.getFunctionary() != null, Product::getFunctionary, productDTO.getFunctionary()));
List<Store> storeList = storeService.list();
List<ProductVO> productVOList = new ArrayList<>();
for (Product pro : productList.getRecords()) {
ProductVO productVO = converter.convert(pro, ProductVO.class);
productVO.setStoreName(storeList.stream().filter(store -> store.getId().equals(pro.getStoreId())).collect(Collectors.toList()).get(0).getName());
productVOList.add(productVO);
}
return Page.<ProductVO>of(productDTO.getPageNum(), productDTO.getPageSize(), productList.getTotal()).setRecords(productVOList);
}
}
package vion.service.impl;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Opt;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import org.springframework.stereotype.Service;
import vion.ding.WechatMod;
import vion.mapper.ServiceOrderMapper;
import vion.model.ServiceOrder;
import vion.model.Task;
import vion.service.IServiceOrderService;
import vion.service.ITaskService;
import vion.service.ITaskTempService;
import java.util.List;
/**
* @author HlQ
* @date 2023/11/21
*/
@Service
@RequiredArgsConstructor
public class ServiceOrderServiceImpl extends ServiceImpl<ServiceOrderMapper, ServiceOrder> implements IServiceOrderService {
private final ITaskService taskService;
private final ITaskTempService taskTempService;
private final WechatMod wechatMod;
@Override
public String sendOrder(Long id) {
ServiceOrder order = this.getById(id);
Task task = taskService.getById(order.getTaskId());
return Opt.ofNullable(task.getTaskTempId())
.map(tempId -> taskTempService.getById(tempId).getOpenid())
.map(openid -> {
List<WxMpTemplateData> wxMpTemplateDataList = ListUtil.of(
new WxMpTemplateData("character_string5", task.getUuid()),
new WxMpTemplateData("thing1", order.getSubmitter() + "-" + order.getSubmitPhone()));
return wechatMod.sendMsg("NN6N58EOr0BE-D0f2vFipqUek4qtVXp08EJWjJora-M", openid, wxMpTemplateDataList, "https://yunwei.vionyun.com:8443/wap/service-bill?unid=" + order.getUnid());
})
.orElse("微信公众号消息推送失败,请检查工单是否绑定微信用户或联系管理员!");
}
}
package vion.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import vion.Global;
import vion.dto.StatusDTO;
import vion.dto.StoreDTO;
import vion.mapper.StoreMapper;
import vion.model.Account;
import vion.model.FileInfo;
import vion.model.Store;
import vion.service.IStoreSerrvice;
import vion.service.IAccountService;
import vion.service.IFileService;
import vion.service.IStoreService;
import vion.vo.StoreVO;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements IStoreSerrvice {
@RequiredArgsConstructor
public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements IStoreService {
private final IAccountService accountService;
private final IFileService fileService;
private final Converter converter;
@Value("${fileUrl:}")
private String fileUrl;
@Override
public Page<StoreVO> getStoreList(StoreDTO data) {
Page<Store> storeList = this.lambdaQuery(converter.convert(data, new Store()))
.between(data.getStartdate() != null && data.getEnddate() != null, Store::getOrderdate, data.getStartdate(), data.getEnddate())
.page(Page.of(data.getPageNum(), data.getPageSize()));
// todo 缓存
List<Account> accountList = accountService.list();
List<FileInfo> fileInfoList = fileService.lambdaQuery().eq(FileInfo::getSourceType, 1).list();
Map<Long, Long> store2CntMap = fileInfoList.stream().collect(Collectors.groupingBy(FileInfo::getStoreId, Collectors.counting()));
List<StoreVO> storeVOList = new ArrayList<>();
storeList.getRecords().forEach(item -> {
StoreVO storeVO = converter.convert(item, new StoreVO());
storeVO.setAccountName(accountList.stream().filter(v -> v.getId().equals(item.getAccountId())).map(Account::getName).findFirst().orElse("--"));
storeVO.setFileNum(store2CntMap.getOrDefault(item.getId(), 0L));
storeVOList.add(storeVO);
});
return Page.<StoreVO>of(data.getPageNum(), data.getPageSize(), storeList.getTotal()).setRecords(storeVOList);
}
@Override
public Store saveAndReturn(Store store) {
this.saveOrUpdate(store);
return store;
public String updateStoreStage(StatusDTO statusDTO, String token) {
this.update(Wrappers.<Store>lambdaUpdate()
.set(Store::getProjectStage, statusDTO.getProjectStage())
.eq(Store::getId, statusDTO.getSourceId()));
Opt.ofNullable(statusDTO.getFiles()).ifPresent(tmpFiles -> {
for (MultipartFile infile : tmpFiles) {
//上传url地址
String orgName = infile.getOriginalFilename();
String fileName = orgName.substring(0, orgName.lastIndexOf("."));
String fileExt = orgName.substring(orgName.lastIndexOf("."));
String filename = fileName + "_" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss") + fileExt;
String path = fileUrl + FileUtil.FILE_SEPARATOR + statusDTO.getStoreId() + FileUtil.FILE_SEPARATOR + statusDTO.getSourceId() + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
try {
infile.transferTo(file);
} catch (IOException e) {
log.error("保存文件出错", e);
}
FileInfo tempFileInfo = new FileInfo();
tempFileInfo.setStoreId(statusDTO.getStoreId());
tempFileInfo.setSourceId(statusDTO.getSourceId());
tempFileInfo.setSourceType(statusDTO.getSourceType());
tempFileInfo.setName(filename);
tempFileInfo.setUrl(path);
tempFileInfo.setType(FileUtil.extName(file));
tempFileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
tempFileInfo.setUploader(Global.USERNAME_MAP.get(token).getUsername());
fileService.save(tempFileInfo);
}
});
return "更新成功";
}
}
package vion.service.impl;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vion.Global;
import vion.ding.DingMod;
import vion.ding.WechatMod;
import vion.dto.TaskDTO;
import vion.mapper.ServiceOrderMapper;
import vion.mapper.TaskMapper;
import vion.model.Task;
import vion.service.ITaskSerrvice;
import vion.model.Dictionary;
import vion.model.*;
import vion.service.*;
import vion.vo.TaskVO;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskSerrvice {
@RequiredArgsConstructor
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {
private final ITaskTempService taskTempService;
private final IFileService fileService;
private final IFaultLogService faultLogService;
private final IStoreService storeService;
private final IUserService userService;
private final IAccountService accountService;
private final IDictionaryService dictionaryService;
// 循环依赖,这里用mapper
// private final IServiceOrderService serviceOrderService;
private final ServiceOrderMapper serviceOrderMapper;
private final DingMod dingMod;
private final WechatMod wechatMod;
private final Converter converter;
@Value("${fileUrl:}")
private String fileUrl;
@Override
public Page<TaskVO> getTaskList(TaskDTO data) {
Page<Task> taskList = this
.lambdaQuery(converter.convert(data, new Task()))
.between(data.getStartdate() != null && data.getEnddate() != null, Task::getRepairTime, data.getStartdate(), data.getEnddate())
.lt(data.getCurDate() != null, Task::getExpDate, data.getCurDate())
.page(Page.of(data.getPageNum(), data.getPageSize()));
// todo 是否加入缓存
List<Store> storeList = storeService.list();
List<Account> accountList = accountService.list();
List<TaskVO> taskVOList = new ArrayList<>();
Map<Long, ServiceOrder> taskId2OrderMap = Opt.ofEmptyAble(taskList.getRecords())
.map(l -> l.stream().map(Task::getId).collect(Collectors.toList()))
.map(idList -> serviceOrderMapper.selectList(Wrappers.<ServiceOrder>lambdaQuery().in(ServiceOrder::getTaskId, idList)))
.map(serviceOrderList -> serviceOrderList.stream().collect(Collectors.toMap(ServiceOrder::getTaskId, Function.identity())))
.orElse(MapUtil.empty());
Opt.ofEmptyAble(taskList.getRecords())
.ifPresent(l -> l.forEach(v -> {
TaskVO taskVO = converter.convert(v, TaskVO.class);
taskVO.setStoreName(storeList.stream().filter(s -> s.getId().equals(v.getStoreId())).map(Store::getName).findFirst().orElse("--"));
taskVO.setAccountName(accountList.stream().filter(a -> a.getId().equals(v.getAccountId())).map(Account::getName).findFirst().orElse("--"));
taskVO.setServiceOrder(taskId2OrderMap.get(v.getId()));
taskVOList.add(taskVO);
}));
return Page.<TaskVO>of(data.getPageNum(), data.getPageSize(), taskList.getTotal()).setRecords(taskVOList);
}
@Override
public Task saveAndReturn(Task task) {
this.saveOrUpdate(task);
return task;
public TaskVO getTaskById(Long taskId) {
Task task = this.getById(taskId);
List<FileInfo> fileInfos = fileService.list(Wrappers.<FileInfo>lambdaUpdate()
.eq(FileInfo::getSourceId, task.getId())
.eq(FileInfo::getStoreId, task.getStoreId()));
TaskVO taskVO = converter.convert(task, TaskVO.class);
taskVO.setFileList(fileInfos);
return taskVO;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long circTask(TaskDTO data, String token) {
User user = Global.USERNAME_MAP.get(token);
Task task = converter.convert(data, Task.class);
if (task.getId() == null) {
task.setCreateUser(user.getId());
}
// 可能直接提工单,而不是预工单确认之后生成的工单
if (data.getTasktempId() != null) {
taskTempService.lambdaUpdate()
.set(TaskTemp::getStatus, 3)
.set(TaskTemp::getOperator, data.getActiveUser())
.set(TaskTemp::getStoreId, data.getStoreId())
.eq(TaskTemp::getId, data.getTasktempId())
.update();
//根据预处理工单更新附件的门店ID
/*fileService.lambdaUpdate()
.set(FileInfo::getStoreId, data.getStoreId())
.eq(FileInfo::getSourceId, data.getId())
.update();*/
}
if (data.getId() == null) {
//添加新工单
task.setUuid(IdUtil.nanoId());
task.setTaskTempId(data.getTasktempId());
this.save(task);
List<FaultLog> saveList = new ArrayList<>();
// 预工单提交,客户名称不在系统用户表内
FaultLog faultLog = new FaultLog();
faultLog.setTaskId(task.getId());
faultLog.setStoreId(task.getStoreId());
faultLog.setOperator(-1L);
faultLog.setContent(data.getRepairPeople() + "|提交工单");
saveList.add(faultLog);
//添加工单处理日志
FaultLog faultLog1 = new FaultLog();
faultLog1.setTaskId(task.getId());
faultLog1.setStoreId(task.getStoreId());
faultLog1.setOperator(user.getId());
faultLog1.setContent("确认工单");
faultLog1.setRemark(task.getRemark());
saveList.add(faultLog1);
faultLogService.saveBatch(saveList);
} else {
this.updateById(task);
//根据状态判断是否要添加工单处理日志(状态:1待确认2进行中3已完成4挂起)
FaultLog faultLog = new FaultLog();
faultLog.setTaskId(task.getId());
faultLog.setStoreId(task.getStoreId());
faultLog.setOperator(user.getId());
faultLog.setRemark(task.getRemark());
if (task.getStatus() == 2) {
faultLog.setContent("工单正在处理中");
}
if (task.getStatus() == 3) {
faultLog.setContent("工单处理完成");
}
if (task.getStatus() == 4) {
faultLog.setContent("工单挂起");
}
if (task.getStatus() == 5) {
faultLog.setContent("工单已关闭");
}
faultLogService.save(faultLog);
}
// todo 异步发送钉钉消息通知
Store store = storeService.getById(task.getStoreId());
Task existTask = this.getById(task.getId());
Long activeUserId = data.getActiveUser();
User activeUser = userService.lambdaQuery().eq(User::getId, activeUserId).one();
Set<String> useridList = new HashSet<>();
useridList.add(activeUser.getUserid());
if (task.getStatus() == 3) {
// 工单完成时,推送钉钉消息到预工单的确认人
Opt.ofNullable(existTask.getTaskTempId())
.map(taskTempId -> taskTempService.getById(taskTempId).getOperator())
.map(userService::getById)
.map(User::getUserid)
.ifPresent(useridList::add);
}
JSONObject msg = buildMsg(String.join(",", useridList), store.getName(), existTask);
String pushRes = dingMod.sendMessage(msg);
// todo 异步微信公众号消息推送
if (task.getStatus() != 5) {
Opt.ofNullable(existTask.getTaskTempId())
.map(taskTempId -> taskTempService.getById(taskTempId).getOpenid())
.ifPresent(openid -> {
Map<Integer, String> statusMap = MapUtil.<Integer, String>builder()
.put(1, "待确认")
.put(2, "进行中")
.put(3, "已完成")
.put(4, "挂起")
.build();
List<WxMpTemplateData> wxMpTemplateDataList = ListUtil.of(
new WxMpTemplateData("character_string1", existTask.getUuid()),
new WxMpTemplateData("thing7", user.getUsername() + "(" + user.getPhone() + ")"),
new WxMpTemplateData("time4", DateUtil.formatDateTime(new Date())),
new WxMpTemplateData("const3", statusMap.get(existTask.getStatus())));
String sentMsg = wechatMod.sendMsg("ueJlVya7uOfYhFlIv28pC0kiHPe1b6Q-gkWsYKkoRWo", openid, wxMpTemplateDataList, null);
});
}
Opt.ofNullable(data.getFiles())
.ifPresent(fileList ->
Arrays.stream(fileList).forEach(infile -> {
//上传url地址
String orgName = infile.getOriginalFilename();
String fileName = orgName.substring(0, orgName.lastIndexOf("."));
String fileExt = orgName.substring(orgName.lastIndexOf("."));
String filename = fileName + "_" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss") + fileExt;
String path = fileUrl + FileUtil.FILE_SEPARATOR + data.getStoreId() + FileUtil.FILE_SEPARATOR + task.getId() + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
try {
infile.transferTo(file);
} catch (IOException e) {
log.error("保存文件出错", e);
}
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(task.getStoreId());
fileInfo.setSourceId(task.getId());
fileInfo.setSourceType(3);
fileInfo.setName(filename);
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
fileInfo.setUploader(user.getUsername());
fileService.save(fileInfo);
}));
return task.getId();
}
JSONObject buildMsg(String userid, String storeName, Task task) {
List<Dictionary> orderStatus = dictionaryService.list(Wrappers.<Dictionary>lambdaQuery().eq(Dictionary::getType, "order_status"));
Map<Integer, String> orderStatusMap = orderStatus.stream().collect(Collectors.toMap(Dictionary::getKey, Dictionary::getValue));
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
jsonObj.set("userid_list", userid);
JSONObject msg = new JSONObject();
JSONObject content = new JSONObject();
content.set("title", "您有一条新工单请及时处理哦~_~");
content.set("markdown", "门店信息: " + storeName + "[FullOfVitality]" +
" \n 报修人:" + task.getRepairPeople() +
" \n 联系方式:" + task.getRepairPhone() +
" \n 当前工单状态:" + orderStatusMap.get(task.getStatus()) +
" \n 故障描述:" + task.getFaultDescription() +
" \n 发送时间:" + DateUtil.now());
content.set("btn_orientation", "1");
JSONArray jsonArray = new JSONArray();
jsonArray.add(new JSONObject().set("title", "查看详情").set("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FstoreId%3D" + task.getStoreId() + "%26taskId%3D" + task.getId()));
content.set("btn_json_list", jsonArray);
msg.set("msgtype", "action_card");
msg.set("action_card", content);
jsonObj.set("msg", msg);
return jsonObj;
}
}
package vion.service.impl;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vion.ding.DingMod;
import vion.ding.WechatMod;
import vion.dto.TaskTempDTO;
import vion.mapper.TaskTempMapper;
import vion.model.FileInfo;
import vion.model.TaskTemp;
import vion.service.ITaskTempSerrvice;
import vion.model.User;
import vion.service.IFileService;
import vion.service.ITaskTempService;
import vion.service.IUserService;
import vion.vo.TaskTempVO;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class TaskTempServiceImpl extends ServiceImpl<TaskTempMapper, TaskTemp> implements ITaskTempSerrvice {
@RequiredArgsConstructor
public class TaskTempServiceImpl extends ServiceImpl<TaskTempMapper, TaskTemp> implements ITaskTempService {
private final IFileService fileService;
private final IUserService userService;
private final DingMod dingMod;
private final WechatMod wechatMod;
private final Converter converter;
@Value("${fileUrl:}")
private String fileUrl;
@Override
public Page<TaskTempVO> getTaskTempList(TaskTempDTO data) {
Page<TaskTemp> taskTempPage = this
.lambdaQuery(converter.convert(data, new TaskTemp()))
.between(data.getStartdate() != null && data.getEnddate() != null, TaskTemp::getRepairTime, data.getStartdate(), data.getEnddate())
.page(Page.of(data.getPageNum(), data.getPageSize()));
List<TaskTempVO> taskTempVOList = converter.convert(taskTempPage.getRecords(), TaskTempVO.class);
return Page.<TaskTempVO>of(taskTempPage.getCurrent(), taskTempPage.getSize(), taskTempPage.getTotal()).setRecords(taskTempVOList);
}
@Override
public TaskTemp saveAndReturn(TaskTemp taskTemp) {
this.saveOrUpdate(taskTemp);
return taskTemp;
public TaskTempVO getTaskTempById(Long id) {
TaskTemp taskTemp = this.getById(id);
List<FileInfo> fileInfos = Opt.ofNullable(taskTemp)
.map(tmp -> fileService.list(Wrappers.<FileInfo>lambdaUpdate()
.eq(FileInfo::getSourceId, tmp.getId())
.eq(FileInfo::getStoreId, 0L)))
.orElse(ListUtil.empty());
TaskTempVO taskTempVO = converter.convert(taskTemp, TaskTempVO.class);
taskTempVO.setFileList(fileInfos);
return taskTempVO;
}
@Override
public String saveOrUpdTaskTemp(TaskTempDTO data) {
TaskTemp taskTemp = converter.convert(data, TaskTemp.class);
this.save(taskTemp);
Opt.ofNullable(data.getFiles())
.ifPresent(fileList ->
Arrays.stream(fileList).forEach(infile -> {
//上传url地址
String orgName = infile.getOriginalFilename();
String fileName = orgName.substring(0, orgName.lastIndexOf("."));
String fileExt = orgName.substring(orgName.lastIndexOf("."));
String filename = fileName + "_" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss") + fileExt;
String path = fileUrl + FileUtil.FILE_SEPARATOR + 0 + FileUtil.FILE_SEPARATOR + taskTemp.getId() + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
try {
infile.transferTo(file);
} catch (IOException e) {
log.error("保存文件出错", e);
}
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(0L);
fileInfo.setSourceId(taskTemp.getId());
fileInfo.setSourceType(2);
fileInfo.setName(filename);
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
fileInfo.setUploader(data.getRepairPeople());
fileService.save(fileInfo);
}));
// todo 异步发送钉钉消息通知
List<User> userList = userService.lambdaQuery().eq(User::getPreWorkOrder, 1).list();
String userids = userList.stream().map(User::getUserid).collect(Collectors.joining(","));
dingMod.sendMessage(buildMsg(userids, taskTemp));
return wechatMod.genCodeUrl(taskTemp.getId());
}
JSONObject buildMsg(String userid, TaskTemp taskTemp) {
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
jsonObj.set("userid_list", userid);
JSONObject msg = new JSONObject();
JSONObject content = new JSONObject();
content.set("title", "客户提交工单,请及时处理哦~_~");
content.set("markdown", "门店信息: " + taskTemp.getStoreName() +
" \n 客户姓名:" + taskTemp.getRepairPeople() +
" \n 联系方式:" + taskTemp.getRepairPhone() +
" \n 故障描述:" + taskTemp.getFaultDescription() +
" \n 发送时间:" + DateUtil.now());
content.set("btn_orientation", "1");
JSONArray jsonArray = new JSONArray();
jsonArray.add(new JSONObject().set("title", "查看详情").set("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FtaskTempId%3D" + taskTemp.getId()));
content.set("btn_json_list", jsonArray);
msg.set("msgtype", "action_card");
msg.set("action_card", content);
jsonObj.set("msg", msg);
return jsonObj;
}
}
package vion.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vion.mapper.UserMapper;
import vion.model.Dept;
import vion.model.User;
import vion.service.IUserSerrvice;
import vion.service.IDeptService;
import vion.service.IUserService;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserSerrvice {
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
private final IDeptService deptService;
@Override
public User saveAndReturn(User user) {
this.saveOrUpdate(user);
return user;
public List<Tree<String>> getOrgTree(String deptId) {
List<Dept> deptList = deptService.list();
List<User> userList = this.list();
List<TreeNode<String>> nodeList = CollUtil.newArrayList();
deptList.forEach(v -> {
TreeNode<String> node = new TreeNode<>(v.getDeptId().toString(), v.getParentId().toString(), v.getDeptName(), 1);
node.setExtra(MapUtil.of("type", "dept"));
node.setExtra(MapUtil.of("pkId", v.getId()));
nodeList.add(node);
});
userList.forEach(v -> {
TreeNode<String> node = new TreeNode<>(v.getUserid(), v.getDeptId().toString(), v.getUsername(), 2);
node.setExtra(MapUtil.of("type", "user"));
node.setExtra(MapUtil.of("pkId", v.getId()));
nodeList.add(node);
});
List<Tree<String>> wholeTree = TreeUtil.build(nodeList, "1");
return Opt.ofBlankAble(deptId).map(d -> {
List<Tree<String>> resTree = new ArrayList<>();
wholeTree.forEach(t ->
t.walk(tmp -> {
if (tmp.getId().equals(d)) {
resTree.add(tmp);
}
}));
return resTree;
}).orElse(wholeTree);
}
}
package vion.utils;
public class FileTypeTool {
public static int fileType(String fileName){
if(fileName==null){
return 0;
}else{
String fileType=fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase();
//创建图片类型数组
String img[]={"bmp","jpg","jpeg","png","tiff","gif","pcx","tga","exif","fpx","svg","psd",
"cdr","pcd","dxf","ufo","eps","ai","raw","wmf"};
for(int i=0;i<img.length+1;i++){
if (img[i].equals(fileType)){
return 1;
}
}
//创建文档类型
String documet[]={"txt","doc","docx","xls","xlsx","htm","html","jsp","rtf","wpd","pdf","ppt"};
for(int i=0;i<documet.length+1;i++){
if (documet[i].equals(fileType)){
return 2;
}
}
//创建视频类型
String video[]={"mp4","avi","wmv","asf","navi","3gp","mkv","f4v","rmvb","webm"};
for(int i=0;i<video.length+1;i++){
if (video[i].equals(fileType)){
return 3;
}
}
//创建音乐类型
String music[]={"mp3","wma","wav","mod","ra","cd","md","asf","aac","vqf","ape","mid","ogg","m4a","vqf"};
for(int i=0;i<music.length+1;i++){
if (music[i].equals(fileType)){
return 4;
}
}
}
return 0;
}
}
......@@ -8,7 +8,7 @@ public class ResultUtil {
public static ResultVO<Object> success(Object o) {
ResultVO<Object> resultVO = new ResultVO<Object>();
resultVO.setCode(ResultEnum.SUCCESS.getCode());
resultVO.setMessage(ResultEnum.SUCCESS.getMessage());
resultVO.setMsg(ResultEnum.SUCCESS.getMessage());
resultVO.setData(o);
return resultVO;
}
......@@ -16,11 +16,23 @@ public class ResultUtil {
public static ResultVO<Object> error(ResultEnum e) {
ResultVO<Object> resultVO = new ResultVO<Object>();
resultVO.setCode(e.getCode());
resultVO.setMessage(e.getMessage());
resultVO.setMsg(e.getMessage());
return resultVO;
}
public static ResultVO<Object> error(Object o) {
ResultVO<Object> resultVO = new ResultVO<Object>();
resultVO.setCode(500);
resultVO.setMsg("error");
resultVO.setData(o);
return resultVO;
}
public static ResultVO<Object> success() {
return success(null);
}
public static ResultVO<Object> error() {
return error(null);
}
}
......@@ -6,9 +6,9 @@ import java.util.Date;
@Data
public class FaultLogVO {
private Integer id;//自增列
private Integer storeId;//门店id(外键)
private Integer taskId;//工单id(外键)
private Long id;//自增列
private Long storeId;//门店id
private Long taskId;//工单id
private Integer operator;//操作者
private String content;//操作内容
private Date createTime;//创建时间
......
......@@ -6,9 +6,9 @@ import java.util.Date;
@Data
public class ProductVO {
private Integer id;//自增列
private Long id;//自增列
private String materialNo;//物料编号
private Integer storeId;//门店id(外键)
private Long storeId;//门店id
private String storeName;//门店名称
private String name;//产品名称
private Integer functionary;//产品型号
......@@ -20,5 +20,5 @@ public class ProductVO {
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Integer accountId;//集团id
private Long accountId;//集团id
}
package vion.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springframework.stereotype.Component;
......@@ -9,13 +8,8 @@ import org.springframework.stereotype.Component;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResultVO<T> {
@JsonProperty(value = "msg_code")
private Integer code;
@JsonProperty(value = "msg_info")
private String message;
private String atoken;
private Integer totalNum;
private String msg;
private T data;
private T result;
}
package vion.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
/**
* @author HlQ
* @date 2023/11/23
*/
@Data
public class ServiceOrderVO {
private String projectName;
/** 报修人 */
private String submitter;
/** 报修人手机号码 */
private String submitPhone;
/** 报修时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date submitTime;
/** 维修人 */
private String repairPeople;
/** 维修人手机号码*/
private String repairPhone;
/** 部门 */
private String dept;
/** 服务方式(1.电话支持 2.远程服务 3.现场服务) */
private String serviceType;
/** 耗时 */
private Double time;
/** 故障内容 */
private String faultContent;
/** 维修结果 */
private String repairRes;
/** 客户评价 */
private String review;
/** 工单id */
private Long taskId;
/** 服务单状态 */
private Integer state;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
/** 五星好评 */
private Integer stars;
/** 签字图片base64 */
private String signPic;
/** 签字时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date signTime;
/** 完成时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date finishTime;
/** 唯一id */
private String unid;
}
package vion.vo;
import lombok.Data;
import java.util.Date;
@Data
public class StatusVO {
private Integer storeId;//门店id
private Integer projectStage;//阶段
private Integer sourceType;//文件来源
private Integer sourceId;//来源id
private Integer type;//文件类型
private String name;//名称
private String url;//地址
}
package vion.vo;
import lombok.Data;
import java.util.Date;
@Data
public class StoreListVO {
private Integer id;
private String name ;// 门店名称
}
package vion.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class StoreVO {
private Integer id;
private Long id;
private String storenum;
private String name ;// 门店名称
private String number;// 流水号
private String contractCode;//合同编码
private Float amount;// 合同金额
private Date orderdate;//签订日期
private Integer salesperson;//销售人
private Integer warrantyPeriod;//质保期
private String customerName;//客户姓名
private Integer implementType;//实施类型:0纯供货、1供货+安装、3续保、4维修
private Integer projectState;//项目状态:0待确认、1进行中、2已完成、3挂起
private String contacts;//联系人(多个联系人逗号隔开)
private Integer createUser;//创建者
private Integer modifyUser;//修改者
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Integer projectStage;//项目阶段
private Integer accountId;//集团id
/** 门店名称 */
private String name;
/** 流水号 */
private String number;
/** 合同编码 */
private String contractCode;
/** 合同金额 */
private Float amount;
/** 签订日期 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date orderdate;
/** 销售人 */
private Integer salesperson;
/** 质保期 */
private Integer warrantyPeriod;
/** 客户姓名 */
private String customerName;
/** 实施类型:0纯供货、1供货+安装、3续保、4维修 */
private Integer implementType;
/** 项目状态:0待确认、1进行中、2已完成、3挂起 */
private Integer projectState;
/** 联系人(多个联系人逗号隔开) */
private String contacts;
/** 创建者 */
private Integer createUser;
/** 修改者 */
private Integer modifyUser;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 项目阶段 */
private Integer projectStage;
/** 集团id */
private Long accountId;
//地址信息
private String consigneeName;//收货名称
private String consigneePhone;//收货手机号
private String consigneeAddress;//收货地址
private String contractName;//合同姓名
private String contractPhone;//合同手机号
private String contractAddress;//合同地址
private String invoiceName ;//发票姓名
private String invoicePhone;//发票手机号
private String invoiceAddress;//发票地址
private String invoiceInfo;//开票信息
/** 收货名称 */
private String consigneeName;
/** 收货手机号 */
private String consigneePhone;
/** 收货地址 */
private String consigneeAddress;
/** 合同姓名 */
private String contractName;
/** 合同手机号 */
private String contractPhone;
/** 合同地址 */
private String contractAddress;
/** 发票姓名 */
private String invoiceName ;
/** 发票手机号 */
private String invoicePhone;
/** 发票地址 */
private String invoiceAddress;
/** 开票信息 */
private String invoiceInfo;
private String accountName;
private Long fileNum;
}
package vion.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import vion.model.File;
import vion.model.FileInfo;
import java.util.Date;
import java.util.List;
@Data
public class TaskTempVO {
private Integer id;//自增列
private String storeName;//项目名称
private Date repairDate;//报修日期
private String faultDescription;//故障说明
private String repairPeople;//报修人
private String repairPhone;//联系方式
private Integer status;//状态(1待确认、2已确认)
private Long id;
/** 项目名称 */
private String storeName;
/** 报修时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date repairTime;
/** 故障说明 */
private String faultDescription;
/** 报修人 */
private String repairPeople;
/** 联系方式 */
private String repairPhone;
/** 状态(1待确认、2已确认) */
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
private List<File> fileList;//附件信息
// private String filename;//文件名称
// private String fileurl;//文件url
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
private String remark;
private List<FileInfo> fileList;
}
package vion.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import vion.model.File;
import vion.model.FileInfo;
import vion.model.ServiceOrder;
import java.util.Date;
import java.util.List;
@Data
public class TaskVO {
private Integer id;//自增列
private Integer storeId;//门店id(外键)
private String storeName;//门店名称
private Integer tasktempId;//预处理工单id
private Date repairDate;//报修日期
private Integer faultType;//故障类型
private String faultDescription;//故障说明
private Integer repairPeople;//报修人
private String repairPhone;//报修人联系方式
private Integer status;//状态:0待确认1进行中2已完成3挂起
private Date solveDate;//解决日期
private String faultReason;//故障原因
private Integer solveType;//解决措施:0产品BUG、1使用问题、2需求问题
private String solveDescription;//解决故障描述
private Integer createUser;//创建者
private Integer activeUser;//当前处理人
private Date createTime;//创建时间
private Date modifyTime;//修改时间
private String remark;//备注
private Integer accountId;//集团id
private List<File> fileList;//附件信息
// private String filename;//文件名称
// private String fileurl;//文件url
private Long id;
/** 门店id */
private Long storeId;
/** 门店名称 */
private String storeName;
/** 预处理工单id */
private Long tasktempId;
/** 报修日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date repairTime;
/** 故障类型 */
private Integer faultType;
/** 故障说明 */
private String faultDescription;
/** 报修人 */
private String repairPeople;
/** 报修人联系方式 */
private String repairPhone;
/** 状态:0待确认1进行中2已完成3挂起 */
private Integer status;
/** 解决日期 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date solveDate;
/** 故障原因 */
private String faultReason;
/** 解决措施:0产品BUG、1使用问题、2需求问题 */
private Integer solveType;
/** 解决故障描述 */
private String solveDescription;
/** 创建者 */
private Long createUser;
/** 当前处理人 */
private Long activeUser;
/** 截止日期 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date expDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
private String remark;
/** 集团id */
private Long accountId;
// 集团名字
private String accountName;
private List<FileInfo> fileList;
private ServiceOrder serviceOrder;
}
......@@ -5,12 +5,8 @@ spring.datasource.username=vion
spring.datasource.password=jkou72j32m4K5d8k
spring.datasource.driver-class-name=org.postgresql.Driver
server.port=8011
fileurl=D:/pic
fileUrl=D:/pic
#fileurl=/nas-data/work-order
agentid=2358374016
appkey=dingkrzwks0jpi2di3uo
appsecret=Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt
dingurl=https://oapi.dingtalk.com
#
CorpId=ding6bb660048f7ae2dcee0f45d8e4f7c288
SSOsecret=l
\ No newline at end of file
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
......@@ -3,17 +3,17 @@ spring:
active: dev
datasource:
driver-class-name: org.postgresql.Driver
aop:
proxy-target-class: true
messages:
encoding: UTF-8
basename: i18n/messages
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
main:
allow-circular-references: true
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
mvc:
view:
prefix: /
suffix: .html
static-path-pattern: /**
wx:
mp:
appid: wx96d05a0e5749f058
secret: 6033fa4f99d855cb914ec1fe2ecc77bd
\ No newline at end of file
......@@ -8,17 +8,18 @@
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="logs" />
<property name="pattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger{50} - %msg%n" />
<property name="log.path" value="logs"/>
<property name="pattern" value="[%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS})] %highlight([%-5level]) [%thread] %green(%logger{50} [%L]) - %msg%n"/>
<property name="datapattern" value="%msg%n"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
<level>debug</level>
</filter>
<encoder>
<Pattern>%highlight(%-5level) %yellow(%d{yyyy-MM-dd HH:mm:ss.SSS}) [%thread] %green(%logger{50}) - %msg%n</Pattern>
<Pattern>${pattern}</Pattern>
<!-- 设置字符集 -->
</encoder>
</appender>
......@@ -38,12 +39,12 @@
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
<maxHistory>5</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
......@@ -65,12 +66,12 @@
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
<maxHistory>5</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
......@@ -91,7 +92,7 @@
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
......@@ -118,12 +119,12 @@
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
<maxHistory>5</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
......@@ -133,6 +134,7 @@
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
......@@ -160,38 +162,21 @@
-->
<logger name="jdbc.sqlonly" level="off">
</logger>
<logger name="jdbc.audit" level="off">
</logger>
<logger name="jdbc.resultset" level="debug">
<logger name="jdbc.resultset" level="off">
</logger>
<logger name="jdbc.connection" level="off">
</logger>
<logger name="jdbc.sqltiming" level="debug">
<logger name="jdbc.sqltiming" level="off">
</logger>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!--生产环境:输出到文件-->
<!--<springProfile name="pro">-->
<!--<root level="info">-->
<!--<appender-ref ref="CONSOLE" />-->
<!--<appender-ref ref="DEBUG_FILE" />-->
<!--<appender-ref ref="INFO_FILE" />-->
<!--<appender-ref ref="ERROR_FILE" />-->
<!--<appender-ref ref="WARN_FILE" />-->
<!--</root>-->
<!--</springProfile>-->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xml; charset=utf-8" />
</head>
<title>绑定失败</title>
<style>
.center{
line-height: 200px;
height: 100%;
text-align: center;
}
.center p {
line-height: 1.5;
display: inline-block;
vertical-align: middle;
font-size: 6rem;
}
</style>
<body>
<div class="center">
<p>绑定失败</p>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xml; charset=utf-8" />
</head>
<title>绑定成功</title>
<style>
.center{
line-height: 200px;
height: 100%;
text-align: center;
}
.center p {
line-height: 1.5;
display: inline-block;
vertical-align: middle;
font-size: 3rem;
}
.center img {
width: 30rem;
height: 100%;
}
</style>
<body >
<div class="center">
<p>用户信息绑定成功,请关注下方公众号(或搜索[VION智慧门店]关注),以接收推送的消息.</p>
</div>
<div class="center">
<img src="data:image/jpeg;base64,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" alt="VION智慧门店"/>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xml; charset=utf-8" />
</head>
<title>绑定成功</title>
<style>
.center{
line-height: 200px;
height: 100%;
text-align: center;
}
.center p {
line-height: 1.5;
display: inline-block;
vertical-align: middle;
font-size: 6rem;
}
</style>
<body>
<div class="center">
<p>绑定成功</p>
</div>
</body>
</html>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!