Compare commits
31 Commits
4c0d5dbd75
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ef02afb5b6 | |||
| 8e06682522 | |||
| 5404fd38c6 | |||
| 458e49df22 | |||
| d0a5c97dcc | |||
| 6429606fda | |||
| 43302a00b8 | |||
| 918ada9a82 | |||
| a2172c691b | |||
| 5caa4b6580 | |||
| ff29da493e | |||
| 51b9180316 | |||
| 2cfadf96dd | |||
| fda3e45dc6 | |||
| 65c41326f4 | |||
| 17e07e3985 | |||
| 3106d787da | |||
| 200fd90339 | |||
| e0e733bc27 | |||
| f5cbe5cac2 | |||
| 715e6a1b70 | |||
| ba60cfb550 | |||
| 451fdc4556 | |||
| 8d6e6b3002 | |||
| 252b978ed4 | |||
| 7ef336d023 | |||
| 45cb8ef788 | |||
| 7882b94c08 | |||
| c0f4d05f00 | |||
| e9ee9d6b90 | |||
| 93c10482d0 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -24,3 +24,7 @@
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
/.idea/
|
||||
/target/
|
||||
|
||||
|
||||
|
||||
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
Normal file
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
Normal file
Binary file not shown.
12
.idea/ApifoxUploaderProjectSetting.xml
generated
Normal file
12
.idea/ApifoxUploaderProjectSetting.xml
generated
Normal file
File diff suppressed because one or more lines are too long
25
.idea/MyBatisCodeHelperDatasource.xml
generated
Normal file
25
.idea/MyBatisCodeHelperDatasource.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MyBatisCodeHelperDatasource">
|
||||
<option name="projectProfile">
|
||||
<ProjectProfile>
|
||||
<option name="controllerTemplateString" value=" #* @vtlvariable name="tableName" type="java.lang.String" *# #* @vtlvariable name="entityPackageName" type="java.lang.String" *# #* @vtlvariable name="entityClassName" type="java.lang.String" *# #* @vtlvariable name="servicePackageName" type="java.lang.String" *# #* @vtlvariable name="serviceInterfacePackage" type="java.lang.String" *# #* @vtlvariable name="serviceClassName" type="java.lang.String" *# #* @vtlvariable name="serviceInterfaceClassName" type="java.lang.String" *# #* @vtlvariable name="mapperPackageName" type="java.lang.String" *# #* @vtlvariable name="mapperClassName" type="java.lang.String" *# #* @vtlvariable name="controllerPackage" type="java.lang.String" *# #* @vtlvariable name="tableRemark" type="java.lang.String" *# #* @vtlvariable name="myDate" type="java.util.Date" *# #* @vtlvariable name="simpleDateFormat" type="java.text.SimpleDateFormat" *# package $!{controllerPackage}; import $!{entityPackageName}.$!{entityClassName}; ###set($realServiceName = $!{serviceClassName}+'Impl') import $!{servicePackageName}.$!{serviceClassName}; import org.springframework.web.bind.annotation.*; #set($serviceFirstLower = $!{serviceClassName.substring(0,1).toLowerCase()}+$!{serviceClassName.substring(1,$!{serviceClassName.length()})}) import org.springframework.beans.factory.annotation.Autowired; /** * $!{tableRemark}($!{tableName})表控制层 * * @author xxxxx */ @RestController @RequestMapping("/$!{tableName}") public class $!{entityClassName}Controller { /** * 服务对象 */ @Autowired private $!{serviceClassName} $!{serviceFirstLower}; /** * 通过主键查询单条数据 * * @param id 主键 * @return 单条数据 */ @GetMapping("selectOne") public $!{entityClassName} selectOne(Integer id) { return $!{serviceFirstLower}.selectByPrimaryKey(id); } }" />
|
||||
<option name="tableGenerateConfigs">
|
||||
<map>
|
||||
<entry key="vv_assistant:user">
|
||||
<value>
|
||||
<TableGenerateConfig>
|
||||
<option name="generatedKey" value="id" />
|
||||
<option name="javaModelName" value="User" />
|
||||
<option name="sequenceColumn" value="" />
|
||||
<option name="sequenceId" value="" />
|
||||
<option name="useActualColumnName" value="false" />
|
||||
</TableGenerateConfig>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</ProjectProfile>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
10
.idea/dataSources.xml
generated
10
.idea/dataSources.xml
generated
@@ -1,11 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="vv_assistant@120.26.251.180" uuid="825abb89-80f2-475c-9ee4-5b0afe788f5b">
|
||||
<data-source source="LOCAL" name="vv_assistant@localhost" uuid="a97b176f-f814-4c14-b11c-1945b687d99f">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<imported>true</imported>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://120.26.251.180:3326/vv_assistant</jdbc-url>
|
||||
<jdbc-url>jdbc:mysql://localhost:3306/vv_assistant?allowMultiQueries=true</jdbc-url>
|
||||
<jdbc-additional-properties>
|
||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
||||
</jdbc-additional-properties>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: jakarta.activation:jakarta.activation-api:1.2.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/activation/jakarta.activation-api/1.2.2/jakarta.activation-api-1.2.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/activation/jakarta.activation-api/1.2.2/jakarta.activation-api-1.2.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/activation/jakarta.activation-api/1.2.2/jakarta.activation-api-1.2.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/xml/bind/jakarta.xml.bind-api/2.3.3/jakarta.xml.bind-api-2.3.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/xml/bind/jakarta.xml.bind-api/2.3.3/jakarta.xml.bind-api-2.3.3-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/jakarta/xml/bind/jakarta.xml.bind-api/2.3.3/jakarta.xml.bind-api-2.3.3-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.apiguardian:apiguardian-api:1.1.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
13
.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml
generated
13
.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml
generated
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.hamcrest:hamcrest:2.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest/2.2/hamcrest-2.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest/2.2/hamcrest-2.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest/2.2/hamcrest-2.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.jupiter:junit-jupiter:5.8.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.8.2/junit-jupiter-5.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.8.2/junit-jupiter-5.8.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.8.2/junit-jupiter-5.8.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.jupiter:junit-jupiter-api:5.8.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.jupiter:junit-jupiter-engine:5.8.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.8.2/junit-jupiter-engine-5.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.8.2/junit-jupiter-engine-5.8.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.8.2/junit-jupiter-engine-5.8.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.jupiter:junit-jupiter-params:5.8.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-params/5.8.2/junit-jupiter-params-5.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-params/5.8.2/junit-jupiter-params-5.8.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-params/5.8.2/junit-jupiter-params-5.8.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.platform:junit-platform-commons:1.8.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.junit.platform:junit-platform-engine:1.8.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.objenesis:objenesis:3.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/3.2/objenesis-3.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/3.2/objenesis-3.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/3.2/objenesis-3.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.opentest4j:opentest4j:1.2.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.skyscreamer:jsonassert:1.5.1">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/skyscreamer/jsonassert/1.5.1/jsonassert-1.5.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/skyscreamer/jsonassert/1.5.1/jsonassert-1.5.1-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/skyscreamer/jsonassert/1.5.1/jsonassert-1.5.1-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.slf4j:jul-to-slf4j:1.7.36">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: org.slf4j:slf4j-api:1.7.36">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -8,5 +8,5 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (tiktok-data)" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/vvPkAssistant.iml" filepath="$PROJECT_DIR$/vvPkAssistant.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
23
.xcodemap/config/xcodemap-class-filter.yaml
Normal file
23
.xcodemap/config/xcodemap-class-filter.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
autoDetectedPackages:
|
||||
- vvpkassistant
|
||||
enableAutoDetect: true
|
||||
entryDisplayConfig:
|
||||
excludedPathPatterns: []
|
||||
skipJsCss: true
|
||||
funcDisplayConfig:
|
||||
skipConstructors: false
|
||||
skipFieldAccess: true
|
||||
skipFieldChange: true
|
||||
skipGetters: false
|
||||
skipNonProjectPackages: false
|
||||
skipPrivateMethods: false
|
||||
skipSetters: false
|
||||
ignoreSameClassCall: null
|
||||
ignoreSamePackageCall: null
|
||||
includedPackagePrefixes: null
|
||||
includedParentClasses: null
|
||||
name: xcodemap-filter
|
||||
recordMode: all
|
||||
sourceDisplayConfig:
|
||||
color: blue
|
||||
startOnDebug: false
|
||||
72
pom.xml
72
pom.xml
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.vv.pk.assistant</groupId>
|
||||
@@ -61,6 +61,10 @@
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -102,6 +106,72 @@
|
||||
<version>5.6.227</version>
|
||||
</dependency>
|
||||
|
||||
<!-- mailgun 邮件服务 -->
|
||||
<dependency>
|
||||
<groupId>com.mailgun</groupId>
|
||||
<artifactId>mailgun-java</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- caffeine 本地缓存 -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.9.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- crypto 加密 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
<version>5.5.1</version> <!-- 请检查最新版本 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.44.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- hu-tool -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.38</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
<!-- 二维码生成-->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
<!-- 引入本项目 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara.x-file-storage</groupId>
|
||||
<artifactId>x-file-storage-spring</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<!-- 引入 腾讯云 COS SDK,如果使用其它存储平台,就引入对应的 SDK -->
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>5.6.227</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package vvpkassistant.Anchors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.pk.PkRecordDao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("anchor")
|
||||
public class AnchorsController {
|
||||
|
||||
@Autowired
|
||||
private AnchorDao anchorDao;
|
||||
|
||||
@Autowired
|
||||
private PkRecordDao recordDao;
|
||||
|
||||
// 添加新主播
|
||||
@PostMapping("add")
|
||||
public ResponseData<Object> addNewAnchor(@RequestBody AnchorModel model) {
|
||||
//查询是否存在重复主播
|
||||
int r = anchorDao.selectAnchorWithAnchorIdAndUserId(model.getAnchorId(), model.getCreateUserId());
|
||||
if (r != 0) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"该主播已存在");
|
||||
}
|
||||
int insert = anchorDao.insert(model);
|
||||
return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,"添加失败");
|
||||
}
|
||||
|
||||
// 查询我的主播列表
|
||||
@PostMapping("list")
|
||||
public ResponseData<Object> myAnchorList(@RequestBody Map<String,Integer> map) {
|
||||
Integer userId = map.get("id");
|
||||
List<AnchorModel> anchorModels = anchorDao.selectMyAnchor(userId);
|
||||
return ResponseData.success(anchorModels);
|
||||
}
|
||||
|
||||
// 删除我的主播
|
||||
@PostMapping("deleteMyAnchor")
|
||||
public ResponseData<Object> deleteMyAnchor(@RequestBody Map<String,Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
AnchorModel anchorModel = anchorDao.selectById(id);
|
||||
try {
|
||||
String anchorId = anchorModel.getAnchorId();
|
||||
// 根据主播id查询该主播是否存在pk记录
|
||||
int i = recordDao.existsPkRecordByAnchor(anchorId);
|
||||
if (i > 0) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"该主播已有pk记录。无法删除");
|
||||
}
|
||||
int r = anchorDao.deleteById(id);
|
||||
return r == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
} catch (Exception e) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"非法数据,操作失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 更新主播信息
|
||||
@PostMapping("updateAnchorInfo")
|
||||
public ResponseData<Object> updateAnchorInfo(@RequestBody AnchorModel model) {
|
||||
// 查询该主播是否存在记录
|
||||
int i = recordDao.existsPkRecordByAnchor(model.getAnchorId());
|
||||
if (i > 0) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"该主播已有pk记录。无法修改信息");
|
||||
}
|
||||
int r = anchorDao.updateById(model);
|
||||
return r == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package vvpkassistant.Anchors;
|
||||
package vvpkassistant.Anchors.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.Anchors.model.AnchorModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.Anchors;
|
||||
package vvpkassistant.Anchors.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@@ -0,0 +1,20 @@
|
||||
package vvpkassistant.Anchors.service;
|
||||
|
||||
import vvpkassistant.Anchors.model.AnchorModel;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/1 19:59
|
||||
*/
|
||||
public interface AnchorsService {
|
||||
Integer addNewAnchor(AnchorModel model);
|
||||
|
||||
List<AnchorModel> selectMyAnchor(Integer userId);
|
||||
|
||||
Integer deleteMyAnchor(Integer id);
|
||||
|
||||
Integer updateAnchorInfo(AnchorModel model);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package vvpkassistant.Anchors.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import vvpkassistant.Anchors.mapper.AnchorDao;
|
||||
import vvpkassistant.Anchors.model.AnchorModel;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.pk.mapper.PkRecordDao;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/1 19:59
|
||||
*/
|
||||
@Service
|
||||
public class AnchorsServiceImpl implements AnchorsService {
|
||||
|
||||
|
||||
@Resource
|
||||
private AnchorDao anchorDao;
|
||||
|
||||
@Resource
|
||||
private PkRecordDao recordDao;
|
||||
@Override
|
||||
public Integer addNewAnchor(AnchorModel model) {
|
||||
//查询是否存在重复主播
|
||||
int r = anchorDao.selectAnchorWithAnchorIdAndUserId(model.getAnchorId(), model.getCreateUserId());
|
||||
if (r != 0) {
|
||||
throw new BusinessException(ErrorCode.ANCHOR_ALREADY_EXISTS);
|
||||
}
|
||||
return anchorDao.insert(model);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<AnchorModel> selectMyAnchor(Integer userId) {
|
||||
return anchorDao.selectMyAnchor(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer deleteMyAnchor(Integer id) {
|
||||
AnchorModel anchorModel = anchorDao.selectById(id);
|
||||
if (anchorModel == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"主播不存在");
|
||||
}
|
||||
String anchorId = anchorModel.getAnchorId();
|
||||
// 根据主播id查询该主播是否存在pk记录
|
||||
int i = recordDao.existsPkRecordByAnchor(anchorId);
|
||||
if (i > 0) {
|
||||
throw new BusinessException(ErrorCode.ANCHOR_HAS_PKRECORD,"该主播已有pk记录。无法删除");
|
||||
}
|
||||
return anchorDao.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer updateAnchorInfo(AnchorModel model) {
|
||||
// 查询该主播是否存在记录
|
||||
int i = recordDao.existsPkRecordByAnchor(model.getAnchorId());
|
||||
if (i > 0) {
|
||||
throw new BusinessException(ErrorCode.ANCHOR_HAS_PKRECORD,"该主播已有pk记录。无法修改信息");
|
||||
}
|
||||
return anchorDao.updateById(model);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package vvpkassistant;
|
||||
import org.dromara.x.file.storage.spring.EnableFileStorage;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAsync
|
||||
@EnableFileStorage
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -1,36 +1,45 @@
|
||||
package vvpkassistant.Data;
|
||||
import lombok.Data;
|
||||
import org.springframework.lang.Nullable;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ResponseData<T> {
|
||||
public class ResponseData<T> implements Serializable {
|
||||
|
||||
// 状态码
|
||||
T data = null;
|
||||
private T data ;
|
||||
public String msg;
|
||||
public Integer code;
|
||||
|
||||
ResponseData() {}
|
||||
public ResponseData(int code, T data,String message) {
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
this.msg = message;
|
||||
}
|
||||
|
||||
public ResponseData(int code, T data) {
|
||||
this(code,data,"");
|
||||
}
|
||||
|
||||
public ResponseData(ErrorCode errorCode) {
|
||||
this(errorCode.getCode(), null, errorCode.getMessage());
|
||||
}
|
||||
|
||||
// 成功的返回方法
|
||||
public static <T> ResponseData<T> success(@Nullable T param) {
|
||||
ResponseInfo info = ResponseInfo.SUCCESS;
|
||||
ResponseData<T> data = new ResponseData<>();
|
||||
data.setData(param);
|
||||
data.setCode(info.getCode());
|
||||
data.setMsg(info.getDesc());
|
||||
return data;
|
||||
public static <T> ResponseData<T> success(T data) {
|
||||
return new ResponseData<>(ResponseInfo.SUCCESS.getCode(),data,"ok");
|
||||
}
|
||||
|
||||
// 返回错误的方法
|
||||
public static ResponseData<Object> error(ResponseInfo info, @Nullable String msg) {
|
||||
ResponseData<Object> data = new ResponseData<>();
|
||||
data.msg = msg != null ? msg : info.getDesc();
|
||||
data.code = info.getCode();
|
||||
data.data = null;
|
||||
return data;
|
||||
public static ResponseData<Object> error(int code,String message) {
|
||||
return new ResponseData<>(code, null,message);
|
||||
}
|
||||
|
||||
public static ResponseData<Object> error(ErrorCode errorCode) {
|
||||
return new ResponseData<>(errorCode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package vvpkassistant.FunctionConfig;
|
||||
package vvpkassistant.FunctionConfig.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import vvpkassistant.FunctionConfig.model.FunctionConfigModel;
|
||||
|
||||
@Mapper
|
||||
public interface FunctionConfigMapper extends BaseMapper<FunctionConfigModel> {
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.FunctionConfig;
|
||||
package vvpkassistant.FunctionConfig.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@@ -0,0 +1,13 @@
|
||||
package vvpkassistant.FunctionConfig.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import vvpkassistant.FunctionConfig.model.FunctionConfigModel;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 13:37
|
||||
*/
|
||||
public interface FunctionConfigService extends IService<FunctionConfigModel> {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package vvpkassistant.FunctionConfig.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.FunctionConfig.mapper.FunctionConfigMapper;
|
||||
import vvpkassistant.FunctionConfig.model.FunctionConfigModel;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 13:38
|
||||
*/
|
||||
@Service
|
||||
public class FunctionConfigServiceImpl extends ServiceImpl<FunctionConfigMapper,FunctionConfigModel> implements FunctionConfigService {
|
||||
|
||||
@Resource
|
||||
private FunctionConfigMapper functionConfigMapper;
|
||||
|
||||
}
|
||||
12
src/main/java/vvpkassistant/OTP/model/OTPDTO.java
Normal file
12
src/main/java/vvpkassistant/OTP/model/OTPDTO.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package vvpkassistant.OTP.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/14 20:53
|
||||
*/
|
||||
@Data
|
||||
public class OTPDTO {
|
||||
private String secretKey;
|
||||
}
|
||||
11
src/main/java/vvpkassistant/OTP/service/OTPService.java
Normal file
11
src/main/java/vvpkassistant/OTP/service/OTPService.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package vvpkassistant.OTP.service;
|
||||
|
||||
import vvpkassistant.OTP.model.OTPDTO;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/14 20:51
|
||||
*/
|
||||
public interface OTPService {
|
||||
Object getOTP();
|
||||
}
|
||||
41
src/main/java/vvpkassistant/OTP/service/OTPServiceImpl.java
Normal file
41
src/main/java/vvpkassistant/OTP/service/OTPServiceImpl.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package vvpkassistant.OTP.service;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.OTP.model.OTPDTO;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/14 20:51
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OTPServiceImpl implements OTPService {
|
||||
|
||||
@Value("${IM-secretKey}")
|
||||
private String IM_SecretKey;
|
||||
|
||||
@Override
|
||||
public Object getOTP() {
|
||||
try {
|
||||
String otp = "000" + System.currentTimeMillis();
|
||||
SecretKeySpec key = new SecretKeySpec(IM_SecretKey.getBytes(), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
|
||||
byte[] otpBytes = otp.getBytes();
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
byte[] encryptedOTP = cipher.doFinal(otpBytes);
|
||||
otp = Base64.encode(encryptedOTP);
|
||||
return otp;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to generate GoEasy-OTP.", e);
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"Failed to generate GoEasy-OTP.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package vvpkassistant.SystemMessage;
|
||||
package vvpkassistant.SystemMessage.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.SystemMessage.model.SystemMessage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.SystemMessage;
|
||||
package vvpkassistant.SystemMessage.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
22
src/main/java/vvpkassistant/Tools/BcryptUtils.java
Normal file
22
src/main/java/vvpkassistant/Tools/BcryptUtils.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package vvpkassistant.Tools;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 18:19
|
||||
*/
|
||||
public class BcryptUtils {
|
||||
|
||||
|
||||
|
||||
public static String encryptPassword(String password) {
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
public static Boolean matchPassword(String rawPassWord,String encodePassword){
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(encodePassword, rawPassWord);
|
||||
}
|
||||
}
|
||||
16
src/main/java/vvpkassistant/Tools/CacheHolder.java
Normal file
16
src/main/java/vvpkassistant/Tools/CacheHolder.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package vvpkassistant.Tools;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/6 20:15
|
||||
*/
|
||||
public class CacheHolder {
|
||||
public static final Cache<String, String> VERIFICATION_MAIL = Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
}
|
||||
31
src/main/java/vvpkassistant/Tools/QRCodeUtil.java
Normal file
31
src/main/java/vvpkassistant/Tools/QRCodeUtil.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package vvpkassistant.Tools;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class QRCodeUtil {
|
||||
|
||||
public static String generateQRCode(String content, int width, int height)
|
||||
throws WriterException, IOException {
|
||||
|
||||
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
||||
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(
|
||||
content, BarcodeFormat.QR_CODE, width, height, hints);
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
MatrixToImageWriter.writeToStream(matrix, "PNG", outputStream);
|
||||
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,8 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
import vvpkassistant.Data.WxParam;
|
||||
import vvpkassistant.User.UserModel;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package vvpkassistant.User;
|
||||
package vvpkassistant.User.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.pk.PkRecord;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.pk.model.PkRecord;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
29
src/main/java/vvpkassistant/User/model/DTO/LoginInfoDTO.java
Normal file
29
src/main/java/vvpkassistant/User/model/DTO/LoginInfoDTO.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package vvpkassistant.User.model.DTO;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginInfoDTO {
|
||||
|
||||
/**
|
||||
* 唯一标识
|
||||
*/
|
||||
private String uuid;
|
||||
/**
|
||||
* 设备号
|
||||
*/
|
||||
private String device;
|
||||
|
||||
/**
|
||||
* 扫码状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
private Integer id;
|
||||
}
|
||||
13
src/main/java/vvpkassistant/User/model/DTO/ScanInfoDTO.java
Normal file
13
src/main/java/vvpkassistant/User/model/DTO/ScanInfoDTO.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package vvpkassistant.User.model.DTO;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/5 16:43
|
||||
*/
|
||||
@Data
|
||||
public class ScanInfoDTO {
|
||||
private String uuid;
|
||||
private Integer id;
|
||||
}
|
||||
30
src/main/java/vvpkassistant/User/model/DTO/UserModelDTO.java
Normal file
30
src/main/java/vvpkassistant/User/model/DTO/UserModelDTO.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package vvpkassistant.User.model.DTO;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
|
||||
public class UserModelDTO {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id; // 主键
|
||||
private String nickName; // 昵称
|
||||
private String phoneNumber; // 手机号码
|
||||
private String headerIcon; // 头像
|
||||
private String openid; // openid
|
||||
private String sessionKey; // session key
|
||||
private Integer status; // 用户状态 0 正常 其他业务逻辑待定
|
||||
private Long createTime; // 创建时间
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
private Integer inviterId; // 邀请人id
|
||||
private String email;
|
||||
private String newPassword;
|
||||
private String confirmPassword;
|
||||
private String oldPassword;
|
||||
private String password;
|
||||
private String token;
|
||||
private String userName;
|
||||
private String userNameOrEmail;
|
||||
}
|
||||
13
src/main/java/vvpkassistant/User/model/QrcodeEntity.java
Normal file
13
src/main/java/vvpkassistant/User/model/QrcodeEntity.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package vvpkassistant.User.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/5 20:06
|
||||
*/
|
||||
@Data
|
||||
public class QrcodeEntity {
|
||||
private String uuid;
|
||||
private String type;
|
||||
}
|
||||
15
src/main/java/vvpkassistant/User/model/QrcodeVO.java
Normal file
15
src/main/java/vvpkassistant/User/model/QrcodeVO.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package vvpkassistant.User.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/5 18:14
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class QrcodeVO {
|
||||
private String uuid;
|
||||
private String qrcode;
|
||||
}
|
||||
32
src/main/java/vvpkassistant/User/model/ResponseVO.java
Normal file
32
src/main/java/vvpkassistant/User/model/ResponseVO.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package vvpkassistant.User.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ResponseVO {
|
||||
|
||||
/**
|
||||
* 唯一标识
|
||||
*/
|
||||
private String uuid;
|
||||
/**
|
||||
* 登录二维码
|
||||
*/
|
||||
private String qrcode;
|
||||
|
||||
/**
|
||||
* jwt令牌
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 扫码状态
|
||||
*/
|
||||
private String status;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.User;
|
||||
package vvpkassistant.User.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@@ -20,4 +20,8 @@ public class UserModel {
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
private Integer inviterId; // 邀请人id
|
||||
private String email;
|
||||
private String password;
|
||||
private Integer mailVerification;
|
||||
private String userName;
|
||||
}
|
||||
28
src/main/java/vvpkassistant/User/model/UserModelVO.java
Normal file
28
src/main/java/vvpkassistant/User/model/UserModelVO.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package vvpkassistant.User.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
|
||||
@Data
|
||||
public class UserModelVO {
|
||||
private Integer id; // 主键
|
||||
private String nickName; // 昵称
|
||||
private String phoneNumber; // 手机号码
|
||||
private String headerIcon; // 头像
|
||||
private String openid; // openid
|
||||
private String sessionKey; // session key
|
||||
private Integer status; // 用户状态 0 正常 其他业务逻辑待定
|
||||
private Long createTime; // 创建时间
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
private Integer inviterId; // 邀请人id
|
||||
private String email;
|
||||
private String token;
|
||||
private Boolean newAccount;
|
||||
private WxChatParam chatInfo;
|
||||
private Boolean havaPassword;
|
||||
private Integer mailVerification;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package vvpkassistant.User.model.enumeration;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum LoginStatusEnum {
|
||||
UNSCANNED("未扫描"),
|
||||
SCANNED("已扫描"),
|
||||
CONFIRMED("已确认");
|
||||
|
||||
private String desc;
|
||||
|
||||
|
||||
LoginStatusEnum(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
47
src/main/java/vvpkassistant/User/service/UserService.java
Normal file
47
src/main/java/vvpkassistant/User/service/UserService.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package vvpkassistant.User.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import vvpkassistant.User.model.DTO.LoginInfoDTO;
|
||||
import vvpkassistant.User.model.DTO.ScanInfoDTO;
|
||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.User.model.UserModelVO;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 16:19
|
||||
*/
|
||||
public interface UserService extends IService<UserModel> {
|
||||
UserModelVO loginWithMail(UserModelDTO model);
|
||||
|
||||
UserModelVO updateUserInfo(UserModelDTO userModelDTO);
|
||||
|
||||
UserModelVO addUserWithMail(UserModelDTO model);
|
||||
|
||||
Boolean activateAccount(String token);
|
||||
|
||||
Boolean verificationMail(String token);
|
||||
|
||||
Object generatedQrcode();
|
||||
|
||||
Object checkQrcode(String uuid);
|
||||
|
||||
LoginInfoDTO scanQrcode(ScanInfoDTO scanInfoDTO);
|
||||
|
||||
void confirm(ScanInfoDTO scanInfoDTO);
|
||||
|
||||
void logOut(Integer id);
|
||||
|
||||
boolean setPassWord(UserModelDTO userModelDTO);
|
||||
|
||||
Object sendForgetPassWordMail(MailModel mailModel);
|
||||
|
||||
Object resetPassWord(UserModelDTO userModelDTO);
|
||||
|
||||
Boolean updateUserMail(MailModel mailModel);
|
||||
|
||||
Boolean checkUserName(UserModelDTO userModelDTO);
|
||||
|
||||
}
|
||||
379
src/main/java/vvpkassistant/User/service/UserServiceImpl.java
Normal file
379
src/main/java/vvpkassistant/User/service/UserServiceImpl.java
Normal file
@@ -0,0 +1,379 @@
|
||||
package vvpkassistant.User.service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.temp.SaTempUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.zxing.WriterException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
import vvpkassistant.Tools.BcryptUtils;
|
||||
import vvpkassistant.Tools.CacheHolder;
|
||||
import vvpkassistant.Tools.QRCodeUtil;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.*;
|
||||
import vvpkassistant.User.model.DTO.LoginInfoDTO;
|
||||
import vvpkassistant.User.model.DTO.ScanInfoDTO;
|
||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||
import vvpkassistant.User.model.enumeration.LoginStatusEnum;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
import vvpkassistant.mail.service.MailService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 16:19
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements UserService {
|
||||
|
||||
@Resource
|
||||
private UserDao userDao;
|
||||
|
||||
@Resource
|
||||
private WxChatParam wxChatParam;
|
||||
@Autowired
|
||||
private MailService mailService;
|
||||
|
||||
|
||||
private final Cache<String, LoginInfoDTO> qrcodeCache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(2, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public UserModelVO loginWithMail(UserModelDTO model) {
|
||||
if (model.getUserNameOrEmail().isEmpty()){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名或邮箱不能为空");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(UserModel::getEmail,model.getUserNameOrEmail())
|
||||
.or()
|
||||
.eq(UserModel::getUserName,model.getUserNameOrEmail())
|
||||
.in(UserModel::getStatus, 0,2);
|
||||
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
String password = userModel.getPassword();
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
if (BcryptUtils.matchPassword(password, model.getPassword())) {
|
||||
StpUtil.login(userModel.getId());
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
userModelVO.setChatInfo(wxChatParam);
|
||||
return userModelVO;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.PASSWORD_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModelVO updateUserInfo(UserModelDTO userModelDTO) {
|
||||
|
||||
UserModel userInfo = userDao.selectById(userModelDTO.getId());
|
||||
if (userInfo == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
// 用户没有密码的情况下设置密码
|
||||
if (userInfo.getPassword() == null && userModelDTO.getNewPassword() != null) {
|
||||
if (!userModelDTO.getNewPassword().isEmpty()){
|
||||
if (userModelDTO.getNewPassword().length()<6){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
}
|
||||
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||
}
|
||||
}
|
||||
if (userModelDTO.getEmail() != null) {
|
||||
mailService.sendVerificationMail(userModelDTO.getEmail(), userModelDTO.getId());
|
||||
}
|
||||
|
||||
// 用户有密码的情况下重新设置密码
|
||||
if (userInfo.getPassword() != null && userModelDTO.getOldPassword() != null) {
|
||||
if (BcryptUtils.matchPassword(userInfo.getPassword(),userModelDTO.getOldPassword())) {
|
||||
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.PASSWORD_ERROR,"旧密码不正确");
|
||||
}
|
||||
}
|
||||
|
||||
UserModel userModel = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||
int i = userDao.updateById(userModel);
|
||||
// 返回结果
|
||||
UserModel afterUserInfo = userDao.selectById(userModel.getId());
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(afterUserInfo, UserModelVO.class);
|
||||
userModelVO.setNewAccount(false);
|
||||
if (i == 1){
|
||||
return userModelVO;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModelVO addUserWithMail(UserModelDTO userModelDTO) {
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
|
||||
LambdaQueryWrapper<UserModel> usernameWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
lambdaQueryWrapper.eq(UserModel::getEmail,userModelDTO.getEmail());
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
|
||||
|
||||
|
||||
UserModel usernameModel = userDao.selectOne(usernameWrapper
|
||||
.eq(UserModel::getUserName, userModelDTO.getUserName()));
|
||||
|
||||
if (userModel != null) {
|
||||
throw new BusinessException(ErrorCode.MAIL_ALREADY_EXIST);
|
||||
}
|
||||
if (usernameModel != null) {
|
||||
throw new BusinessException(ErrorCode.USERNAME_ALREADY_EXIST);
|
||||
}
|
||||
if (userModelDTO.getPassword().length() < 6 ){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
}
|
||||
if (userModelDTO.getUserName().isEmpty()){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名不能为空");
|
||||
}
|
||||
|
||||
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||
userModelDTO.setCreateTime(VVTools.currentTimeStamp());
|
||||
//设置状态为待验证
|
||||
userModelDTO.setStatus(2);
|
||||
//设置积分为0
|
||||
userModelDTO.setPoints(0);
|
||||
UserModel userModelEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||
userModelEntity.setMailVerification(1);
|
||||
if ( userDao.insert(userModelEntity) != 1){
|
||||
throw new BusinessException(ErrorCode.ADD_FAILED,"用户注册失败");
|
||||
}
|
||||
mailService.sendMail(userModelDTO.getEmail(),userModelEntity.getId());
|
||||
// 判断用户是否为邀请用户
|
||||
if (userModelDTO.getInviterId() != null) {
|
||||
UserModel oldUser = userDao.selectById(userModelDTO.getInviterId());
|
||||
oldUser.setPoints(oldUser.getPoints() + 10);
|
||||
userDao.updateById(oldUser);
|
||||
}
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModelEntity, UserModelVO.class);
|
||||
StpUtil.login(userModelVO.getId());
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
userModelVO.setHavaPassword(true);
|
||||
userModelVO.setNewAccount(true);
|
||||
userModelVO.setChatInfo(wxChatParam);
|
||||
log.info("用户{}注册,邮箱{},手机号{}",userModelVO.getId(),userModelVO.getEmail(),userModelVO.getPhoneNumber());
|
||||
return userModelVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean activateAccount(String token) {
|
||||
Integer userId = SaTempUtil.parseToken(token, Integer.class);
|
||||
UserModel userModel = userDao.selectById(userId);
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
if (userModel.getStatus() == 0){
|
||||
throw new BusinessException(ErrorCode.USER_HAS_ACTIVATED);
|
||||
}
|
||||
userModel.setStatus(0);
|
||||
userModel.setMailVerification(0);
|
||||
if (userDao.updateById(userModel) == 1){
|
||||
return true;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.UPDATE_FAILED,"激活失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean verificationMail(String token) {
|
||||
Integer userId = SaTempUtil.parseToken(token, Integer.class);
|
||||
UserModel userModel = userDao.selectById(userId);
|
||||
userModel.setMailVerification(0);
|
||||
if (userDao.updateById(userModel) == 1){
|
||||
return true;
|
||||
}
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"邮箱验证失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
public QrcodeVO generatedQrcode() {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
QrcodeEntity qrcodeEntity = new QrcodeEntity();
|
||||
qrcodeEntity.setUuid(uuid);
|
||||
qrcodeEntity.setType("qrcdoe");
|
||||
String base64QR = null;
|
||||
try {
|
||||
base64QR = QRCodeUtil.generateQRCode(JSONUtil.toJsonStr(qrcodeEntity), 200, 200);
|
||||
} catch (WriterException | IOException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"二维码生成失败");
|
||||
}
|
||||
|
||||
LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
|
||||
loginInfoDTO.setStatus(LoginStatusEnum.UNSCANNED.name());
|
||||
loginInfoDTO.setUuid(uuid);
|
||||
|
||||
// 二维码uuid绑定,存入缓存
|
||||
qrcodeCache.put(uuid,loginInfoDTO);
|
||||
// 返回生成的二维码信息
|
||||
QrcodeVO vo = QrcodeVO.builder().uuid(uuid).qrcode("data:image/png;base64," + base64QR).build();
|
||||
log.info("-------生成二维码成功:{}-------", uuid);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object checkQrcode(String uuid) {
|
||||
LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(uuid);
|
||||
if (loginInfoDTO == null) {
|
||||
throw new BusinessException(ErrorCode.QRCODE_EXPIRED);
|
||||
}
|
||||
if (Objects.equals(loginInfoDTO.getStatus(), LoginStatusEnum.SCANNED.name())) {
|
||||
return loginInfoDTO;
|
||||
}
|
||||
if (LoginStatusEnum.CONFIRMED.name().equals(loginInfoDTO.getStatus())) {
|
||||
UserModel userModel = userDao.selectById(loginInfoDTO.getId());
|
||||
StpUtil.login(userModel.getId());
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
userModelVO.setChatInfo(wxChatParam);
|
||||
return userModelVO;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginInfoDTO scanQrcode(ScanInfoDTO scanInfoDTO) {
|
||||
LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(scanInfoDTO.getUuid());
|
||||
if (loginInfoDTO != null) {
|
||||
loginInfoDTO.setStatus(LoginStatusEnum.SCANNED.name());
|
||||
qrcodeCache.put(scanInfoDTO.getUuid(),loginInfoDTO);
|
||||
}
|
||||
log.info("-------扫码成功uuid:{}-------", scanInfoDTO.getUuid());
|
||||
return loginInfoDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void confirm(ScanInfoDTO scanInfoDTO) {
|
||||
LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(scanInfoDTO.getUuid());
|
||||
if (loginInfoDTO != null) {
|
||||
loginInfoDTO.setStatus(LoginStatusEnum.CONFIRMED.name());
|
||||
loginInfoDTO.setId(scanInfoDTO.getId());
|
||||
qrcodeCache.put(scanInfoDTO.getUuid(),loginInfoDTO);
|
||||
}
|
||||
log.info("-------确认登录成功uuid:{}-------", scanInfoDTO.getUuid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logOut(Integer id) {
|
||||
StpUtil.logout(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPassWord(UserModelDTO userModelDTO) {
|
||||
UserModel userModel = userDao.selectById(userModelDTO.getId());
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
if (userModel.getPassword()!= null){
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"已设置过密码");
|
||||
}
|
||||
if (userModelDTO.getPassword().length()< 6 ){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
}
|
||||
if (!Objects.equals(userModelDTO.getPassword(), userModelDTO.getConfirmPassword())) {
|
||||
log.error("密码{},确认密码{}",userModelDTO.getPassword(),userModelDTO.getConfirmPassword());
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次密码输入不一致");
|
||||
}else{
|
||||
UserModel saveEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||
saveEntity.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||
return userDao.updateById(saveEntity) == 1 ;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object sendForgetPassWordMail(MailModel mailModel) {
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||
.eq(UserModel::getEmail, mailModel.getMailAddress())
|
||||
.eq(UserModel::getStatus, 0)
|
||||
.eq(UserModel::getMailVerification, 0));
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
mailService.sendForgetPassWordMail(mailModel.getMailAddress(),userModel.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resetPassWord(UserModelDTO userModelDTO) {
|
||||
Integer i = SaTempUtil.parseToken(userModelDTO.getToken(), Integer.class);
|
||||
UserModel userModel = userDao.selectById(i);
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
if (userModelDTO.getPassword().equals(userModelDTO.getConfirmPassword())) {
|
||||
userModel.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||
return userDao.updateById(userModel) == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateUserMail(MailModel mailModel) {
|
||||
String mail = CacheHolder.VERIFICATION_MAIL.getIfPresent(mailModel.getCode());
|
||||
if (mail != null && mail.isEmpty()) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"验证码过期或验证码错误");
|
||||
}
|
||||
LambdaQueryWrapper<UserModel> duplicateMailUserWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
UserModel duplicateMailUser = userDao.selectOne(duplicateMailUserWrapper
|
||||
.eq(UserModel::getEmail, mailModel.getMailAddress()));
|
||||
if (duplicateMailUser != null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"邮箱地址已被使用");
|
||||
}
|
||||
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||
.eq(UserModel::getEmail, mail)
|
||||
.eq(UserModel::getMailVerification, 0 ));
|
||||
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_MAIL_NOT_VERIFICATION);
|
||||
}
|
||||
userModel.setEmail(mailModel.getMailAddress());
|
||||
mailService.sendVerificationMail(mailModel.getMailAddress(),userModel.getId());
|
||||
userModel.setMailVerification(1);
|
||||
return userDao.updateById(userModel) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean checkUserName(UserModelDTO userModelDTO) {
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||
.eq(UserModel::getUserName, userModelDTO.getUserName()));
|
||||
return userModel == null;
|
||||
}
|
||||
|
||||
}
|
||||
55
src/main/java/vvpkassistant/aop/LogInterceptor.java
Normal file
55
src/main/java/vvpkassistant/aop/LogInterceptor.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package vvpkassistant.aop;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LogInterceptor {
|
||||
|
||||
/**
|
||||
* 执行拦截
|
||||
*/
|
||||
@Around("execution(* vvpkassistant.controller.*.*(..))")
|
||||
public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
|
||||
// 计时
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
// 获取请求路径
|
||||
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
|
||||
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
|
||||
// 生成请求唯一 id
|
||||
String requestId = UUID.randomUUID().toString();
|
||||
String url = httpServletRequest.getRequestURI();
|
||||
// 获取请求参数
|
||||
Object[] args = point.getArgs();
|
||||
String reqParam = "[" + StringUtils.join(args, ", ") + "]";
|
||||
// 输出请求日志
|
||||
log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
|
||||
httpServletRequest.getRemoteHost(), reqParam);
|
||||
// log.info("request start,id: {}, path: {}, ip: {}", requestId, url,
|
||||
// httpServletRequest.getRemoteHost());
|
||||
// 执行原方法
|
||||
Object result = point.proceed();
|
||||
// 输出响应日志
|
||||
stopWatch.stop();
|
||||
long totalTimeMillis = stopWatch.getTotalTimeMillis();
|
||||
log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package vvpkassistant.chat;
|
||||
package vvpkassistant.chat.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.chat.model.ChatModel;
|
||||
|
||||
@Mapper
|
||||
public interface ChatDao extends BaseMapper<ChatModel> {
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.chat;
|
||||
package vvpkassistant.chat.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
65
src/main/java/vvpkassistant/common/ErrorCode.java
Normal file
65
src/main/java/vvpkassistant/common/ErrorCode.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package vvpkassistant.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ErrorCode {
|
||||
/* =============== 全局通用 =============== */
|
||||
SUCCESS(0, "ok"),
|
||||
PARAMS_ERROR(40000, "请求参数错误"),
|
||||
SYSTEM_ERROR(50000, "系统错误"),
|
||||
|
||||
/* =============== 业务失败 =============== */
|
||||
ADD_FAILED(1001, "添加失败"),
|
||||
DELETE_FAILED(1002, "删除失败"),
|
||||
UPDATE_FAILED(1003, "更新失败"),
|
||||
CONFIG_NAME_DUPLICATE(1004, "配置名称重复"),
|
||||
SIGN_IN_FAIL(1004, "当天已签到"),
|
||||
EMAIL_SEND_FREQUENT(1005,"邮件发送太频繁,请 1 分钟后再试"),
|
||||
QRCODE_EXPIRED(1006,"二维码已过期"),
|
||||
|
||||
/* =============== 主播相关 =============== */
|
||||
ANCHOR_ALREADY_EXISTS(2001, "主播已存在"),
|
||||
ANCHOR_HAS_PKRECORD(2002, "主播存在PK记录"),
|
||||
|
||||
/* =============== 微信小程序 =============== */
|
||||
WX_API_CALL_TOO_FREQUENT(45011, "API 调用太频繁,请稍候再试"),
|
||||
WX_INVALID_JSCODE(40029, "js_code 无效"),
|
||||
WX_RISK_ACCOUNT(40226, "该账号为风险用户,禁止登录小程序"),
|
||||
WX_SYSTEM_BUSY(-1, "系统繁忙"),
|
||||
|
||||
/* =============== 登录/用户信息 =============== */
|
||||
WX_GET_USER_INFO_FAILED(50001, "获取用户信息失败,请稍后再试"),
|
||||
USER_DOES_NOT_EXIST(5002,"用户不存在"),
|
||||
MAIL_ALREADY_EXIST(5003,"邮箱已存在"),
|
||||
USERNAME_ALREADY_EXIST(5006,"用户名已存在"),
|
||||
PASSWORD_ERROR(5004, "用户名或密码错误" ),
|
||||
USER_MAIL_NOT_VERIFICATION(5005,"用户邮未验证"),
|
||||
TOKEN_INVALID(40400, "Token无效,请重新登录"),
|
||||
|
||||
USER_HAS_ACTIVATED(5005,"用户已激活" );
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
ErrorCode(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package vvpkassistant.FunctionConfig;
|
||||
package vvpkassistant.config;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import vvpkassistant.FunctionConfig.mapper.FunctionConfigMapper;
|
||||
import vvpkassistant.FunctionConfig.model.FunctionConfigModel;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
@@ -12,7 +13,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@RequiredArgsConstructor
|
||||
public class FunctionConfigHolder {
|
||||
// 线程安全的全局配置容器
|
||||
static final List<FunctionConfigModel> CONFIGS = new CopyOnWriteArrayList<>();
|
||||
public static final List<FunctionConfigModel> CONFIGS = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Autowired
|
||||
private FunctionConfigMapper configMapper;
|
||||
86
src/main/java/vvpkassistant/config/SaTokenConfigure.java
Normal file
86
src/main/java/vvpkassistant/config/SaTokenConfigure.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package vvpkassistant.config;
|
||||
|
||||
import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaHttpMethod;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册Sa-Token的拦截器
|
||||
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(getExcludePaths());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要放行的路径
|
||||
*/
|
||||
private String[] getExcludePaths() {
|
||||
return new String[]{
|
||||
// Swagger & Knife4j 相关
|
||||
"/error",
|
||||
"/doc.html",
|
||||
"/webjars/**",
|
||||
"/swagger-resources/**",
|
||||
"/v2/api-docs",
|
||||
"/v3/api-docs",
|
||||
"/v3/api-docs/**",
|
||||
"/swagger-ui.html",
|
||||
"/swagger-ui/**",
|
||||
"/favicon.ico",
|
||||
// 你的其他放行路径,例如登录接口
|
||||
"/user/loginWithPhoneNumber",
|
||||
"/user/registerWithMail",
|
||||
"/user/loginWithMail",
|
||||
"/user/inputUserInfo",
|
||||
"/user/verificationMail",
|
||||
"/user/activate",
|
||||
"/user/qrcode",
|
||||
"/user/check/**",
|
||||
"/user/scan",
|
||||
"/user/confirm",
|
||||
"/user/checkUserName",
|
||||
"/user/verification",
|
||||
"/user/forgetMail",
|
||||
"/user/loginWithPhoneNumber",
|
||||
"/user/inputUserInfo",
|
||||
"/user/resetPassword",
|
||||
"/pk/pkList",
|
||||
"/systemMessage/list"
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SaCorsHandleFunction corsHandle() {
|
||||
return (req, res, sto) -> {
|
||||
res.
|
||||
// 允许指定域访问跨域资源
|
||||
setHeader("Access-Control-Allow-Origin", "*")
|
||||
// 允许所有请求方式
|
||||
.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
||||
// 有效时间
|
||||
.setHeader("Access-Control-Max-Age", "3600")
|
||||
// 允许的header参数
|
||||
.setHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
// 如果是预检请求,则立即返回到前端
|
||||
SaRouter.match(SaHttpMethod.OPTIONS)
|
||||
.back();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package vvpkassistant.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import vvpkassistant.Anchors.model.AnchorModel;
|
||||
import vvpkassistant.Anchors.service.AnchorsService;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("anchor")
|
||||
public class AnchorsController {
|
||||
|
||||
@Resource
|
||||
private AnchorsService anchorsService;
|
||||
|
||||
|
||||
// 添加新主播
|
||||
@PostMapping("add")
|
||||
public ResponseData<Object> addNewAnchor(@RequestBody AnchorModel model) {
|
||||
return anchorsService.addNewAnchor(model) == 1 ? ResponseData.success("") : ResponseData.error(ErrorCode.ADD_FAILED);
|
||||
}
|
||||
|
||||
// 查询我的主播列表
|
||||
@PostMapping("list")
|
||||
public ResponseData<Object> myAnchorList(@RequestBody Map<String,Integer> map) {
|
||||
Integer userId = map.get("id");
|
||||
return ResponseData.success(anchorsService.selectMyAnchor(userId));
|
||||
}
|
||||
|
||||
// 删除我的主播
|
||||
@PostMapping("deleteMyAnchor")
|
||||
public ResponseData<Object> deleteMyAnchor(@RequestBody Map<String,Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
return anchorsService.deleteMyAnchor(id) == 1 ? ResponseData.success(""):ResponseData.error(ErrorCode.DELETE_FAILED );
|
||||
}
|
||||
|
||||
// 更新主播信息
|
||||
@PostMapping("updateAnchorInfo")
|
||||
public ResponseData<Object> updateAnchorInfo(@RequestBody AnchorModel model) {
|
||||
|
||||
return anchorsService.updateAnchorInfo(model) == 1 ? ResponseData.success(""):ResponseData.error(ErrorCode.UPDATE_FAILED);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package vvpkassistant.chat;
|
||||
package vvpkassistant.controller;
|
||||
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.chat.mapper.ChatDao;
|
||||
import vvpkassistant.chat.model.ChatModel;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -20,7 +22,7 @@ public class ChatController {
|
||||
@PostMapping("add")
|
||||
public ResponseData<Object> add(@RequestBody ChatModel model) {
|
||||
int insert = chatDao.insert(model);
|
||||
return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
return insert == 1 ? ResponseData.success("") : ResponseData.error(ErrorCode.ADD_FAILED);
|
||||
}
|
||||
|
||||
//根据ip查询数据
|
||||
31
src/main/java/vvpkassistant/controller/FileController.java
Normal file
31
src/main/java/vvpkassistant/controller/FileController.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package vvpkassistant.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.file.service.FileService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/7 13:58
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("file")
|
||||
public class FileController {
|
||||
|
||||
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
|
||||
|
||||
@PostMapping("/uploadHeadIcon")
|
||||
public ResponseData<Object> uploadHeadIcon(@RequestParam("file") MultipartFile file) {
|
||||
return ResponseData.success(fileService.uploadHeadIcon(file));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,15 @@
|
||||
package vvpkassistant.FunctionConfig;
|
||||
package vvpkassistant.controller;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.FunctionConfig.mapper.FunctionConfigMapper;
|
||||
import vvpkassistant.FunctionConfig.model.FunctionConfigModel;
|
||||
import vvpkassistant.FunctionConfig.service.FunctionConfigService;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.config.FunctionConfigHolder;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("config")
|
||||
@@ -11,6 +18,9 @@ public class FunctionConfigController {
|
||||
@Autowired
|
||||
private FunctionConfigMapper configMapper;
|
||||
|
||||
@Resource
|
||||
private FunctionConfigService functionConfigService;
|
||||
|
||||
// 获取所有配置
|
||||
@GetMapping("getAllConfig")
|
||||
public ResponseData<Object> getAllConfig() {
|
||||
@@ -21,7 +31,7 @@ public class FunctionConfigController {
|
||||
@PostMapping("updateConfigValue")
|
||||
public ResponseData<Object> updateConfigValue(@RequestBody FunctionConfigModel model) {
|
||||
// 1. 更新数据库
|
||||
configMapper.updateById(model);
|
||||
functionConfigService.updateById(model);
|
||||
// 2. 更新内存
|
||||
FunctionConfigHolder.CONFIGS.removeIf(c -> model.getFunctionName().equals(c.getFunctionName()));
|
||||
FunctionConfigHolder.CONFIGS.add(model);
|
||||
@@ -34,9 +44,9 @@ public class FunctionConfigController {
|
||||
boolean isDuplicate = FunctionConfigHolder.CONFIGS.stream()
|
||||
.anyMatch(config -> name.equals(config.getFunctionName()));
|
||||
if (isDuplicate) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"配置名称重复");
|
||||
throw new BusinessException(ErrorCode.CONFIG_NAME_DUPLICATE);
|
||||
}else {
|
||||
configMapper.insert(newModel);
|
||||
functionConfigService.save(newModel);
|
||||
FunctionConfigHolder.CONFIGS.add(newModel);
|
||||
return ResponseData.success("");
|
||||
}
|
||||
@@ -44,12 +54,11 @@ public class FunctionConfigController {
|
||||
|
||||
@PostMapping("deleteConfigById")
|
||||
public ResponseData<Object> deleteConfigById(@RequestBody FunctionConfigModel model) {
|
||||
int i = configMapper.deleteById(model);
|
||||
if (i == 1) {
|
||||
if (functionConfigService.removeById(model)) {
|
||||
FunctionConfigHolder.CONFIGS.removeIf(c -> model.getId().equals(c.getId()));
|
||||
return ResponseData.success("");
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,null);
|
||||
throw new BusinessException(ErrorCode.DELETE_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
26
src/main/java/vvpkassistant/controller/OTPController.java
Normal file
26
src/main/java/vvpkassistant/controller/OTPController.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package vvpkassistant.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.OTP.model.OTPDTO;
|
||||
import vvpkassistant.OTP.service.OTPService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/14 20:50
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("otp")
|
||||
public class OTPController {
|
||||
|
||||
|
||||
@Resource
|
||||
private OTPService otpService;
|
||||
|
||||
@GetMapping("/getotp")
|
||||
public ResponseData<Object> getOTP() {
|
||||
return ResponseData.success(otpService.getOTP());
|
||||
}
|
||||
}
|
||||
160
src/main/java/vvpkassistant/controller/PkController.java
Normal file
160
src/main/java/vvpkassistant/controller/PkController.java
Normal file
@@ -0,0 +1,160 @@
|
||||
package vvpkassistant.controller;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.CoinRecords.CoinRecordsDao;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.pk.mapper.PkInfoDao;
|
||||
import vvpkassistant.pk.mapper.PkRecordDao;
|
||||
import vvpkassistant.pk.mapper.PkRecordDetailDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
import vvpkassistant.pk.model.PkRecord;
|
||||
import vvpkassistant.pk.model.PkRecordDetail;
|
||||
import vvpkassistant.pk.service.PKService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("pk")
|
||||
public class PkController {
|
||||
|
||||
@Resource
|
||||
private PKService pkService;
|
||||
|
||||
@Autowired
|
||||
private PkInfoDao pkDao;
|
||||
|
||||
@Autowired
|
||||
private PkRecordDao recordDao;
|
||||
|
||||
@Autowired
|
||||
private PkRecordDetailDao detailDao;
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
@Autowired
|
||||
private CoinRecordsDao coinRecordsDao;
|
||||
|
||||
// 创建pk数据
|
||||
@PostMapping("addPkData")
|
||||
public ResponseData<PkInfoModel> addPkData(@RequestBody PkInfoModel pkModel) {
|
||||
return ResponseData.success(pkService.addPkAddData(pkModel));
|
||||
}
|
||||
|
||||
// 更新pk信息
|
||||
@PostMapping("updatePkStatus")
|
||||
public ResponseData<Object> updatePkStatus(@RequestBody PkRecord recordModel) {
|
||||
return ResponseData.success(pkService.updatePkStatus(recordModel));
|
||||
}
|
||||
|
||||
// 创建PK记录
|
||||
@PostMapping("createPkRecord")
|
||||
public ResponseData<Object> createPkRecord(@RequestBody PkRecord record) {
|
||||
return ResponseData.success(pkService.createPKRecord(record));
|
||||
}
|
||||
|
||||
// pk列表
|
||||
@PostMapping("pkList")
|
||||
public ResponseData<Object> pkList(@RequestBody Map<String,Object> map) {
|
||||
return ResponseData.success(pkService.getPKList(map));
|
||||
}
|
||||
|
||||
// 查询用户发布的大于当前时间的pk数据
|
||||
@PostMapping("queryMyCanUsePkData")
|
||||
public ResponseData<Object> queryMyCanUsePkData(@RequestBody Map<String,Object> map) {
|
||||
Long time = VVTools.currentTimeStamp();
|
||||
Integer userId = (Integer) map.get("userId");
|
||||
List<PkInfoModel> pkModels = pkDao.queryCanUseData(userId, time);
|
||||
return ResponseData.success(pkModels);
|
||||
}
|
||||
|
||||
//pk文章详情
|
||||
@PostMapping("pkInfoDetail")
|
||||
public ResponseData<Object> pkInfoDetail(@RequestBody Map<String, Integer> map) {
|
||||
return ResponseData.success(pkService.pkInfoDetail(map));
|
||||
}
|
||||
|
||||
//删除自己的pk数据 (单个)
|
||||
@PostMapping("deletePkDataWithId")
|
||||
public ResponseData<Object> deletePkDataWithId(@RequestBody Map<String,Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
PkInfoModel pkInfoModel = pkDao.selectById(id);
|
||||
|
||||
if (pkInfoModel.getPinExpireTime() > VVTools.currentTimeStamp()) {
|
||||
return ResponseData.error(ResponseInfo.ERROR.getCode(),"该信息在置顶中。如要删除清先取消置顶");
|
||||
}
|
||||
|
||||
Integer result = pkDao.deletePkDataWithId(id);
|
||||
return result == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR.getCode(),"删除数据失败");
|
||||
}
|
||||
|
||||
//修改pk信息内容
|
||||
@PostMapping("updatePkInfoById")
|
||||
public ResponseData<Object> updatePkInfoById(@RequestBody PkInfoModel infoModel) {
|
||||
int result = pkDao.updateById(infoModel);
|
||||
return result == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR.getCode(),null);
|
||||
}
|
||||
|
||||
// 根据id查询pk记录
|
||||
@PostMapping("singleRecord")
|
||||
public ResponseData<Object> singleRecord(@RequestBody PkRecord record) {
|
||||
PkRecord data = recordDao.singleRecord(record.getId());
|
||||
return ResponseData.success(data);
|
||||
}
|
||||
|
||||
// 查询pk中每个场次的详细数据
|
||||
@PostMapping("fetchDetailPkDataWithId")
|
||||
public ResponseData<Object> fetchDetailPkDataWithId(@RequestBody Map<String,Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
List<PkRecordDetail> pkRecordDetails = recordDao.fetchDetailPkDataWithId(id);
|
||||
return ResponseData.success(pkRecordDetails);
|
||||
}
|
||||
|
||||
// 根据用户id查询该用户已发布的未被邀请的主播列表
|
||||
@PostMapping("listUninvitedPublishedAnchorsByUserId")
|
||||
public ResponseData<Object> listUninvitedPublishedAnchorsByUserId(@RequestBody Map<String,Integer> map) {
|
||||
Integer userId = map.get("userId");
|
||||
List<PkInfoModel> pkInfoModels = pkDao.listUninvitedPublishedAnchorsByUserId(userId);
|
||||
for (PkInfoModel pkInfoModel : pkInfoModels) {
|
||||
pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(),'*'));
|
||||
}
|
||||
return ResponseData.success(pkInfoModels);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************************************************/
|
||||
/** Python 相关接口 */
|
||||
/************************************************************************************************************************************/
|
||||
// Python那边需要的pk数据
|
||||
@PostMapping("pkListForPython")
|
||||
public ResponseData<Object> pkDataListForPython() {
|
||||
// 获取当日的开始时间和结束时间
|
||||
Map<String, Long> timeMap = VVTools.startAndEndTimeStampForToday();
|
||||
long start = timeMap.get("start");
|
||||
long end = timeMap.get("end");
|
||||
List<PkRecord> result = recordDao.pkListForToday(start, end);
|
||||
return ResponseData.success(result);
|
||||
}
|
||||
|
||||
// 更新pk结果信息
|
||||
@PostMapping("updatePkRecordInfo")
|
||||
public ResponseData<Object> updatePkRecordInfo(@RequestBody PkRecord record) {
|
||||
int i = recordDao.updateById(record);
|
||||
return i == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR.getCode(),null);
|
||||
}
|
||||
|
||||
// 插入pk明细表数据
|
||||
@PostMapping("insertPkDetail")
|
||||
public ResponseData<Object> insert(@RequestBody PkRecordDetail detail) {
|
||||
detail.setCreateTime(VVTools.currentTimeStamp());
|
||||
int insert = detailDao.insert(detail);
|
||||
return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR.getCode(),null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.SystemMessage;
|
||||
package vvpkassistant.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -6,6 +6,8 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.SystemMessage.mapper.SystemMessageDao;
|
||||
import vvpkassistant.SystemMessage.model.SystemMessage;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
|
||||
import java.util.List;
|
||||
@@ -1,4 +1,6 @@
|
||||
package vvpkassistant.User;
|
||||
package vvpkassistant.controller;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.CoinRecords.CoinRecords;
|
||||
@@ -6,13 +8,25 @@ import vvpkassistant.CoinRecords.CoinRecordsDao;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
import vvpkassistant.FunctionConfig.FunctionConfigHolder;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.DTO.ScanInfoDTO;
|
||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.User.model.UserModelVO;
|
||||
import vvpkassistant.User.service.UserService;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.config.FunctionConfigHolder;
|
||||
import vvpkassistant.Tools.VVRequester;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.pk.PkInfoDao;
|
||||
import vvpkassistant.pk.PkInfoModel;
|
||||
import vvpkassistant.pk.PkRecordDetail;
|
||||
import vvpkassistant.pk.PkRecordDetailDao;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
import vvpkassistant.mail.service.MailService;
|
||||
import vvpkassistant.pk.mapper.PkInfoDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
import vvpkassistant.pk.model.PkRecordDetail;
|
||||
import vvpkassistant.pk.mapper.PkRecordDetailDao;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -39,16 +53,23 @@ public class UserController {
|
||||
@Autowired
|
||||
private VVRequester vvRequester;
|
||||
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@Resource
|
||||
private MailService mailService;
|
||||
|
||||
// 配置用户信息
|
||||
@PostMapping("inputUserInfo")
|
||||
public ResponseData<Object> inputUserInfo(@RequestBody Map<String,Object> param) {
|
||||
|
||||
if (!param.containsKey("code")) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "code不能为空");
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"code不能为空");
|
||||
}
|
||||
|
||||
if (!param.containsKey("id")) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "id不能为空");
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"id不能为空");
|
||||
}
|
||||
|
||||
//获取前端传递过来的code
|
||||
@@ -62,23 +83,23 @@ public class UserController {
|
||||
Integer errcode = Integer.valueOf(wx_result.get("errcode").toString());
|
||||
|
||||
if (errcode == 45011) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "API 调用太频繁,请稍候再试。");
|
||||
throw new BusinessException(ErrorCode.WX_API_CALL_TOO_FREQUENT);
|
||||
}
|
||||
|
||||
if (errcode == 40029) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "js_code 无效");
|
||||
throw new BusinessException(ErrorCode.WX_INVALID_JSCODE);
|
||||
}
|
||||
|
||||
if (errcode == 40226) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "该账号为风险用户。禁止登录小程序");
|
||||
throw new BusinessException(ErrorCode.WX_RISK_ACCOUNT);
|
||||
}
|
||||
|
||||
if (errcode == -1) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "系统繁忙");
|
||||
throw new BusinessException(ErrorCode.WX_SYSTEM_BUSY);
|
||||
}
|
||||
|
||||
if (!wx_result.containsKey("openid")) {
|
||||
return ResponseData.error(ResponseInfo.ERROR, "获取用户信息失败,请稍后再试。");
|
||||
throw new BusinessException(ErrorCode.WX_GET_USER_INFO_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,13 +124,15 @@ public class UserController {
|
||||
// return ResponseData.error(ResponseInfo.ERROR,"创建聊天账号失败,请稍后再试");
|
||||
// }
|
||||
Map<String,Object> result = new HashMap<>();
|
||||
result.put("info", tempModel);
|
||||
StpUtil.login(tempModel.getId());
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(tempModel, UserModelVO.class);
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
result.put("info", userModelVO);
|
||||
result.put("newAccount",false);
|
||||
//否则直接返回用户
|
||||
return ResponseData.success(result);
|
||||
}
|
||||
|
||||
return ResponseData.error(ResponseInfo.ERROR,"未知错误");
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
// 手机号登录 / 注册
|
||||
@@ -117,21 +140,23 @@ public class UserController {
|
||||
public ResponseData<Object> loginWithPhoneNumber(@RequestBody Map<String,Object> param) {
|
||||
|
||||
if (!param.containsKey("code")) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"code不能为空");
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"code不能为空");
|
||||
}
|
||||
|
||||
String code = param.get("code").toString();
|
||||
String phoneNumber = vvRequester.queryPhoneNumber(code);
|
||||
|
||||
if (phoneNumber.isEmpty()) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"手机号码无法查询");
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"手机号码无法查询");
|
||||
}
|
||||
|
||||
// 查询是否存在用户。如果用户存在直接返回 如果用户不存在则新建用户
|
||||
UserModel model = userDao.queryWithPhoneNumber(phoneNumber);
|
||||
Map<String,Object> result = new HashMap<>();
|
||||
if (model != null) { // 老用户
|
||||
result.put("info",model);
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(model, UserModelVO.class);
|
||||
StpUtil.login(userModelVO.getId());
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
result.put("info",userModelVO);
|
||||
result.put("newAccount", false);
|
||||
result.put("chatInfo",wxChatParam);
|
||||
return ResponseData.success(result);
|
||||
@@ -154,39 +179,40 @@ public class UserController {
|
||||
userDao.updateById(oldUser);
|
||||
}
|
||||
|
||||
result.put("info",tempModel);
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(tempModel, UserModelVO.class);
|
||||
StpUtil.login(userModelVO.getId());
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
result.put("info",userModelVO);
|
||||
result.put("newAccount",true);
|
||||
result.put("chatInfo",wxChatParam);
|
||||
|
||||
return ResponseData.success(result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 修改用户信息
|
||||
@PostMapping("updateUserInfo")
|
||||
public ResponseData<Object> updateUserInfo(@RequestBody Map<String,Object> map) {
|
||||
UserModel userModel = new UserModel();
|
||||
//设置用户id
|
||||
userModel.setId(Integer.valueOf(map.get("id").toString()));
|
||||
//设置用户头像
|
||||
userModel.setHeaderIcon(map.get("headerIcon").toString());
|
||||
//设置用户昵称
|
||||
userModel.setNickName(map.get("nickName").toString());
|
||||
|
||||
int i = userDao.updateById(userModel);
|
||||
// 返回结果
|
||||
Map<String,Object> result = new HashMap<>();
|
||||
result.put("info", userDao.selectById(map.get("id").toString()));
|
||||
result.put("newAccount", false);
|
||||
return i == 1 ? ResponseData.success(result) : ResponseData.error(ResponseInfo.ERROR, "");
|
||||
public ResponseData<Object> updateUserInfo(@RequestBody UserModelDTO userModelDTO) {
|
||||
UserModelVO userModelVO = userService.updateUserInfo( userModelDTO);
|
||||
return ResponseData.success(userModelVO);
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
@PostMapping("getUserInfo")
|
||||
public ResponseData<Object> getUserInfo(@RequestBody Map<String,Integer> map) {
|
||||
UserModel userModel = userDao.selectById(map.get("id"));
|
||||
return ResponseData.success(userModel);
|
||||
public ResponseData<Object> getUserInfo(@RequestBody UserModelDTO userModelDTO) {
|
||||
if (userModelDTO.getId() == null){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
UserModel userModel = userDao.selectById(userModelDTO.getId());
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
userModelVO.setHavaPassword(userModel.getPassword() != null);
|
||||
return ResponseData.success(userModelVO);
|
||||
}
|
||||
|
||||
// 查询用户所有pk数据
|
||||
@@ -219,7 +245,7 @@ public class UserController {
|
||||
// 别人邀请我的pk数据
|
||||
return ResponseData.success(userDao.getMyGuestPkList(id, page * size, size));
|
||||
}
|
||||
return ResponseData.error(ResponseInfo.ERROR,"未知错误");
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +263,7 @@ public class UserController {
|
||||
Integer userId = map.get("userId");
|
||||
int i = userDao.checkSignStatus(userId);
|
||||
if (i != 0) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"当天已签到");
|
||||
throw new BusinessException(ErrorCode.SIGN_IN_FAIL);
|
||||
}
|
||||
|
||||
int result = userDao.signIn(userId);
|
||||
@@ -256,7 +282,7 @@ public class UserController {
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
return ResponseData.success(null);
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,null);
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"签到失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,13 +329,13 @@ public class UserController {
|
||||
// 返回给前端数据
|
||||
return ResponseData.success(info);
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,null);
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,String.format("积分不足,需要%d积分",totalCoin));
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,String.format("积分不足,需要%d积分",totalCoin));
|
||||
}
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"用户不存在");
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"用户不存在");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +369,7 @@ public class UserController {
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
return ResponseData.success(String.format("操作成功,返还%d积分",totalCoin));
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,null);
|
||||
return ResponseData.error(ResponseInfo.ERROR.getCode(),null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -359,5 +385,101 @@ public class UserController {
|
||||
return ResponseData.success(coinRecords);
|
||||
}
|
||||
|
||||
|
||||
// 邮件登录接口
|
||||
@PostMapping("/loginWithMail")
|
||||
public ResponseData<Object> loginWithMail(@RequestBody UserModelDTO model) {
|
||||
return ResponseData.success(userService.loginWithMail(model));
|
||||
}
|
||||
|
||||
//邮件注册接口
|
||||
@PostMapping("/registerWithMail")
|
||||
public ResponseData<Object> mailRegister(@RequestBody UserModelDTO model){
|
||||
return ResponseData.success(userService.addUserWithMail(model));
|
||||
}
|
||||
|
||||
// 用户邮件激活
|
||||
@GetMapping("/activate")
|
||||
public ResponseData<Object> activateAccount(@RequestParam("token") String token){
|
||||
return ResponseData.success(userService.activateAccount(token));
|
||||
}
|
||||
|
||||
// 重发邮件接口
|
||||
@PostMapping("/resendMail")
|
||||
public ResponseData<Object> resendMail(@RequestBody MailModel mailModel){
|
||||
return ResponseData.success(mailService.resendMail(mailModel));
|
||||
}
|
||||
|
||||
// 验证邮箱链接
|
||||
@GetMapping("/verificationMail")
|
||||
public ResponseData<Object> verificationMail(@RequestParam("token") String token){
|
||||
return ResponseData.success(userService.verificationMail(token));
|
||||
}
|
||||
|
||||
// 发送忘记密码邮件
|
||||
@PostMapping("/forgetMail")
|
||||
public ResponseData<Object> sendForgetPassWordMail(@RequestBody MailModel mailModel){
|
||||
return ResponseData.success(userService.sendForgetPassWordMail(mailModel));
|
||||
}
|
||||
|
||||
// 生成二维码登录接口
|
||||
@GetMapping("/qrcode")
|
||||
public ResponseData<Object> generatedQrcode(){
|
||||
return ResponseData.success(userService.generatedQrcode());
|
||||
}
|
||||
|
||||
// 检查二维码状态接口
|
||||
@GetMapping("/check/{uuid}")
|
||||
public ResponseData<Object> checkQrcode(@PathVariable String uuid){
|
||||
return ResponseData.success(userService.checkQrcode(uuid));
|
||||
}
|
||||
|
||||
// 二维码扫描状态
|
||||
@PostMapping("/scan")
|
||||
public ResponseData<?> scanQrCode(@RequestBody ScanInfoDTO scanInfoDTO) {
|
||||
return ResponseData.success( userService.scanQrcode(scanInfoDTO));
|
||||
}
|
||||
|
||||
//二维码扫描确认
|
||||
@PostMapping("/confirm")
|
||||
public ResponseData<?> confirm(@RequestBody ScanInfoDTO scanInfoDTO) {
|
||||
userService.confirm(scanInfoDTO);
|
||||
return ResponseData.success("");
|
||||
}
|
||||
|
||||
// 注销接口
|
||||
@PostMapping("/logout")
|
||||
public ResponseData<Object> logOut(@RequestBody UserModelDTO userModelDTO){
|
||||
userService.logOut(userModelDTO.getId());
|
||||
return ResponseData.success("");
|
||||
}
|
||||
|
||||
// 设置密码接口
|
||||
@PostMapping("/setPassword")
|
||||
public ResponseData<Object>setPassWord(@RequestBody UserModelDTO userModelDTO){
|
||||
return ResponseData.success(userService.setPassWord(userModelDTO));
|
||||
}
|
||||
|
||||
// 用户通过邮件验证链接重设密码接口
|
||||
@PostMapping("/resetPassword")
|
||||
public ResponseData<Object>resetPassWord(@RequestBody UserModelDTO userModelDTO){
|
||||
return ResponseData.success(userService.resetPassWord(userModelDTO));
|
||||
}
|
||||
|
||||
// 设置新邮箱接口
|
||||
@PostMapping("/updateUserMail")
|
||||
public ResponseData<Object>updateUserMail(@RequestBody MailModel mailModel){
|
||||
return ResponseData.success(userService.updateUserMail(mailModel));
|
||||
}
|
||||
|
||||
// 发送更新邮箱验证邮件接口
|
||||
@PostMapping("/sendUpdateMailConfirmMail")
|
||||
public ResponseData<Object>sendUpdateMailConfirmMail(@RequestBody MailModel mailModel){
|
||||
return ResponseData.success(mailService.sendUpdateConfirmMail(mailModel));
|
||||
}
|
||||
|
||||
// 检查重复用户名接口
|
||||
@PostMapping("/checkUserName")
|
||||
public ResponseData<Boolean>checkUserName(@RequestBody UserModelDTO userModelDTO){
|
||||
return ResponseData.success(userService.checkUserName(userModelDTO));
|
||||
}
|
||||
}
|
||||
32
src/main/java/vvpkassistant/exception/BusinessException.java
Normal file
32
src/main/java/vvpkassistant/exception/BusinessException.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package vvpkassistant.exception;
|
||||
|
||||
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
|
||||
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
public BusinessException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode) {
|
||||
super(errorCode.getMessage());
|
||||
this.code = errorCode.getCode();
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode, String message) {
|
||||
super(message);
|
||||
this.code = errorCode.getCode();
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package vvpkassistant.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*
|
||||
* @author <a href="https://github.com/liyupi">程序员鱼皮</a>
|
||||
* @from <a href="https://yupi.icu">编程导航知识星球</a>
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public ResponseData<?> businessExceptionHandler(BusinessException e) {
|
||||
log.error("BusinessException", e);
|
||||
return ResponseData.error(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseData<?> runtimeExceptionHandler(RuntimeException e) {
|
||||
log.error("RuntimeException", e);
|
||||
return ResponseData.error(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
// 全局异常拦截(拦截项目中的NotLoginException异常)
|
||||
@ExceptionHandler(NotLoginException.class)
|
||||
public ResponseData<?> handlerNotLoginException(NotLoginException nle)
|
||||
throws Exception {
|
||||
|
||||
// 打印堆栈,以供调试
|
||||
nle.printStackTrace();
|
||||
|
||||
// 判断场景值,定制化异常信息
|
||||
String message = "";
|
||||
if(nle.getType().equals(NotLoginException.NOT_TOKEN)) {
|
||||
message = "未能读取到有效用户令牌";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
|
||||
message = "令牌无效";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
|
||||
message = "令牌已过期";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.BE_REPLACED)) {
|
||||
message = "令牌已被顶下线";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.KICK_OUT)) {
|
||||
message = "令牌已被踢下线";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.TOKEN_FREEZE)) {
|
||||
message = "令牌已被冻结";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.NO_PREFIX)) {
|
||||
message = "未按照指定前缀提交令牌";
|
||||
}
|
||||
else {
|
||||
message = "当前会话未登录";
|
||||
}
|
||||
|
||||
// 返回给前端
|
||||
return ResponseData.error(ErrorCode.TOKEN_INVALID.getCode(),message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
46
src/main/java/vvpkassistant/exception/ThrowUtils.java
Normal file
46
src/main/java/vvpkassistant/exception/ThrowUtils.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package vvpkassistant.exception;
|
||||
|
||||
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
|
||||
/**
|
||||
* 抛异常工具类
|
||||
*
|
||||
* @author <a href="https://github.com/liyupi">程序员鱼皮</a>
|
||||
* @from <a href="https://yupi.icu">编程导航知识星球</a>
|
||||
*/
|
||||
public class ThrowUtils {
|
||||
|
||||
/**
|
||||
* 条件成立则抛异常
|
||||
*
|
||||
* @param condition
|
||||
* @param runtimeException
|
||||
*/
|
||||
public static void throwIf(boolean condition, RuntimeException runtimeException) {
|
||||
if (condition) {
|
||||
throw runtimeException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件成立则抛异常
|
||||
*
|
||||
* @param condition
|
||||
* @param errorCode
|
||||
*/
|
||||
public static void throwIf(boolean condition, ErrorCode errorCode) {
|
||||
throwIf(condition, new BusinessException(errorCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件成立则抛异常
|
||||
*
|
||||
* @param condition
|
||||
* @param errorCode
|
||||
* @param message
|
||||
*/
|
||||
public static void throwIf(boolean condition, ErrorCode errorCode, String message) {
|
||||
throwIf(condition, new BusinessException(errorCode, message));
|
||||
}
|
||||
}
|
||||
11
src/main/java/vvpkassistant/file/service/FileService.java
Normal file
11
src/main/java/vvpkassistant/file/service/FileService.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package vvpkassistant.file.service;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/7 13:58
|
||||
*/
|
||||
public interface FileService {
|
||||
Object uploadHeadIcon(MultipartFile file);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package vvpkassistant.file.service;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/7 13:58
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FileServiceImpl implements FileService {
|
||||
|
||||
@Resource
|
||||
private FileStorageService fileStorageService;//注入实列
|
||||
|
||||
@Override
|
||||
public Object uploadHeadIcon(MultipartFile file) {
|
||||
// 生成 UUID 文件名,保留原扩展名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String extension = originalFilename != null && originalFilename.contains(".")
|
||||
? originalFilename.substring(originalFilename.lastIndexOf("."))
|
||||
: "";
|
||||
String uuidFileName = UUID.randomUUID().toString().replace("-", "") + extension;
|
||||
|
||||
// 使用 fileStorageService 进行上传
|
||||
// 设置保存的文件名为 UUID
|
||||
|
||||
// 返回文件信息或 URL
|
||||
|
||||
log.info("Uploading head icon to file: {}", uuidFileName);
|
||||
return fileStorageService.of(file)
|
||||
.setSaveFilename(uuidFileName) // 设置保存的文件名为 UUID
|
||||
.upload();
|
||||
}
|
||||
}
|
||||
15
src/main/java/vvpkassistant/mail/model/MailModel.java
Normal file
15
src/main/java/vvpkassistant/mail/model/MailModel.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package vvpkassistant.mail.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 15:48
|
||||
*/
|
||||
@Data
|
||||
public class MailModel {
|
||||
private String mailAddress;
|
||||
private Integer userId;
|
||||
private Integer type;
|
||||
private String code;
|
||||
}
|
||||
20
src/main/java/vvpkassistant/mail/service/MailService.java
Normal file
20
src/main/java/vvpkassistant/mail/service/MailService.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package vvpkassistant.mail.service;
|
||||
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 15:42
|
||||
*/
|
||||
public interface MailService {
|
||||
|
||||
void sendMail(String emailAddress,Integer userId);
|
||||
|
||||
void sendVerificationMail(String emailAddress,Integer userId);
|
||||
|
||||
Boolean resendMail(MailModel mailModel);
|
||||
|
||||
void sendForgetPassWordMail(String mailAddress, Integer id);
|
||||
|
||||
Object sendUpdateConfirmMail(MailModel mailModel);
|
||||
}
|
||||
635
src/main/java/vvpkassistant/mail/service/MailServiceImpl.java
Normal file
635
src/main/java/vvpkassistant/mail/service/MailServiceImpl.java
Normal file
@@ -0,0 +1,635 @@
|
||||
package vvpkassistant.mail.service;
|
||||
|
||||
import cn.dev33.satoken.temp.SaTempUtil;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.Tools.CacheHolder;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 15:42
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MailServiceImpl implements MailService {
|
||||
|
||||
|
||||
@Value("${activateUrl}")
|
||||
private String activateUrl;
|
||||
|
||||
@Value("${verificationMailUrl}")
|
||||
private String verificationMailUrl;
|
||||
|
||||
@Value("${forgetPassWordUrl}")
|
||||
private String forgetPassWordUrl;
|
||||
|
||||
|
||||
@Resource
|
||||
private UserDao userDao;
|
||||
|
||||
|
||||
private static final Cache<String, Object> emailSendCache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
|
||||
@Override
|
||||
@Async("taskExecutor")
|
||||
public void sendMail(String emailAddress,Integer userId) {
|
||||
log.info("Sending email to {}", emailAddress);
|
||||
String token = SaTempUtil.createToken(userId, 600);
|
||||
if (emailSendCache.getIfPresent(emailAddress) != null) {
|
||||
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||
}
|
||||
ThreadUtil.execute(() -> {
|
||||
try {
|
||||
MailUtil.send(emailAddress, "激活你的账号", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Account Activation</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to activate your account</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ activateUrl+ token + "\" class=\"activate-button\">\n" +
|
||||
" Activate Account\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 24 hours<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
log.info("账号激活邮件发送成功,邮箱地址:{},用户 Id:{}", emailAddress,userId);
|
||||
} catch (Exception e) {
|
||||
log.error("账号激活邮件发送失败,邮箱地址:{},用户 Id:{}",emailAddress,userId);
|
||||
}
|
||||
});
|
||||
emailSendCache.put(emailAddress, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendVerificationMail(String emailAddress, Integer userId) {
|
||||
log.info("Sending email to {}", emailAddress);
|
||||
String token = SaTempUtil.createToken(userId, 600);
|
||||
if (emailSendCache.getIfPresent(emailAddress) != null) {
|
||||
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||
}
|
||||
ThreadUtil.execAsync(() ->{
|
||||
try {
|
||||
MailUtil.send(emailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Verification Mail</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to verification your mail</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ verificationMailUrl+ token + "\" class=\"activate-button\">\n" +
|
||||
" Verification\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 10 minutes<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
log.info("邮箱验证发送成功,邮箱地址:{},用户 Id: {}",emailAddress,userId );
|
||||
}catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
log.error("邮箱验证发送失败,邮箱地址:{},用户 Id: {}",emailAddress,userId );
|
||||
}
|
||||
});
|
||||
|
||||
emailSendCache.put(emailAddress, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean resendMail(MailModel mailModel) {
|
||||
if (mailModel.getMailAddress() == null && mailModel.getType() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper.eq(UserModel::getEmail, mailModel.getMailAddress()));
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
Object ifPresent = emailSendCache.getIfPresent(mailModel.getMailAddress());
|
||||
if (ifPresent == null) {
|
||||
switch (mailModel.getType()) {
|
||||
case 1:
|
||||
sendMail(mailModel.getMailAddress(), userModel.getId());
|
||||
break;
|
||||
case 2:
|
||||
sendVerificationMail(mailModel.getMailAddress(), userModel.getId());
|
||||
break;
|
||||
case 3:
|
||||
sendForgetPassWordMail(mailModel.getMailAddress(), userModel.getId());
|
||||
break;
|
||||
case 4:
|
||||
sendUpdateConfirmMail(mailModel);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendForgetPassWordMail(String mailAddress, Integer userId) {
|
||||
if (checkCache(mailAddress)){
|
||||
String token = SaTempUtil.createToken(userId, 600);
|
||||
ThreadUtil.execAsync(() ->{
|
||||
try {
|
||||
MailUtil.send(mailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Verification Mail</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to reset your password</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ forgetPassWordUrl + token + "\" class=\"activate-button\">\n" +
|
||||
" Reset PassWord\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 10 minutes<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
log.info("找回密码邮件发送成功,邮箱地址:{},用户 Id:{}", mailAddress,userId);
|
||||
}catch (Exception e) {
|
||||
log.error("找回密码邮件发送失败,邮箱地址:{},用户 Id:{}", mailAddress,userId);
|
||||
}
|
||||
});
|
||||
emailSendCache.put(mailAddress, userId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object sendUpdateConfirmMail(MailModel mailModel) {
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
UserModel userModel = userDao.selectOne(
|
||||
lambdaQueryWrapper.eq(UserModel::getEmail, mailModel.getMailAddress())
|
||||
.eq(UserModel::getStatus, 0)
|
||||
.eq(UserModel::getMailVerification, 0));
|
||||
if (userModel == null){
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
if (checkCache(mailModel.getMailAddress())) {
|
||||
String code = RandomUtil.randomString(6);
|
||||
emailSendCache.put(mailModel.getMailAddress(), code);
|
||||
CacheHolder.VERIFICATION_MAIL.put(code, mailModel.getMailAddress());
|
||||
ThreadUtil.execAsync(() -> {
|
||||
try {
|
||||
MailUtil.send(mailModel.getMailAddress(),"your Verification code is: " + code,
|
||||
"your Verification code is: " + code,false);
|
||||
log.info("邮箱:{},发送验证码:{}", mailModel.getMailAddress(),code);
|
||||
}catch (Exception e){
|
||||
log.error("发送邮件失败, address={}, code={}", mailModel.getMailAddress(), code, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public Boolean checkCache(String mailAddress){
|
||||
Object ifPresent = emailSendCache.getIfPresent(mailAddress);
|
||||
if (ifPresent == null) {
|
||||
return true;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
package vvpkassistant.pk;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.CoinRecords.CoinRecords;
|
||||
import vvpkassistant.CoinRecords.CoinRecordsDao;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.FunctionConfig.FunctionConfigHolder;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.User.UserDao;
|
||||
import vvpkassistant.User.UserModel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("pk")
|
||||
public class PkController {
|
||||
|
||||
@Autowired
|
||||
private PkInfoDao pkDao;
|
||||
|
||||
@Autowired
|
||||
private PkRecordDao recordDao;
|
||||
|
||||
@Autowired
|
||||
private PkRecordDetailDao detailDao;
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
@Autowired
|
||||
private CoinRecordsDao coinRecordsDao;
|
||||
|
||||
// 创建pk数据
|
||||
@PostMapping("addPkData")
|
||||
public ResponseData<Object> addPkData(@RequestBody PkInfoModel pkModel) {
|
||||
|
||||
// 初始可邀请状态为0
|
||||
pkModel.setInviteStatus(0);
|
||||
pkModel.setPinExpireTime(0);
|
||||
|
||||
// 获取主播id
|
||||
String anchorId = pkModel.getAnchorId();
|
||||
// 查询当天是否存在该主播发布的pk信息。
|
||||
Integer pkTime = pkModel.getPkTime();
|
||||
|
||||
// 根据设置的pk时间。查询出当天的开始时间和结束时间
|
||||
Map<String, Long> dayStartAndEndTimestamp = VVTools.getDayStartAndEndTimestamp(pkTime);
|
||||
|
||||
Long start = dayStartAndEndTimestamp.get("start");
|
||||
Long end = dayStartAndEndTimestamp.get("end");
|
||||
|
||||
// 查询主播在当天是否有发布过pk信息
|
||||
List<PkInfoModel> pkInfoModels = pkDao.selectDataWithAnchorIdAndTime(anchorId, start, end);
|
||||
|
||||
// 判断该主播在当日是否已发布过pk信息
|
||||
if (pkInfoModels.size() > 0) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"该主播当日已有pk信息");
|
||||
}
|
||||
|
||||
int insert = pkDao.insert(pkModel);
|
||||
return insert == 1 ? ResponseData.success(pkModel) : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
// 更新pk信息
|
||||
@PostMapping("updatePkStatus")
|
||||
public ResponseData<Object> updatePkStatus(@RequestBody PkRecord recordModel) {
|
||||
|
||||
//如果是同意了pk邀请、则更新已发布的主播pk可邀请状态
|
||||
if (recordModel.getPkStatus() == 1) {
|
||||
|
||||
// 查询出记录信息
|
||||
PkRecord pkRecordById = recordDao.singleRecord(recordModel.getId());
|
||||
|
||||
// 更新可邀请状态
|
||||
PkInfoModel pkInfoModelA = pkDao.selectById(pkRecordById.getPkIdA());
|
||||
pkInfoModelA.setInviteStatus(1);
|
||||
|
||||
PkInfoModel pkInfoModelB = pkDao.selectById(pkRecordById.getPkIdB());
|
||||
pkInfoModelB.setInviteStatus(1);
|
||||
|
||||
pkDao.updateById(pkInfoModelA);
|
||||
pkDao.updateById(pkInfoModelB);
|
||||
|
||||
// 如果有置顶的状态。需要取消置顶
|
||||
if (pkInfoModelA.getPinExpireTime() > VVTools.currentTimeStamp()) {
|
||||
long hour = VVTools.calculateHoursFloor(pkInfoModelA.getPinExpireTime(),VVTools.currentTimeStamp());
|
||||
int coin = Integer.parseInt(FunctionConfigHolder.getValue("置顶扣除积分"));
|
||||
int totalCoin = (int) (coin * hour);
|
||||
|
||||
// 插入记录
|
||||
CoinRecords coinRecords = new CoinRecords("成功预约pk,自动取消置顶", pkInfoModelA.getSenderId(),totalCoin, (int) VVTools.currentTimeStamp(),1);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
|
||||
// 更新积分
|
||||
UserModel userModel = userDao.selectById(pkRecordById.getUserIdA());
|
||||
Integer points = userModel.getPoints();
|
||||
userModel.setPoints(points + totalCoin);
|
||||
}
|
||||
|
||||
if (pkInfoModelB.getPinExpireTime() > VVTools.currentTimeStamp()) {
|
||||
long hour = VVTools.calculateHoursFloor(pkInfoModelB.getPinExpireTime(),VVTools.currentTimeStamp());
|
||||
int coin = Integer.parseInt(FunctionConfigHolder.getValue("置顶扣除积分"));
|
||||
int totalCoin = (int) (coin * hour);
|
||||
|
||||
// 插入记录
|
||||
CoinRecords coinRecords = new CoinRecords("成功预约pk,自动取消置顶", pkInfoModelB.getSenderId(),totalCoin, (int) VVTools.currentTimeStamp(),1);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
|
||||
// 更新积分
|
||||
UserModel userModel = userDao.selectById(pkRecordById.getUserIdB());
|
||||
Integer points = userModel.getPoints();
|
||||
userModel.setPoints(points + totalCoin);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新pk邀请记录
|
||||
int update = recordDao.updateById(recordModel);
|
||||
return update == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
// 创建PK记录
|
||||
@PostMapping("createPkRecord")
|
||||
public ResponseData<Object> createPkRecord(@RequestBody PkRecord record) {
|
||||
|
||||
// 如果这两个邀约直播之间存在未处理的邀请记录。那就不允许继续发送pk邀请
|
||||
String anchorIdA = record.getAnchorIdA();
|
||||
String anchorIdB = record.getAnchorIdB();
|
||||
Integer dataCount = recordDao.getPendingInvitations(anchorIdA, anchorIdB);
|
||||
|
||||
if (dataCount > 0) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"已存在一条未处理的pk申请,不能重复发送,");
|
||||
}
|
||||
|
||||
record.setPkStatus(0);
|
||||
int insert = recordDao.insert(record);
|
||||
return insert == 1 ? ResponseData.success(record) : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
// pk列表
|
||||
@PostMapping("pkList")
|
||||
public ResponseData<Object> pkList(@RequestBody Map<String,Object> map) {
|
||||
|
||||
Integer page = (Integer) map.get("page");
|
||||
Integer size = (Integer) map.get("size");
|
||||
Map<String,Object> condition = (Map<String, Object>) map.get("condition");
|
||||
|
||||
Map<String, Long> todayTimeStampMap = VVTools.startAndEndTimeStampForToday();
|
||||
Long start = VVTools.currentTimeStamp();
|
||||
Long end = todayTimeStampMap.get("end");
|
||||
|
||||
List<PkInfoModel> pkModels = pkDao.selectPkInfoByCondition(page * size, size, condition, start, end);
|
||||
|
||||
long currentTimeStamp = VVTools.currentTimeStamp();
|
||||
|
||||
//如果传了用户id
|
||||
if (map.containsKey("userId")) {
|
||||
Long begin = VVTools.currentTimeStamp();
|
||||
Integer userId = Integer.valueOf(map.get("userId").toString());
|
||||
// 查询出当前用户大于等于今天的已接受邀请的pk数据
|
||||
List<PkRecord> pkRecords = recordDao.fetchDataFromTodayWithUserId(userId, begin);
|
||||
// 遍历查询出的数据。如果文章的id相同。就显示完整的主播名称,
|
||||
for (PkInfoModel pkModel : pkModels) {
|
||||
pkModel.setDisPlayId(pkModel.getAnchorId());
|
||||
// 设置是否为置顶
|
||||
pkModel.setIsPin(pkModel.getPinExpireTime() > currentTimeStamp);
|
||||
// 如果文章的发布者不是当前登录主播。
|
||||
if (pkModel.getSenderId().intValue() != userId) {
|
||||
boolean showId = false;
|
||||
// 查找是否和当前登录的账号有pk关系。
|
||||
for (PkRecord pkRecord : pkRecords) {
|
||||
// 如果当前用户是邀请pk的,并且对方已接受pk,也可以看到主播id
|
||||
if (pkRecord.getUserIdB().intValue() == userId &&
|
||||
pkRecord.getPkIdA().intValue() == pkModel.getId().intValue() &&
|
||||
pkRecord.getPkStatus() == 1) {
|
||||
showId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 条件不满足则隐藏主播id'
|
||||
if (!showId) {
|
||||
pkModel.setDisPlayId(VVTools.replaceChar(pkModel.getAnchorId(), '*'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for (PkInfoModel pkModel : pkModels) {
|
||||
// 设置是否为置顶
|
||||
pkModel.setIsPin(pkModel.getPinExpireTime() > currentTimeStamp);
|
||||
pkModel.setDisPlayId(VVTools.replaceChar(pkModel.getAnchorId(), '*'));
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseData.success(pkModels);
|
||||
}
|
||||
|
||||
// 查询用户发布的大于当前时间的pk数据
|
||||
@PostMapping("queryMyCanUsePkData")
|
||||
public ResponseData<Object> queryMyCanUsePkData(@RequestBody Map<String,Object> map) {
|
||||
Long time = VVTools.currentTimeStamp();
|
||||
Integer userId = (Integer) map.get("userId");
|
||||
List<PkInfoModel> pkModels = pkDao.queryCanUseData(userId, time);
|
||||
return ResponseData.success(pkModels);
|
||||
}
|
||||
|
||||
//pk文章详情
|
||||
@PostMapping("pkInfoDetail")
|
||||
public ResponseData<Object> pkInfoDetail(@RequestBody Map<String, Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
Integer userId = map.get("userId");
|
||||
Integer from = map.get("from"); // 1 首页 2 聊天
|
||||
|
||||
PkInfoModel pkInfoModel = pkDao.selectById(id);
|
||||
if (pkInfoModel == null) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"该信息不存在");
|
||||
}
|
||||
|
||||
if (from == 1) {
|
||||
if (pkInfoModel.getPkTime() > VVTools.currentTimeStamp()) {
|
||||
// 判断是否是自己发布的数据 如果不是,就隐藏主播id
|
||||
if (pkInfoModel.getSenderId().equals(userId)) {
|
||||
pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId());
|
||||
} else {
|
||||
// 查询是否存在未完成的pk记录
|
||||
Integer isHave = pkDao.checkIfUnfinishedPKExistsWithAnchor(userId, pkInfoModel.getAnchorId());
|
||||
if (isHave > 0) {
|
||||
pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId());
|
||||
}else {
|
||||
pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(), '*'));
|
||||
}
|
||||
}
|
||||
return ResponseData.success(pkInfoModel);
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"当前信息已无效");
|
||||
}
|
||||
}else{
|
||||
Integer isHave = pkDao.checkIfUnfinishedPKExistsWithAnchor(userId, pkInfoModel.getAnchorId());
|
||||
if (isHave > 0) {
|
||||
pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId());
|
||||
}else {
|
||||
pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(), '*'));
|
||||
}
|
||||
return ResponseData.success(pkInfoModel);
|
||||
}
|
||||
}
|
||||
|
||||
//删除自己的pk数据 (单个)
|
||||
@PostMapping("deletePkDataWithId")
|
||||
public ResponseData<Object> deletePkDataWithId(@RequestBody Map<String,Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
PkInfoModel pkInfoModel = pkDao.selectById(id);
|
||||
|
||||
if (pkInfoModel.getPinExpireTime() > VVTools.currentTimeStamp()) {
|
||||
return ResponseData.error(ResponseInfo.ERROR,"该信息在置顶中。如要删除清先取消置顶");
|
||||
}
|
||||
|
||||
Integer result = pkDao.deletePkDataWithId(id);
|
||||
return result == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,"删除数据失败");
|
||||
}
|
||||
|
||||
//修改pk信息内容
|
||||
@PostMapping("updatePkInfoById")
|
||||
public ResponseData<Object> updatePkInfoById(@RequestBody PkInfoModel infoModel) {
|
||||
int result = pkDao.updateById(infoModel);
|
||||
return result == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
// 根据id查询pk记录
|
||||
@PostMapping("singleRecord")
|
||||
public ResponseData<Object> singleRecord(@RequestBody PkRecord record) {
|
||||
PkRecord data = recordDao.singleRecord(record.getId());
|
||||
return ResponseData.success(data);
|
||||
}
|
||||
|
||||
// 查询pk中每个场次的详细数据
|
||||
@PostMapping("fetchDetailPkDataWithId")
|
||||
public ResponseData<Object> fetchDetailPkDataWithId(@RequestBody Map<String,Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
List<PkRecordDetail> pkRecordDetails = recordDao.fetchDetailPkDataWithId(id);
|
||||
return ResponseData.success(pkRecordDetails);
|
||||
}
|
||||
|
||||
// 根据用户id查询该用户已发布的未被邀请的主播列表
|
||||
@PostMapping("listUninvitedPublishedAnchorsByUserId")
|
||||
public ResponseData<Object> listUninvitedPublishedAnchorsByUserId(@RequestBody Map<String,Integer> map) {
|
||||
Integer userId = map.get("userId");
|
||||
List<PkInfoModel> pkInfoModels = pkDao.listUninvitedPublishedAnchorsByUserId(userId);
|
||||
for (PkInfoModel pkInfoModel : pkInfoModels) {
|
||||
pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(),'*'));
|
||||
}
|
||||
return ResponseData.success(pkInfoModels);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************************************************/
|
||||
/** Python 相关接口 */
|
||||
/************************************************************************************************************************************/
|
||||
// Python那边需要的pk数据
|
||||
@PostMapping("pkListForPython")
|
||||
public ResponseData<Object> pkDataListForPython() {
|
||||
// 获取当日的开始时间和结束时间
|
||||
Map<String, Long> timeMap = VVTools.startAndEndTimeStampForToday();
|
||||
long start = timeMap.get("start");
|
||||
long end = timeMap.get("end");
|
||||
List<PkRecord> result = recordDao.pkListForToday(start, end);
|
||||
return ResponseData.success(result);
|
||||
}
|
||||
|
||||
// 更新pk结果信息
|
||||
@PostMapping("updatePkRecordInfo")
|
||||
public ResponseData<Object> updatePkRecordInfo(@RequestBody PkRecord record) {
|
||||
int i = recordDao.updateById(record);
|
||||
return i == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
// 插入pk明细表数据
|
||||
@PostMapping("insertPkDetail")
|
||||
public ResponseData<Object> insert(@RequestBody PkRecordDetail detail) {
|
||||
detail.setCreateTime(VVTools.currentTimeStamp());
|
||||
int insert = detailDao.insert(detail);
|
||||
return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package vvpkassistant.pk;
|
||||
package vvpkassistant.pk.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -1,9 +1,12 @@
|
||||
package vvpkassistant.pk;
|
||||
package vvpkassistant.pk.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.pk.model.PkRecordDetail;
|
||||
import vvpkassistant.pk.model.PkRecord;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package vvpkassistant.pk;
|
||||
package vvpkassistant.pk.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.pk.model.PkRecordDetail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.pk;
|
||||
package vvpkassistant.pk.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.pk;
|
||||
package vvpkassistant.pk.model;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
@@ -1,4 +1,4 @@
|
||||
package vvpkassistant.pk;
|
||||
package vvpkassistant.pk.model;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
24
src/main/java/vvpkassistant/pk/service/PKService.java
Normal file
24
src/main/java/vvpkassistant/pk/service/PKService.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package vvpkassistant.pk.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
import vvpkassistant.pk.model.PkRecord;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 13:53
|
||||
*/
|
||||
public interface PKService extends IService<PkInfoModel> {
|
||||
PkInfoModel addPkAddData(PkInfoModel pkModel);
|
||||
|
||||
Boolean updatePkStatus(PkRecord recordModel);
|
||||
|
||||
PkRecord createPKRecord(PkRecord record);
|
||||
|
||||
List<PkInfoModel> getPKList(Map<String, Object> map);
|
||||
|
||||
PkInfoModel pkInfoDetail(Map<String, Integer> map);
|
||||
}
|
||||
243
src/main/java/vvpkassistant/pk/service/PKServiceImpl.java
Normal file
243
src/main/java/vvpkassistant/pk/service/PKServiceImpl.java
Normal file
@@ -0,0 +1,243 @@
|
||||
package vvpkassistant.pk.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.CoinRecords.CoinRecords;
|
||||
import vvpkassistant.CoinRecords.CoinRecordsDao;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.config.FunctionConfigHolder;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.pk.mapper.PkInfoDao;
|
||||
import vvpkassistant.pk.mapper.PkRecordDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
import vvpkassistant.pk.model.PkRecord;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 13:54
|
||||
*/
|
||||
@Service
|
||||
public class PKServiceImpl extends ServiceImpl<PkInfoDao, PkInfoModel> implements PKService {
|
||||
|
||||
@Resource
|
||||
private PkInfoDao pkInfoDao;
|
||||
|
||||
@Resource
|
||||
private PkRecordDao pkRecordDao;
|
||||
|
||||
@Resource
|
||||
private CoinRecordsDao coinRecordsDao;
|
||||
|
||||
@Resource
|
||||
private UserDao userDao;
|
||||
|
||||
@Override
|
||||
public PkInfoModel addPkAddData(PkInfoModel pkModel) {
|
||||
// 初始可邀请状态为0
|
||||
pkModel.setInviteStatus(0);
|
||||
pkModel.setPinExpireTime(0);
|
||||
|
||||
// 获取主播id
|
||||
String anchorId = pkModel.getAnchorId();
|
||||
// 查询当天是否存在该主播发布的pk信息。
|
||||
Integer pkTime = pkModel.getPkTime();
|
||||
|
||||
// 根据设置的pk时间。查询出当天的开始时间和结束时间
|
||||
Map<String, Long> dayStartAndEndTimestamp = VVTools.getDayStartAndEndTimestamp(pkTime);
|
||||
|
||||
Long start = dayStartAndEndTimestamp.get("start");
|
||||
Long end = dayStartAndEndTimestamp.get("end");
|
||||
|
||||
// 查询主播在当天是否有发布过pk信息
|
||||
List<PkInfoModel> pkInfoModels = pkInfoDao.selectDataWithAnchorIdAndTime(anchorId, start, end);
|
||||
|
||||
// 判断该主播在当日是否已发布过pk信息
|
||||
if (!pkInfoModels.isEmpty()) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "该主播当日已有pk信息");
|
||||
}
|
||||
|
||||
if (pkInfoDao.insert(pkModel) == 1) {
|
||||
return pkModel;
|
||||
} else
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updatePkStatus(PkRecord recordModel) {
|
||||
if (recordModel.getPkStatus() == 1) {
|
||||
|
||||
// 查询出记录信息
|
||||
PkRecord pkRecordById = pkRecordDao.singleRecord(recordModel.getId());
|
||||
|
||||
// 更新可邀请状态
|
||||
PkInfoModel pkInfoModelA = pkInfoDao.selectById(pkRecordById.getPkIdA());
|
||||
pkInfoModelA.setInviteStatus(1);
|
||||
|
||||
PkInfoModel pkInfoModelB = pkInfoDao.selectById(pkRecordById.getPkIdB());
|
||||
pkInfoModelB.setInviteStatus(1);
|
||||
|
||||
pkInfoDao.updateById(pkInfoModelA);
|
||||
pkInfoDao.updateById(pkInfoModelB);
|
||||
|
||||
// 如果有置顶的状态。需要取消置顶
|
||||
if (pkInfoModelA.getPinExpireTime() > VVTools.currentTimeStamp()) {
|
||||
long hour = VVTools.calculateHoursFloor(pkInfoModelA.getPinExpireTime(), VVTools.currentTimeStamp());
|
||||
int coin = Integer.parseInt(FunctionConfigHolder.getValue("置顶扣除积分"));
|
||||
int totalCoin = (int) (coin * hour);
|
||||
|
||||
// 插入记录
|
||||
CoinRecords coinRecords = new CoinRecords("成功预约pk,自动取消置顶", pkInfoModelA.getSenderId(), totalCoin, (int) VVTools.currentTimeStamp(), 1);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
|
||||
// 更新积分
|
||||
UserModel userModel = userDao.selectById(pkRecordById.getUserIdA());
|
||||
Integer points = userModel.getPoints();
|
||||
userModel.setPoints(points + totalCoin);
|
||||
}
|
||||
|
||||
if (pkInfoModelB.getPinExpireTime() > VVTools.currentTimeStamp()) {
|
||||
long hour = VVTools.calculateHoursFloor(pkInfoModelB.getPinExpireTime(), VVTools.currentTimeStamp());
|
||||
int coin = Integer.parseInt(FunctionConfigHolder.getValue("置顶扣除积分"));
|
||||
int totalCoin = (int) (coin * hour);
|
||||
|
||||
// 插入记录
|
||||
CoinRecords coinRecords = new CoinRecords("成功预约pk,自动取消置顶", pkInfoModelB.getSenderId(), totalCoin, (int) VVTools.currentTimeStamp(), 1);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
|
||||
// 更新积分
|
||||
UserModel userModel = userDao.selectById(pkRecordById.getUserIdB());
|
||||
Integer points = userModel.getPoints();
|
||||
userModel.setPoints(points + totalCoin);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新pk邀请记录
|
||||
if (pkRecordDao.updateById(recordModel) == 1) {
|
||||
return true;
|
||||
} else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PkRecord createPKRecord(PkRecord record) {
|
||||
// 如果这两个邀约直播之间存在未处理的邀请记录。那就不允许继续发送pk邀请
|
||||
String anchorIdA = record.getAnchorIdA();
|
||||
String anchorIdB = record.getAnchorIdB();
|
||||
Integer dataCount = pkRecordDao.getPendingInvitations(anchorIdA, anchorIdB);
|
||||
|
||||
if (dataCount > 0) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "已存在一条未处理的pk申请,不能重复发送");
|
||||
}
|
||||
|
||||
record.setPkStatus(0);
|
||||
if (pkRecordDao.insert(record) == 1 ){
|
||||
return record;
|
||||
}else
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PkInfoModel> getPKList(Map<String, Object> map) {
|
||||
|
||||
Integer page = (Integer) map.get("page");
|
||||
Integer size = (Integer) map.get("size");
|
||||
Map<String,Object> condition = (Map<String, Object>) map.get("condition");
|
||||
|
||||
Map<String, Long> todayTimeStampMap = VVTools.startAndEndTimeStampForToday();
|
||||
Long start = VVTools.currentTimeStamp();
|
||||
Long end = todayTimeStampMap.get("end");
|
||||
|
||||
List<PkInfoModel> pkModels = pkInfoDao.selectPkInfoByCondition(page * size, size, condition, start, end);
|
||||
|
||||
long currentTimeStamp = VVTools.currentTimeStamp();
|
||||
|
||||
//如果传了用户id
|
||||
if (map.containsKey("userId")) {
|
||||
Long begin = VVTools.currentTimeStamp();
|
||||
Integer userId = Integer.valueOf(map.get("userId").toString());
|
||||
// 查询出当前用户大于等于今天的已接受邀请的pk数据
|
||||
List<PkRecord> pkRecords = pkRecordDao.fetchDataFromTodayWithUserId(userId, begin);
|
||||
// 遍历查询出的数据。如果文章的id相同。就显示完整的主播名称,
|
||||
for (PkInfoModel pkModel : pkModels) {
|
||||
pkModel.setDisPlayId(pkModel.getAnchorId());
|
||||
// 设置是否为置顶
|
||||
pkModel.setIsPin(pkModel.getPinExpireTime() > currentTimeStamp);
|
||||
// 如果文章的发布者不是当前登录主播。
|
||||
if (pkModel.getSenderId().intValue() != userId) {
|
||||
boolean showId = false;
|
||||
// 查找是否和当前登录的账号有pk关系。
|
||||
for (PkRecord pkRecord : pkRecords) {
|
||||
// 如果当前用户是邀请pk的,并且对方已接受pk,也可以看到主播id
|
||||
if (pkRecord.getUserIdB().intValue() == userId &&
|
||||
pkRecord.getPkIdA().intValue() == pkModel.getId().intValue() &&
|
||||
pkRecord.getPkStatus() == 1) {
|
||||
showId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 条件不满足则隐藏主播id'
|
||||
if (!showId) {
|
||||
pkModel.setDisPlayId(VVTools.replaceChar(pkModel.getAnchorId(), '*'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for (PkInfoModel pkModel : pkModels) {
|
||||
// 设置是否为置顶
|
||||
pkModel.setIsPin(pkModel.getPinExpireTime() > currentTimeStamp);
|
||||
pkModel.setDisPlayId(VVTools.replaceChar(pkModel.getAnchorId(), '*'));
|
||||
}
|
||||
}
|
||||
return pkModels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PkInfoModel pkInfoDetail(Map<String, Integer> map) {
|
||||
Integer id = map.get("id");
|
||||
Integer userId = map.get("userId");
|
||||
Integer from = map.get("from"); // 1 首页 2 聊天
|
||||
|
||||
PkInfoModel pkInfoModel = pkInfoDao.selectById(id);
|
||||
if (pkInfoModel == null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "该信息不存在");
|
||||
}
|
||||
|
||||
if (from == 1) {
|
||||
if (pkInfoModel.getPkTime() > VVTools.currentTimeStamp()) {
|
||||
// 判断是否是自己发布的数据 如果不是,就隐藏主播id
|
||||
if (pkInfoModel.getSenderId().equals(userId)) {
|
||||
pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId());
|
||||
} else {
|
||||
// 查询是否存在未完成的pk记录
|
||||
Integer isHave = pkInfoDao.checkIfUnfinishedPKExistsWithAnchor(userId, pkInfoModel.getAnchorId());
|
||||
if (isHave > 0) {
|
||||
pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId());
|
||||
} else {
|
||||
pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(), '*'));
|
||||
}
|
||||
}
|
||||
return pkInfoModel;
|
||||
} else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"当前信息已无效");
|
||||
}
|
||||
} else {
|
||||
Integer isHave = pkInfoDao.checkIfUnfinishedPKExistsWithAnchor(userId, pkInfoModel.getAnchorId());
|
||||
if (isHave > 0) {
|
||||
pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId());
|
||||
} else {
|
||||
pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(), '*'));
|
||||
}
|
||||
return pkInfoModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ spring:
|
||||
url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true
|
||||
|
||||
|
||||
|
||||
chat:
|
||||
appId: 1600092688
|
||||
appKey: 9bb6df04907a8cff9292eee8d6b32158d008350198acba11607068d91cb65f66
|
||||
@@ -4,8 +4,8 @@ spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: wfn53400
|
||||
url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true
|
||||
password: 123asd
|
||||
url: jdbc:mysql://localhost:3306/vv_assistant?allowMultiQueries=true
|
||||
|
||||
|
||||
chat:
|
||||
|
||||
@@ -3,7 +3,60 @@ server:
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
active: local
|
||||
# Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
|
||||
execution:
|
||||
thread-name-prefix: mail-task # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
|
||||
pool: # 线程池相关
|
||||
core-size: 10 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
|
||||
max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
|
||||
keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
|
||||
queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
|
||||
allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
|
||||
shutdown:
|
||||
await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
|
||||
await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
|
||||
|
||||
|
||||
mybatis-plus:
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto
|
||||
|
||||
|
||||
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
|
||||
sa-token:
|
||||
# token 名称(同时也是 cookie 名称)
|
||||
token-name: token
|
||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||
timeout: -1
|
||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
||||
active-timeout: 648000
|
||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||
is-share: false
|
||||
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
|
||||
token-style: random-128
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
activateUrl: https://pk.webapp.yolozs.com/activationSuccessful/
|
||||
verificationMailUrl: https://pk.webapp.yolozs.com/verifyAccount/
|
||||
forgetPassWordUrl: https://pk.webapp.yolozs.com/resetPassword/
|
||||
|
||||
dromara:
|
||||
x-file-storage: #文件存储配置
|
||||
default-platform: tencent-cos-1 #默认使用的存储平台
|
||||
thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
|
||||
tencent-cos:
|
||||
- platform: tencent-cos-1 # 存储平台标识
|
||||
enable-storage: true # 启用存储
|
||||
secret-id: AKIDNbcQ1c3HJD9rQ6g5PaZN0PekcIkyzmMl
|
||||
secret-key: Nl4FI9mLo46vWu40iT0JQK8j8LK5cw2u
|
||||
region: ap-shanghai #存仓库所在地域
|
||||
bucket-name: vv-1317974657
|
||||
domain: https://vv-1317974657.cos.ap-shanghai.myqcloud.com # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
|
||||
base-path: /headerIcon/ # 基础路径
|
||||
|
||||
IM-secretKey: 04452c3231ae4fe5
|
||||
10
src/main/resources/mail.setting
Normal file
10
src/main/resources/mail.setting
Normal file
@@ -0,0 +1,10 @@
|
||||
# 邮件服务器的SMTP地址,可选,默认为smtp.<发件人邮箱后缀>
|
||||
host = smtp.exmail.qq.com
|
||||
# 邮件服务器的SMTP端口,可选,默认25
|
||||
port = 465
|
||||
# 发件人(必须正确,否则发送失败)
|
||||
from = niuyuxi@hanxiaokj.cn
|
||||
# 用户名,默认为发件人邮箱前缀
|
||||
user = niuyuxi@hanxiaokj.cn
|
||||
pass = tF35umug9CBCBKqR
|
||||
sslEnable = true
|
||||
@@ -8,7 +8,6 @@ spring:
|
||||
url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true
|
||||
|
||||
|
||||
|
||||
chat:
|
||||
appId: 1600092688
|
||||
appKey: 9bb6df04907a8cff9292eee8d6b32158d008350198acba11607068d91cb65f66
|
||||
@@ -4,8 +4,8 @@ spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: wfn53400
|
||||
url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true
|
||||
password: 123asd
|
||||
url: jdbc:mysql://localhost:3306/vv_assistant?allowMultiQueries=true
|
||||
|
||||
|
||||
chat:
|
||||
|
||||
@@ -3,7 +3,60 @@ server:
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
active: local
|
||||
# Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
|
||||
execution:
|
||||
thread-name-prefix: mail-task # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
|
||||
pool: # 线程池相关
|
||||
core-size: 10 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
|
||||
max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
|
||||
keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
|
||||
queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
|
||||
allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
|
||||
shutdown:
|
||||
await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
|
||||
await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
|
||||
|
||||
|
||||
mybatis-plus:
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto
|
||||
|
||||
|
||||
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
|
||||
sa-token:
|
||||
# token 名称(同时也是 cookie 名称)
|
||||
token-name: token
|
||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||
timeout: -1
|
||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
||||
active-timeout: 648000
|
||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||
is-share: false
|
||||
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
|
||||
token-style: random-128
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
activateUrl: https://pk.webapp.yolozs.com/activationSuccessful/
|
||||
verificationMailUrl: https://pk.webapp.yolozs.com/verifyAccount/
|
||||
forgetPassWordUrl: https://pk.webapp.yolozs.com/resetPassword/
|
||||
|
||||
dromara:
|
||||
x-file-storage: #文件存储配置
|
||||
default-platform: tencent-cos-1 #默认使用的存储平台
|
||||
thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
|
||||
tencent-cos:
|
||||
- platform: tencent-cos-1 # 存储平台标识
|
||||
enable-storage: true # 启用存储
|
||||
secret-id: AKIDNbcQ1c3HJD9rQ6g5PaZN0PekcIkyzmMl
|
||||
secret-key: Nl4FI9mLo46vWu40iT0JQK8j8LK5cw2u
|
||||
region: ap-shanghai #存仓库所在地域
|
||||
bucket-name: vv-1317974657
|
||||
domain: https://vv-1317974657.cos.ap-shanghai.myqcloud.com # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
|
||||
base-path: /headerIcon/ # 基础路径
|
||||
|
||||
IM-secretKey: 04452c3231ae4fe5
|
||||
@@ -1,5 +0,0 @@
|
||||
#Generated by Maven
|
||||
#Wed Jul 30 13:17:57 CST 2025
|
||||
version=0.0.1
|
||||
groupId=com.vv.pk.assistant
|
||||
artifactId=vvPkAssistant
|
||||
@@ -1,38 +0,0 @@
|
||||
vvpkassistant\FunctionConfig\FunctionConfigHolder.class
|
||||
vvpkassistant\FunctionConfig\FunctionConfigMapper.class
|
||||
vvpkassistant\User\UserModel.class
|
||||
vvpkassistant\pk\PkInfoDao.class
|
||||
vvpkassistant\pk\PkRecordDetail.class
|
||||
META-INF\spring-configuration-metadata.json
|
||||
vvpkassistant\Anchors\AnchorModel.class
|
||||
vvpkassistant\CoinRecords\CoinRecordsDao.class
|
||||
vvpkassistant\Data\ResponseData.class
|
||||
vvpkassistant\SystemMessage\SystemMessageDao.class
|
||||
vvpkassistant\SystemMessage\SystemMessage.class
|
||||
vvpkassistant\Tools\VVRequester.class
|
||||
vvpkassistant\Anchors\AnchorDao.class
|
||||
vvpkassistant\FunctionConfig\FunctionConfigController.class
|
||||
vvpkassistant\pk\PkRecord.class
|
||||
vvpkassistant\Tools\OkHttpUtils.class
|
||||
vvpkassistant\Tools\COSSigner.class
|
||||
vvpkassistant\chat\ChatModel.class
|
||||
vvpkassistant\pk\PkRecordDetailDao.class
|
||||
vvpkassistant\Tools\VVRequester$1.class
|
||||
vvpkassistant\Data\WxChatParam.class
|
||||
vvpkassistant\chat\ChatDao.class
|
||||
vvpkassistant\pk\PkInfoModel.class
|
||||
vvpkassistant\SystemMessage\SystemMessageController.class
|
||||
vvpkassistant\Data\ResponseInfo.class
|
||||
vvpkassistant\chat\ChatController.class
|
||||
vvpkassistant\FunctionConfig\FunctionConfigModel.class
|
||||
vvpkassistant\User\UserDao.class
|
||||
vvpkassistant\pk\PkController.class
|
||||
vvpkassistant\Anchors\AnchorsController.class
|
||||
vvpkassistant\Application.class
|
||||
vvpkassistant\pk\PkRecordDao.class
|
||||
vvpkassistant\CoinRecords\CoinRecords.class
|
||||
vvpkassistant\Tools\VVTools.class
|
||||
vvpkassistant\Tools\LogUtil.class
|
||||
vvpkassistant\User\UserController.class
|
||||
vvpkassistant\Tools\WebMvcConfig.class
|
||||
vvpkassistant\Data\WxParam.class
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user