feat: add core entities, controllers, services, and mappers across multi-module project
This commit is contained in:
commit
4335344af7
1456 files changed
+58308
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
test
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<annotationProcessing>
|
||||||
|
<profile default="true" name="Default" enabled="true" />
|
||||||
|
<profile name="Maven default annotation processors profile" enabled="true">
|
||||||
|
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||||
|
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||||
|
<outputRelativeToContentRoot value="true" />
|
||||||
|
<module name="admin" />
|
||||||
|
<module name="applet" />
|
||||||
|
<module name="common" />
|
||||||
|
<module name="mobileApp" />
|
||||||
|
</profile>
|
||||||
|
</annotationProcessing>
|
||||||
|
<bytecodeTargetLevel target="8">
|
||||||
|
<module name="udpServer" target="1.5" />
|
||||||
|
</bytecodeTargetLevel>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+19
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="uni_ai_doctor@139.9.2.195" uuid="06e507fc-985b-4560-a7ce-efbeebdf9230">
|
||||||
|
<driver-ref>mysql</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>com.mysql.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://139.9.2.195:3306/uni_ai_doctor</jdbc-url>
|
||||||
|
<driver-properties>
|
||||||
|
<property name="autoReconnect" value="true" />
|
||||||
|
<property name="zeroDateTimeBehavior" value="convertToNull" />
|
||||||
|
<property name="tinyInt1isBit" value="false" />
|
||||||
|
<property name="characterEncoding" value="utf8" />
|
||||||
|
<property name="characterSetResults" value="utf8" />
|
||||||
|
<property name="yearIsDateType" value="false" />
|
||||||
|
</driver-properties>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+16
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with NO BOM">
|
||||||
|
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/admin" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/admin/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/admin/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/applet" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/applet/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/applet/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/common" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/common/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/common/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/mobileApp" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+102
@@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PersistentConfig">
|
||||||
|
<option name="historyConfigList">
|
||||||
|
<map>
|
||||||
|
<entry key="sys_dict">
|
||||||
|
<value>
|
||||||
|
<Config>
|
||||||
|
<option name="comment" value="true" />
|
||||||
|
<option name="daoMvnPath" value="" />
|
||||||
|
<option name="daoName" value="SysDictMapper" />
|
||||||
|
<option name="daoPackage" value="mapper" />
|
||||||
|
<option name="daoPostfix" value="Mapper" />
|
||||||
|
<option name="daoTargetFolder" value="$PROJECT_DIR$/applet/src/main/java/cn/unizk" />
|
||||||
|
<option name="modelMvnPath" value="" />
|
||||||
|
<option name="modelName" value="SysDict" />
|
||||||
|
<option name="modelPackage" value="po" />
|
||||||
|
<option name="modelTargetFolder" value="$PROJECT_DIR$/common/src/main/java/cn/unizk/entity" />
|
||||||
|
<option name="mysql_8" value="true" />
|
||||||
|
<option name="name" value="sys_dict" />
|
||||||
|
<option name="needToStringHashcodeEquals" value="true" />
|
||||||
|
<option name="offsetLimit" value="true" />
|
||||||
|
<option name="overrideXML" value="true" />
|
||||||
|
<option name="primaryKey" value="dict_code" />
|
||||||
|
<option name="projectFolder" value="$PROJECT_DIR$" />
|
||||||
|
<option name="tableName" value="sys_dict" />
|
||||||
|
<option name="useSchemaPrefix" value="true" />
|
||||||
|
<option name="xmlMvnPath" value="" />
|
||||||
|
<option name="xmlPackage" value="mapper" />
|
||||||
|
<option name="xmlTargetFolder" value="E:\code\unizk\AI_Questioning\applet\src\main\resources" />
|
||||||
|
</Config>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="xunfu_account">
|
||||||
|
<value>
|
||||||
|
<Config>
|
||||||
|
<option name="comment" value="true" />
|
||||||
|
<option name="daoMvnPath" value="src/main/java" />
|
||||||
|
<option name="daoName" value="XunfuAccountDao" />
|
||||||
|
<option name="daoPackage" value="mapper" />
|
||||||
|
<option name="daoPostfix" value="Dao" />
|
||||||
|
<option name="daoTargetFolder" value="$PROJECT_DIR$/applet/src/main/java/cn/unizk" />
|
||||||
|
<option name="modelMvnPath" value="src/main/java" />
|
||||||
|
<option name="modelName" value="XunfuAccount" />
|
||||||
|
<option name="modelPackage" value="po" />
|
||||||
|
<option name="modelTargetFolder" value="$PROJECT_DIR$/common/src/main/java/cn/unizk/entity" />
|
||||||
|
<option name="name" value="xunfu_account" />
|
||||||
|
<option name="needToStringHashcodeEquals" value="true" />
|
||||||
|
<option name="offsetLimit" value="true" />
|
||||||
|
<option name="overrideXML" value="true" />
|
||||||
|
<option name="primaryKey" value="xunfu_account_id" />
|
||||||
|
<option name="projectFolder" value="$PROJECT_DIR$" />
|
||||||
|
<option name="tableName" value="xunfu_account" />
|
||||||
|
<option name="useExample" value="true" />
|
||||||
|
<option name="useSchemaPrefix" value="true" />
|
||||||
|
<option name="xmlMvnPath" value="src/main/resources" />
|
||||||
|
<option name="xmlPackage" value="mapper" />
|
||||||
|
<option name="xmlTargetFolder" value="E:\code\unizk\AI_Questioning\applet\src\main\resources" />
|
||||||
|
</Config>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="xunfu_account_image">
|
||||||
|
<value>
|
||||||
|
<Config>
|
||||||
|
<option name="comment" value="true" />
|
||||||
|
<option name="daoMvnPath" value="" />
|
||||||
|
<option name="daoName" value="XunfuAccountImageDao" />
|
||||||
|
<option name="daoPackage" value="cn.unizk.mapper" />
|
||||||
|
<option name="daoPostfix" value="Dao" />
|
||||||
|
<option name="daoTargetFolder" value="$PROJECT_DIR$/applet/src/main/java/cn/unizk/mapper" />
|
||||||
|
<option name="modelMvnPath" value="src/main/java" />
|
||||||
|
<option name="modelName" value="XunfuAccountImage" />
|
||||||
|
<option name="modelPackage" value="cn.unizk.entity.po" />
|
||||||
|
<option name="modelTargetFolder" value="$PROJECT_DIR$/common/src/main/java/cn/unizk/entity/po" />
|
||||||
|
<option name="name" value="xunfu_account_image" />
|
||||||
|
<option name="overrideXML" value="true" />
|
||||||
|
<option name="primaryKey" value="image_id" />
|
||||||
|
<option name="projectFolder" value="$PROJECT_DIR$" />
|
||||||
|
<option name="tableName" value="xunfu_account_image" />
|
||||||
|
<option name="useExample" value="true" />
|
||||||
|
<option name="useSchemaPrefix" value="true" />
|
||||||
|
<option name="xmlMvnPath" value="" />
|
||||||
|
<option name="xmlPackage" value="generator" />
|
||||||
|
<option name="xmlTargetFolder" value="E:\code\unizk\AI_Questioning\applet\src\main\resources\mapper" />
|
||||||
|
</Config>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="users">
|
||||||
|
<map>
|
||||||
|
<entry key="jdbc:mysql://139.9.2.195:3306/uni_ai_doctor">
|
||||||
|
<value>
|
||||||
|
<User>
|
||||||
|
<option name="username" value="unizk" />
|
||||||
|
</User>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GitToolBoxProjectSettings">
|
||||||
|
<option name="commitMessageIssueKeyValidationOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
<option name="commitMessageValidationEnabledOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||||
|
<option name="superClassString" value="java.awt.Component" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
Generated
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RemoteRepositoriesConfiguration">
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Maven Central repository" />
|
||||||
|
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="jboss.community" />
|
||||||
|
<option name="name" value="JBoss Community repository" />
|
||||||
|
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Central Repository" />
|
||||||
|
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public" />
|
||||||
|
</remote-repository>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+14
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="MavenProjectsManager">
|
||||||
|
<option name="originalFiles">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+124
@@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Palette2">
|
||||||
|
<group name="Swing">
|
||||||
|
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Button" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="RadioButton" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="CheckBox" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Label" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||||
|
<preferred-size width="-1" height="20" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
</group>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4" />
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# AI智能问诊
|
||||||
|
|
||||||
|
#### Description
|
||||||
|
尤尼智康-AI智能问诊项目
|
||||||
|
|
||||||
|
#### Software Architecture
|
||||||
|
Software architecture description
|
||||||
|
|
||||||
|
#### Installation
|
||||||
|
|
||||||
|
1. xxxx
|
||||||
|
2. xxxx
|
||||||
|
3. xxxx
|
||||||
|
|
||||||
|
#### Instructions
|
||||||
|
|
||||||
|
1. xxxx
|
||||||
|
2. xxxx
|
||||||
|
3. xxxx
|
||||||
|
|
||||||
|
#### Contribution
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create Feat_xxx branch
|
||||||
|
3. Commit your code
|
||||||
|
4. Create Pull Request
|
||||||
|
|
||||||
|
|
||||||
|
#### Gitee Feature
|
||||||
|
|
||||||
|
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||||
|
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||||
|
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||||
|
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||||
|
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||||
|
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# AI智能问诊
|
||||||
|
|
||||||
|
#### 介绍
|
||||||
|
尤尼智康-AI智能问诊项目
|
||||||
|
|
||||||
|
#### 软件架构
|
||||||
|
软件架构说明
|
||||||
|
|
||||||
|
|
||||||
|
#### 安装教程
|
||||||
|
|
||||||
|
1. xxxx
|
||||||
|
2. xxxx
|
||||||
|
3. xxxx
|
||||||
|
|
||||||
|
#### 使用说明
|
||||||
|
|
||||||
|
1. xxxx
|
||||||
|
2. xxxx
|
||||||
|
3. xxxx
|
||||||
|
|
||||||
|
#### 参与贡献
|
||||||
|
|
||||||
|
1. Fork 本仓库
|
||||||
|
2. 新建 Feat_xxx 分支
|
||||||
|
3. 提交代码
|
||||||
|
4. 新建 Pull Request
|
||||||
|
|
||||||
|
|
||||||
|
#### 特技
|
||||||
|
|
||||||
|
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||||
|
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||||
|
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||||
|
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||||
|
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||||
|
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4" />
|
||||||
+12807
File diff suppressed because it is too large.
Load diff
+124
@@ -0,0 +1,124 @@
|
|||||||
|
<?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"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>AI_Questioning</artifactId>
|
||||||
|
<groupId>cn.unizk</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>admin</artifactId>
|
||||||
|
|
||||||
|
<name>admin</name>
|
||||||
|
<!-- FIXME change it to the project's website -->
|
||||||
|
<url>http://www.example.com</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.release>17</maven.compiler.release>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.davidcarboni</groupId>
|
||||||
|
<artifactId>encrypted-</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.unizk</groupId>
|
||||||
|
<artifactId>common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-integration</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.integration</groupId>
|
||||||
|
<artifactId>spring-integration-ip</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.integration</groupId>
|
||||||
|
<artifactId>spring-integration-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<version>2.1.1.RELEASE</version>
|
||||||
|
<configuration>
|
||||||
|
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package cn.unizk;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableWebSecurity
|
||||||
|
@MapperScan("cn.unizk.mapper")
|
||||||
|
@EnableScheduling
|
||||||
|
public class AdminApp {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(AdminApp.class,args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package cn.unizk.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Anonymous
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.unizk.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/3/13 15:34
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@ConfigurationProperties(prefix = "huifu-vendor")
|
||||||
|
@Component
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class HuiFuVendorProperties {
|
||||||
|
|
||||||
|
private String sysId;
|
||||||
|
|
||||||
|
private String huifuId;
|
||||||
|
|
||||||
|
private String publicKey;
|
||||||
|
|
||||||
|
private String privateKey;
|
||||||
|
|
||||||
|
private String refundApi;
|
||||||
|
|
||||||
|
private String productId;
|
||||||
|
|
||||||
|
private String notifyUrl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.unizk.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/25 18:30
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
public class ResourcesConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsFilter corsFilter()
|
||||||
|
{
|
||||||
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
|
config.setAllowCredentials(true);
|
||||||
|
// 设置访问源地址
|
||||||
|
config.addAllowedOriginPattern("*");
|
||||||
|
// 设置访问源请求头
|
||||||
|
config.addAllowedHeader("*");
|
||||||
|
// 设置访问源请求方法
|
||||||
|
config.addAllowedMethod("*");
|
||||||
|
// 有效期 1800秒
|
||||||
|
config.setMaxAge(1800L);
|
||||||
|
// 添加映射路径,拦截一切请求
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
// 返回新的CorsFilter
|
||||||
|
return new CorsFilter(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package cn.unizk.config;
|
||||||
|
|
||||||
|
import cn.unizk.security.filter.JwtAuthenticationTokenFilter;
|
||||||
|
import cn.unizk.properties.PermitAllUrlProperties;
|
||||||
|
import cn.unizk.security.handler.AuthenticationEntryPointImpl;
|
||||||
|
import cn.unizk.security.handler.LogoutSuccessHandlerImpl;
|
||||||
|
import cn.unizk.security.handler.UserAccessDeniedHandler;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||||
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/25 10:55
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||||
|
@Configuration
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义用户认证逻辑
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证失败处理类
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationEntryPointImpl unauthorizedHandler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserAccessDeniedHandler userAccessDeniedHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出处理类
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private LogoutSuccessHandlerImpl logoutSuccessHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token认证过滤器
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private JwtAuthenticationTokenFilter authenticationTokenFilter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跨域过滤器
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private CorsFilter corsFilter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许匿名访问的地址
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private PermitAllUrlProperties permitAllUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份验证实现
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager() {
|
||||||
|
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
|
||||||
|
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
|
||||||
|
daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
|
||||||
|
return new ProviderManager(daoAuthenticationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* anyRequest | 匹配所有请求路径
|
||||||
|
* access | SpringEl表达式结果为true时可以访问
|
||||||
|
* anonymous | 匿名可以访问
|
||||||
|
* denyAll | 用户不能访问
|
||||||
|
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
|
||||||
|
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
|
||||||
|
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
|
||||||
|
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
|
||||||
|
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
|
||||||
|
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
|
||||||
|
* permitAll | 用户可以任意访问
|
||||||
|
* rememberMe | 允许通过remember-me登录的用户访问
|
||||||
|
* authenticated | 用户登录后可访问
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||||
|
return httpSecurity
|
||||||
|
// CSRF禁用,因为不使用session
|
||||||
|
.csrf(csrf -> csrf.disable())
|
||||||
|
// 禁用HTTP响应标头
|
||||||
|
.headers((headersCustomizer) -> {
|
||||||
|
headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
|
||||||
|
})
|
||||||
|
// 认证失败处理类
|
||||||
|
.exceptionHandling(exception -> exception
|
||||||
|
.authenticationEntryPoint(unauthorizedHandler)
|
||||||
|
.accessDeniedHandler(userAccessDeniedHandler))
|
||||||
|
// 基于token,所以不需要session
|
||||||
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
|
// 注解标记允许匿名访问的url
|
||||||
|
.authorizeHttpRequests((requests) -> {
|
||||||
|
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
|
||||||
|
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||||
|
requests.antMatchers("/pc/loginByUsername", "/register", "/captchaImage", "/wx/**","/h5/**","/pc/test","/satoken/ajaxlogin",
|
||||||
|
"/equipment/warehousing","/pc/userTreat/**").permitAll()
|
||||||
|
.antMatchers("/pc/admin/**").hasRole("ADMIN")
|
||||||
|
// 静态资源,可匿名访问
|
||||||
|
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||||
|
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||||
|
// 除上面外的所有请求全部需要鉴权认证
|
||||||
|
.anyRequest().authenticated();
|
||||||
|
})
|
||||||
|
// 添加Logout filter
|
||||||
|
.logout(logout -> logout.logoutUrl("/pc/logout").logoutSuccessHandler(logoutSuccessHandler))
|
||||||
|
// 添加JWT filter
|
||||||
|
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
|
||||||
|
// 添加CORS filter
|
||||||
|
/*.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
|
||||||
|
.addFilterBefore(corsFilter, LogoutFilter.class)*/
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强散列哈希加密实现
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public BCryptPasswordEncoder bCryptPasswordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
package cn.unizk.config;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.DeviceUpgrade;
|
||||||
|
import cn.unizk.mapper.DeviceUpgradeMapper;
|
||||||
|
import cn.unizk.service.FileService;
|
||||||
|
import cn.unizk.utils.FixedLengthSerializer;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.dsl.IntegrationFlow;
|
||||||
|
import org.springframework.integration.dsl.IntegrationFlows;
|
||||||
|
import org.springframework.integration.handler.LoggingHandler;
|
||||||
|
import org.springframework.integration.ip.dsl.Tcp;
|
||||||
|
import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory;
|
||||||
|
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
|
||||||
|
import org.springframework.integration.support.MessageBuilder;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/11/18 11:55
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
//@Configuration
|
||||||
|
public class TcpServerDSLConfig {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TcpServerDSLConfig.class);
|
||||||
|
// private static final String UPGRADE_PACKAGE_ROOT_PATH = "/opt/jkadmin/upgrade/";
|
||||||
|
private static final String UPGRADE_PACKAGE_ROOT_PATH = "E:\\opt\\";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileService fileService;
|
||||||
|
@Resource
|
||||||
|
private DeviceUpgradeMapper deviceUpgradeMapper;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TcpNetServerConnectionFactory serverConnectionFactory() {
|
||||||
|
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(55367);
|
||||||
|
factory.setSingleUse(false);
|
||||||
|
factory.setSoTimeout(60_000);
|
||||||
|
factory.setSoKeepAlive(true);
|
||||||
|
factory.setSoLinger(3);
|
||||||
|
factory.setSoReceiveBufferSize(64 * 1024);
|
||||||
|
factory.setSoSendBufferSize(64* 1024);
|
||||||
|
factory.setSoTcpNoDelay(true);
|
||||||
|
ByteArrayCrLfSerializer deserializer = new ByteArrayCrLfSerializer();
|
||||||
|
deserializer.setMaxMessageSize(8192);
|
||||||
|
/*ByteArrayLengthHeaderSerializer ser = new ByteArrayLengthHeaderSerializer();
|
||||||
|
ser.setMaxMessageSize(1024 * 1024);*/
|
||||||
|
// factory.setSerializer(new FixedLengthSerializer());
|
||||||
|
factory.setDeserializer(deserializer);
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public IntegrationFlow tcpServerFlow(){
|
||||||
|
return IntegrationFlows
|
||||||
|
.from(Tcp.inboundGateway(serverConnectionFactory()))
|
||||||
|
.log(LoggingHandler.Level.INFO, "TCP接收",
|
||||||
|
message -> "来自 " +
|
||||||
|
message.getHeaders().get("ip_address") +
|
||||||
|
" 的数据")
|
||||||
|
.<byte[],byte[]>transform(payload -> {
|
||||||
|
logger.info("收到字节长度为:{}",payload.length);
|
||||||
|
return payload;
|
||||||
|
})
|
||||||
|
.<byte[],String>transform(payload ->
|
||||||
|
new String(payload,StandardCharsets.UTF_8))
|
||||||
|
.transform(this::processBusinessLogic)
|
||||||
|
.handle(((payload, headers) -> {
|
||||||
|
/*return MessageBuilder.withPayload(payload.toString().getBytes())
|
||||||
|
.copyHeaders(headers)
|
||||||
|
.build();*/
|
||||||
|
if (payload instanceof byte[]) {
|
||||||
|
return MessageBuilder.withPayload((byte[]) payload)
|
||||||
|
.copyHeaders(headers)
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
return MessageBuilder.withPayload(payload.toString().getBytes())
|
||||||
|
.copyHeaders(headers)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建数据包响应
|
||||||
|
* @param packageIndex 分包索引(00-31)
|
||||||
|
* @param data 1024字节数据
|
||||||
|
* @return 完整的响应数据包
|
||||||
|
*/
|
||||||
|
private byte[] buildDataPacket(String packageIndex, byte[] data) {
|
||||||
|
if (data.length != 1024){
|
||||||
|
logger.error("数据包大小不正确: {}, 应该是1024", data.length);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 协议格式:$|PN{index}|DA{1024字节二进制数据}|{CRC}\r\n
|
||||||
|
String crc = calculateCRC(data);
|
||||||
|
String header = String.format("$|PN%s|DA", packageIndex);
|
||||||
|
byte[] headerBytes = header.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
// CRC部分:|{CRC}
|
||||||
|
String crcPart = "|" + crc;
|
||||||
|
byte[] crcBytes = crcPart.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
// 完整数据包 = 协议头 + 1024字节文件数据 + CRC
|
||||||
|
byte[] response = new byte[headerBytes.length + data.length + crcBytes.length];
|
||||||
|
|
||||||
|
// 组装
|
||||||
|
System.arraycopy(headerBytes, 0, response, 0, headerBytes.length);
|
||||||
|
System.arraycopy(data, 0, response, headerBytes.length, data.length);
|
||||||
|
System.arraycopy(crcBytes, 0, response, headerBytes.length + data.length, crcBytes.length);
|
||||||
|
logger.info("构建数据包:索引={}, 总长度={}, CRC={}",
|
||||||
|
packageIndex, response.length, crc);
|
||||||
|
logger.info("========== 发送数据包详细信息 ==========");
|
||||||
|
logger.info("包索引: {}", packageIndex);
|
||||||
|
logger.info("协议头字符串: {}", header);
|
||||||
|
logger.info("协议头字节数: {}", headerBytes.length);
|
||||||
|
logger.info("数据字节数: {}", data.length);
|
||||||
|
logger.info("CRC字符串: {}", crc);
|
||||||
|
logger.info("CRC字节数: {}", crcBytes.length);
|
||||||
|
logger.info("总长度: {}", response.length);
|
||||||
|
// 打印完整十六进制(前200字节和后50字节)
|
||||||
|
StringBuilder hexFull = new StringBuilder();
|
||||||
|
int printLen = Math.min(1036, response.length);
|
||||||
|
for (int i = 0; i < printLen; i++) {
|
||||||
|
hexFull.append(String.format("%02X ", response[i]));
|
||||||
|
if ((i + 1) % 16 == 0) {
|
||||||
|
hexFull.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("前{}字节十六进制:\n{}", printLen, hexFull.toString());
|
||||||
|
|
||||||
|
// 打印协议头部分的ASCII
|
||||||
|
byte[] headerOnly = new byte[headerBytes.length];
|
||||||
|
System.arraycopy(response, 0, headerOnly, 0, headerBytes.length);
|
||||||
|
logger.info("协议头ASCII: {}", new String(headerOnly, StandardCharsets.US_ASCII));
|
||||||
|
|
||||||
|
// 打印数据部分的前20字节
|
||||||
|
StringBuilder dataHex = new StringBuilder();
|
||||||
|
for (int i = 0; i < Math.min(20, data.length); i++) {
|
||||||
|
dataHex.append(String.format("%02X ", data[i]));
|
||||||
|
}
|
||||||
|
logger.info("数据部分前20字节: {}", dataHex.toString());
|
||||||
|
|
||||||
|
// 打印CRC部分
|
||||||
|
byte[] crcOnly = new byte[crcBytes.length];
|
||||||
|
System.arraycopy(response, headerBytes.length + data.length, crcOnly, 0, crcBytes.length);
|
||||||
|
logger.info("CRC部分ASCII: {}", new String(crcOnly, StandardCharsets.US_ASCII));
|
||||||
|
logger.info("======================================");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("构建数据包失败", e);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String calculateCRC(byte[] data) {
|
||||||
|
byte crc = 0;
|
||||||
|
for (byte b : data) {
|
||||||
|
crc ^= b;
|
||||||
|
}
|
||||||
|
return String.format("%02X", crc & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object processBusinessLogic(String input) {
|
||||||
|
//解析$|MUxxxx|HWxxxx|SWxxxx|UPxx|UQyy|*CRC\r\n
|
||||||
|
/**
|
||||||
|
* 去查software_upgrade表的当前版本的软件硬件号,如果和input解析不一致则升级
|
||||||
|
*去/opt/jkadmin/upgrade下面拿到升级包,调fileService拆包
|
||||||
|
* List<bytes[1024]> packages = fileService.splitFileWithNIO("/opt/jkadmin/upgrade/filename.bin")
|
||||||
|
* byte[] pack = packages.get(0)
|
||||||
|
* String s = new String(pack)
|
||||||
|
* 发送:$|PN00|DA{s}|{CRC}
|
||||||
|
*/
|
||||||
|
logger.info("处理业务数据: {}", input);
|
||||||
|
if (StringUtils.isBlank(input)){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
DeviceUpgrade deviceUpgrade = deviceUpgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
|
||||||
|
if (Objects.isNull(deviceUpgrade)){
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
String fileUrl = UPGRADE_PACKAGE_ROOT_PATH + deviceUpgrade.getFileName();
|
||||||
|
List<byte[]> packages = null;
|
||||||
|
try {
|
||||||
|
packages = fileService.splitFileWithNIO(fileUrl);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("分包发生异常",e);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(packages)){
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
String[] items = input.split("\\|");
|
||||||
|
if (input.contains("HW") && input.contains("SW")){
|
||||||
|
logger.info("集线器回复包含HW和SW,回复第一个数据包");
|
||||||
|
//解析拿到硬件版本号和软件版本号,与device_upgrade表的当前版本对比,如果一致则不用升级,看这个逻辑需不需要吧,目前不加
|
||||||
|
String msg = "$|PN00|DA{s}|{CRC}";
|
||||||
|
byte[] bytes = packages.get(0);
|
||||||
|
//这里我是打算将bytes拼到msg上然后发送给硬件,不知道可不可行?crcHex是1024个字节的异或和
|
||||||
|
|
||||||
|
return buildDataPacket("00",bytes);
|
||||||
|
}else if (input.contains("ST")){
|
||||||
|
String msg = "$|PN{i}|DA{s}|{CRC}";
|
||||||
|
String i = null;
|
||||||
|
String st = null;
|
||||||
|
String pn = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("UP")){
|
||||||
|
i = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("ST")){
|
||||||
|
st = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PN")){
|
||||||
|
pn = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("0".equals(st) && i != null){
|
||||||
|
if ("00".equals(i)){
|
||||||
|
//表示升级数据传输完成,是否需要断开连接
|
||||||
|
logger.info("升级数据传输完成");
|
||||||
|
return "";
|
||||||
|
}else {
|
||||||
|
byte[] bytes = packages.get(Integer.parseInt(i));
|
||||||
|
//这里我是打算将bytes拼到msg上然后发送给硬件,不知道可不可行?crcHex是1024个字节的异或和
|
||||||
|
return buildDataPacket(i,bytes);
|
||||||
|
}
|
||||||
|
}else if ("1".equals(st) && pn != null){
|
||||||
|
logger.info("集线器回复数据接收错误,重发第{}个数据包",pn);
|
||||||
|
byte[] bytes = packages.get(Integer.parseInt(pn));
|
||||||
|
//这里我是打算将bytes拼到msg上然后发送给硬件,不知道可不可行?crcHex是1024个字节的异或和
|
||||||
|
return buildDataPacket(pn,bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
package cn.unizk.config;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.DeviceUpgrade;
|
||||||
|
import cn.unizk.mapper.DeviceUpgradeMapper;
|
||||||
|
import cn.unizk.service.FileService;
|
||||||
|
import cn.unizk.utils.Crc16Util;
|
||||||
|
import cn.unizk.utils.XorUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.dsl.IntegrationFlow;
|
||||||
|
import org.springframework.integration.dsl.IntegrationFlows;
|
||||||
|
import org.springframework.integration.handler.LoggingHandler;
|
||||||
|
import org.springframework.integration.ip.dsl.Tcp;
|
||||||
|
import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory;
|
||||||
|
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
|
||||||
|
import org.springframework.integration.ip.tcp.serializer.ByteArrayRawSerializer;
|
||||||
|
import org.springframework.integration.support.MessageBuilder;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/10/30 14:58
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
public class TcpServerDSLConfig2 {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TcpServerDSLConfig.class);
|
||||||
|
private static final String UPGRADE_PACKAGE_ROOT_PATH = "/opt/jkadmin/upgrade/";
|
||||||
|
// private static final String UPGRADE_PACKAGE_ROOT_PATH = "E:\\opt\\";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileService fileService;
|
||||||
|
@Resource
|
||||||
|
private DeviceUpgradeMapper deviceUpgradeMapper;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TcpNetServerConnectionFactory serverConnectionFactory() {
|
||||||
|
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(55367);
|
||||||
|
factory.setSingleUse(false);
|
||||||
|
factory.setSoTimeout(60_000);
|
||||||
|
factory.setSoKeepAlive(true);
|
||||||
|
factory.setSoLinger(3);
|
||||||
|
factory.setSoReceiveBufferSize(64 * 1024);
|
||||||
|
factory.setSoSendBufferSize(64* 1024);
|
||||||
|
factory.setSoTcpNoDelay(true);
|
||||||
|
ByteArrayCrLfSerializer deserializer = new ByteArrayCrLfSerializer();
|
||||||
|
deserializer.setMaxMessageSize(8192);
|
||||||
|
/*ByteArrayLengthHeaderSerializer ser = new ByteArrayLengthHeaderSerializer();
|
||||||
|
ser.setMaxMessageSize(1024 * 1024);*/
|
||||||
|
factory.setSerializer(new ByteArrayRawSerializer());
|
||||||
|
factory.setDeserializer(deserializer);
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public IntegrationFlow tcpServerFlow(){
|
||||||
|
return IntegrationFlows
|
||||||
|
.from(Tcp.inboundAdapter(serverConnectionFactory()))
|
||||||
|
.log(LoggingHandler.Level.INFO, "TCP接收",
|
||||||
|
message -> "来自 " +
|
||||||
|
message.getHeaders().get("ip_address") +
|
||||||
|
" 的数据")
|
||||||
|
.<byte[],byte[]>transform(payload -> {
|
||||||
|
logger.info("收到字节长度为:{}",payload.length);
|
||||||
|
return payload;
|
||||||
|
})
|
||||||
|
.<byte[],byte[]>transform(this::processBusinessLogic)
|
||||||
|
.handle(Tcp.outboundAdapter(serverConnectionFactory()))
|
||||||
|
.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建数据包响应
|
||||||
|
* @param packageIndex 分包索引(00-31)
|
||||||
|
* @param data 1024字节数据
|
||||||
|
* @return 完整的响应数据包
|
||||||
|
*/
|
||||||
|
private byte[] buildDataPacket(String packageIndex, byte[] data) {
|
||||||
|
|
||||||
|
if (data.length != 1024){
|
||||||
|
logger.error("数据包大小不正确: {}, 应该是1024", data.length);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 协议格式:$|PN{index}|DA{1024字节数据}|{CRC}\r\n
|
||||||
|
String crc = XorUtil.calculateCRC(data);
|
||||||
|
String header = String.format("$|PN%s|DA", packageIndex);
|
||||||
|
byte[] headerBytes = header.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
// CRC部分:|{CRC}
|
||||||
|
String shuxian = "|";
|
||||||
|
byte[] shuxianBytes = shuxian.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
byte[] crc16ToBytes = crc.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
// 完整数据包 = 协议头 + 1024字节文件数据 + CRC
|
||||||
|
byte[] response = new byte[headerBytes.length + data.length + shuxianBytes.length + crc16ToBytes.length];
|
||||||
|
int destPos = 0;
|
||||||
|
|
||||||
|
// 组装
|
||||||
|
System.arraycopy(headerBytes, 0, response, destPos, headerBytes.length);
|
||||||
|
destPos += headerBytes.length;
|
||||||
|
System.arraycopy(data, 0, response, destPos, data.length);
|
||||||
|
destPos += data.length;
|
||||||
|
System.arraycopy(shuxianBytes, 0, response, destPos, shuxianBytes.length);
|
||||||
|
destPos += shuxianBytes.length;
|
||||||
|
System.arraycopy(crc16ToBytes,0,response,destPos,crc16ToBytes.length);
|
||||||
|
logger.info("构建数据包:索引={}, 总长度={}, CRC={},{}",
|
||||||
|
packageIndex, response.length, crc16ToBytes[0],crc16ToBytes[1]);
|
||||||
|
logger.info("========== 发送数据包详细信息 ==========");
|
||||||
|
logger.info("包索引: {}", packageIndex);
|
||||||
|
logger.info("协议头字符串: {}", header);
|
||||||
|
logger.info("协议头字节数: {}", headerBytes.length);
|
||||||
|
logger.info("数据字节数: {}", data.length);
|
||||||
|
logger.info("CRC字符串: {}", crc);
|
||||||
|
logger.info("CRC字节数: {}", crc16ToBytes.length);
|
||||||
|
logger.info("总长度: {}", response.length);
|
||||||
|
// 打印完整十六进制(前200字节和后50字节)
|
||||||
|
StringBuilder hexFull = new StringBuilder();
|
||||||
|
int printLen = Math.min(1036, response.length);
|
||||||
|
for (int i = 0; i < printLen; i++) {
|
||||||
|
hexFull.append(String.format("%02X ", response[i]));
|
||||||
|
if ((i + 1) % 16 == 0) {
|
||||||
|
hexFull.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("前{}字节十六进制:\n{}", printLen, hexFull.toString());
|
||||||
|
|
||||||
|
// 打印协议头部分的ASCII
|
||||||
|
byte[] headerOnly = new byte[headerBytes.length];
|
||||||
|
System.arraycopy(response, 0, headerOnly, 0, headerBytes.length);
|
||||||
|
logger.info("协议头ASCII: {}", new String(headerOnly, StandardCharsets.US_ASCII));
|
||||||
|
|
||||||
|
// 打印数据部分的前20字节
|
||||||
|
StringBuilder dataHex = new StringBuilder();
|
||||||
|
for (int i = 0; i < Math.min(20, data.length); i++) {
|
||||||
|
dataHex.append(String.format("%02X ", data[i]));
|
||||||
|
}
|
||||||
|
logger.info("数据部分前20字节: {}", dataHex.toString());
|
||||||
|
|
||||||
|
// 打印CRC部分
|
||||||
|
byte[] crcOnly = new byte[crc16ToBytes.length];
|
||||||
|
System.arraycopy(response, headerBytes.length + data.length, crcOnly, 0, crc16ToBytes.length);
|
||||||
|
logger.info("CRC部分ASCII: {}", new String(crcOnly, StandardCharsets.US_ASCII));
|
||||||
|
logger.info("======================================");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("构建数据包失败", e);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private byte[] processBusinessLogic(byte[] message) {
|
||||||
|
//解析$|MUxxxx|HWxxxx|SWxxxx|UPxx|UQyy|*CRC\r\n
|
||||||
|
/**
|
||||||
|
* 去查software_upgrade表的当前版本的软件硬件号,如果和input解析不一致则升级
|
||||||
|
*去/opt/jkadmin/upgrade下面拿到升级包,调fileService拆包
|
||||||
|
* List<bytes[1024]> packages = fileService.splitFileWithNIO("/opt/jkadmin/upgrade/filename.bin")
|
||||||
|
* byte[] pack = packages.get(0)
|
||||||
|
* String s = new String(pack)
|
||||||
|
* 发送:$|PN00|DA{s}|{CRC}
|
||||||
|
*/
|
||||||
|
String input = new String(message,StandardCharsets.US_ASCII);
|
||||||
|
logger.info("处理业务数据: {}", input);
|
||||||
|
if (StringUtils.isBlank(input)){
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
DeviceUpgrade deviceUpgrade = deviceUpgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
|
||||||
|
if (Objects.isNull(deviceUpgrade)){
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
String fileUrl = UPGRADE_PACKAGE_ROOT_PATH + deviceUpgrade.getFileName();
|
||||||
|
List<byte[]> packages = null;
|
||||||
|
try {
|
||||||
|
packages = fileService.splitFileWithNIO(fileUrl);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("分包发生异常",e);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(packages)){
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
String[] items = input.split("\\|");
|
||||||
|
if (input.contains("HW") && input.contains("SW")){
|
||||||
|
logger.info("集线器回复包含HW和SW,回复第一个数据包");
|
||||||
|
//解析拿到硬件版本号和软件版本号,与device_upgrade表的当前版本对比,如果一致则不用升级,看这个逻辑需不需要吧,目前不加
|
||||||
|
String msg = "$|PN00|DA{s}|{CRC}";
|
||||||
|
byte[] bytes = packages.get(0);
|
||||||
|
//这里我是打算将bytes拼到msg上然后发送给硬件,不知道可不可行?crcHex是1024个字节的异或和
|
||||||
|
|
||||||
|
return buildDataPacket("01",bytes);
|
||||||
|
}else if (input.contains("ST")){
|
||||||
|
String msg = "$|PN{i}|DA{s}|{CRC}";
|
||||||
|
String i = null;
|
||||||
|
String st = null;
|
||||||
|
String pn = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("UP")){
|
||||||
|
i = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("ST")){
|
||||||
|
st = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PN")){
|
||||||
|
pn = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("0".equals(st) && i != null){
|
||||||
|
if ("00".equals(i)){
|
||||||
|
//表示升级数据传输完成,是否需要断开连接
|
||||||
|
logger.info("升级数据传输完成");
|
||||||
|
return new byte[0];
|
||||||
|
}else {
|
||||||
|
byte[] bytes = packages.get(Integer.parseInt(i)-1);
|
||||||
|
//这里我是打算将bytes拼到msg上然后发送给硬件,不知道可不可行?crcHex是1024个字节的异或和
|
||||||
|
return buildDataPacket(i,bytes);
|
||||||
|
}
|
||||||
|
}else if ("1".equals(st) && pn != null){
|
||||||
|
logger.info("集线器回复数据接收错误,重发第{}个数据包",pn);
|
||||||
|
byte[] bytes = packages.get(Integer.parseInt(pn));
|
||||||
|
//这里我是打算将bytes拼到msg上然后发送给硬件,不知道可不可行?crcHex是1024个字节的异或和
|
||||||
|
return buildDataPacket(pn,bytes);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
String up = null;
|
||||||
|
String pn = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("UP")){
|
||||||
|
up = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PN")){
|
||||||
|
pn = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("00".equals(up) && "00".equals(pn)){
|
||||||
|
logger.info("升级数据传输完成");
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package cn.unizk.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:52
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
public class CacheConstant {
|
||||||
|
public static final String LOGIN_TOKEN_KEY = "login_tokens";
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.unizk.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:51
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
public class Constants {
|
||||||
|
public static final String JWT_TOKEN_KEY = "login_client_key";
|
||||||
|
|
||||||
|
public static final String TOKEN_PREFIX = "Bearer";
|
||||||
|
|
||||||
|
public static final Integer MAX_USERNAME_LENGTH = 15;
|
||||||
|
|
||||||
|
public static final String ALL_PERMISSION = "*:*:*";
|
||||||
|
|
||||||
|
public static final Integer MIN_PASSWORD_LENGTH = 6;
|
||||||
|
|
||||||
|
public static final Integer MAX_PASSWORD_LENGTH = 15;
|
||||||
|
|
||||||
|
public static final String DEVICE_UPGRADE_PACKAGE_ROOT_PATH = "/opt/jkadmin/upgrade/";
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.*;
|
||||||
|
import cn.unizk.entity.vo.*;
|
||||||
|
import cn.unizk.enums.OrderAfterSaleStatus;
|
||||||
|
import cn.unizk.enums.OrderStatus;
|
||||||
|
import cn.unizk.enums.PlatformType;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.MobileAppUserMapper;
|
||||||
|
import cn.unizk.mapper.MobileOrderItemMapper;
|
||||||
|
import cn.unizk.mapper.OrderReviewMapper;
|
||||||
|
import cn.unizk.service.ComboService;
|
||||||
|
import cn.unizk.service.ProductService;
|
||||||
|
import cn.unizk.service.SysOrderService;
|
||||||
|
import cn.unizk.utils.BeanCopyUtils;
|
||||||
|
import cn.unizk.utils.SecurityUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/4 18:16
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin")
|
||||||
|
public class AdminOrderController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysOrderService sysOrderService;
|
||||||
|
@Resource
|
||||||
|
private ComboService comboService;
|
||||||
|
@Resource
|
||||||
|
private MobileOrderItemMapper mobileOrderItemMapper;
|
||||||
|
@Resource
|
||||||
|
private ProductService productService;
|
||||||
|
@Resource
|
||||||
|
private MobileAppUserMapper mobileAppUserMapper;
|
||||||
|
@Resource
|
||||||
|
private OrderReviewMapper reviewMapper;
|
||||||
|
|
||||||
|
@PostMapping("/orders")
|
||||||
|
public Page<MobileOrderVO> orders(@RequestBody UniPage<OrderReqVO> uniPage) {
|
||||||
|
return sysOrderService.orderList(uniPage);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editOrder")
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public ResultData editOrder(@RequestParam("orderId") String orderId, @RequestParam("optionType") Integer optionType) {
|
||||||
|
|
||||||
|
MobileOrder wxOrder = sysOrderService.getById(orderId);
|
||||||
|
if (Objects.isNull(wxOrder)) {
|
||||||
|
throw new ServiceException("该订单不存在");
|
||||||
|
}
|
||||||
|
if (optionType == 1) {
|
||||||
|
//发货
|
||||||
|
if (!OrderStatus.paid.name().equals(wxOrder.getStatus())) {
|
||||||
|
throw new ServiceException(String.format("%s状态订单不支持发货", OrderStatus.valueOf(wxOrder.getStatus()).getValue()));
|
||||||
|
}
|
||||||
|
if (wxOrder.getProductId() == null) {
|
||||||
|
throw new ServiceException("该订单商品为非实体商品,不支持发货");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.shipped.name());
|
||||||
|
sysOrderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
if (optionType == 2) {
|
||||||
|
//核销
|
||||||
|
if (!OrderStatus.paid.name().equals(wxOrder.getStatus()) && !OrderStatus.unverified.name().equals(wxOrder.getStatus())) {
|
||||||
|
throw new ServiceException(String.format("%s状态订单不支持核销", OrderStatus.valueOf(wxOrder.getStatus()).getValue()));
|
||||||
|
}
|
||||||
|
if (wxOrder.getComboId() == null) {
|
||||||
|
throw new ServiceException("该订单商品为实体商品,不支持核销");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.verified.name());
|
||||||
|
sysOrderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
/*if (optionType == 3){
|
||||||
|
if (!OrderStatus.request_refund.name().equals(wxOrder.getStatus())){
|
||||||
|
throw new ServiceException("该订单非申请退款,不能做退款操作!");
|
||||||
|
}
|
||||||
|
if (OrderStatus.refunded.name().equals(wxOrder.getStatus())){
|
||||||
|
throw new ServiceException("该订单已做退款处理");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.refunded.name());
|
||||||
|
sysOrderService.updateById(wxOrder);
|
||||||
|
}*/
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getOrderStatistics")
|
||||||
|
public Map<String, Long> getOrderStatistics() {
|
||||||
|
List<MobileOrder> wxOrders = sysOrderService.getBaseMapper().selectList(null);
|
||||||
|
Map<String, Long> map = new HashMap<>();
|
||||||
|
map.put("A", (long) wxOrders.size());
|
||||||
|
long p = wxOrders.stream().filter(o -> o.getStoreId() == null).count();
|
||||||
|
map.put("P", p);
|
||||||
|
long s = wxOrders.stream().filter(o -> o.getStoreId() != null).count();
|
||||||
|
map.put("S", s);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/orderDetail")
|
||||||
|
public MobileOrderDetailVO detail(@RequestParam("orderId") String orderId) {
|
||||||
|
MobileOrderDetailVO vo = new MobileOrderDetailVO();
|
||||||
|
MobileOrder wxOrder = sysOrderService.getById(orderId);
|
||||||
|
BeanUtils.copyProperties(wxOrder, vo);
|
||||||
|
if (vo.getComboId() != null) {
|
||||||
|
List<MobileOrderItemVO> list = new ArrayList<>();
|
||||||
|
Combo combo = comboService.getById(vo.getComboId());
|
||||||
|
MobileOrderItemVO product = new MobileOrderItemVO();
|
||||||
|
product.setImage(combo.getImage());
|
||||||
|
product.setProductName(combo.getComboName());
|
||||||
|
product.setSingleProductPrice(combo.getComboPrice());
|
||||||
|
list.add(product);
|
||||||
|
vo.setOrderItemVOS(list);
|
||||||
|
} else {
|
||||||
|
List<MobileOrderItem> wxOrderItems = mobileOrderItemMapper.selectList(new LambdaQueryWrapper<MobileOrderItem>().eq(MobileOrderItem::getMobileOrderId, vo.getOrderId()));
|
||||||
|
if (CollectionUtils.isNotEmpty(wxOrderItems)){
|
||||||
|
Collection<MobileOrderItemVO> itemVOS = BeanCopyUtils.copyArrays(wxOrderItems, MobileOrderItemVO::new);
|
||||||
|
for (MobileOrderItemVO itemVO : itemVOS) {
|
||||||
|
if (itemVO.getProductId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JkProduct jkProduct = productService.getById(itemVO.getProductId());
|
||||||
|
itemVO.setProductName(jkProduct.getProductName());
|
||||||
|
itemVO.setImage(jkProduct.getProductImage());
|
||||||
|
itemVO.setSingleProductPrice(jkProduct.getProductPrice());
|
||||||
|
}
|
||||||
|
vo.setOrderItemVOS((List<MobileOrderItemVO>) itemVOS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MobileAppUser one = mobileAppUserMapper.selectById(vo.getMobileUserId());
|
||||||
|
vo.setMobileAppUser(one);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/agreeRefund")
|
||||||
|
public ResultData refund(@RequestParam("orderId") String orderId,@RequestParam("platformType") String platformType) {
|
||||||
|
if (!PlatformType.WECHAT_MP.name().equals(platformType) && !PlatformType.APP.name().equals(platformType)){
|
||||||
|
throw new ServiceException("未知的平台类型");
|
||||||
|
}
|
||||||
|
return sysOrderService.agreeRefund(orderId,platformType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/afterSales")
|
||||||
|
public Page<MobileOrderVO> afterSales(@RequestBody UniPage<OrderReqVO> uniPage) {
|
||||||
|
return sysOrderService.afterSale(uniPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getDeliveryTotal")
|
||||||
|
public Map<String, Long> getDeliveryTotal() {
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
Map<String, Long> map = new HashMap<>();
|
||||||
|
Long ps = sysOrderService.getBaseMapper().selectCount(new LambdaQueryWrapper<MobileOrder>().eq(MobileOrder::getDeliveryWay, "配送")
|
||||||
|
.eq(MobileOrder::getAfterSaleStatus, 0));
|
||||||
|
map.put("配送", ps);
|
||||||
|
Long zt = sysOrderService.getBaseMapper().selectCount(new LambdaQueryWrapper<MobileOrder>().eq(MobileOrder::getDeliveryWay, "自提")
|
||||||
|
.eq(MobileOrder::getAfterSaleStatus, 0));
|
||||||
|
map.put("核销", zt);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/refundRefusal")
|
||||||
|
public boolean refundRefusal(@RequestBody MobileOrder order) {
|
||||||
|
MobileOrder wxOrder = sysOrderService.getById(order.getOrderId());
|
||||||
|
if (Objects.isNull(wxOrder)) {
|
||||||
|
throw new ServiceException("无此订单");
|
||||||
|
}
|
||||||
|
wxOrder.setRejectReason(order.getRejectReason());
|
||||||
|
wxOrder.setAfterSaleStatus(OrderAfterSaleStatus.REJECT_TUI_KUAN.getKey());
|
||||||
|
return sysOrderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getOrderReview")
|
||||||
|
public List<OrderReview> getOrderReview(@RequestParam("orderId") String orderId) {
|
||||||
|
return reviewMapper.selectList(new LambdaQueryWrapper<OrderReview>().eq(OrderReview::getOrderId, orderId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @PostMapping("/appOrders")
|
||||||
|
public Page<MobileOrderVO> appOrders(@RequestBody UniPage<OrderReqVO> uniPage) {
|
||||||
|
Page<MobileOrderVO> page = (Page<MobileOrderVO>) uniPage.getPage();
|
||||||
|
return page;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.dto.LoginUser;
|
||||||
|
import cn.unizk.entity.po.Device;
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.service.DeviceService;
|
||||||
|
import cn.unizk.utils.SecurityUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/26 16:48
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/store/device")
|
||||||
|
public class ChildDeviceController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceService deviceService;
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Page<Device> page(@RequestParam(value = "keyword",required = false) String keyword,
|
||||||
|
UniPage uniPage){
|
||||||
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
|
if (Objects.isNull(loginUser) || Objects.isNull(loginUser.getSysUser())){
|
||||||
|
throw new ServiceException(401,"登录已过期");
|
||||||
|
}
|
||||||
|
if (loginUser.getSysUser().getStoreId() == null){
|
||||||
|
return new Page<>();
|
||||||
|
}
|
||||||
|
Page<Device> page = new Page<>(uniPage.getCurrentPage(),uniPage.getPageSize());
|
||||||
|
return deviceService.page(page,new LambdaQueryWrapper<Device>()
|
||||||
|
.eq(Device::getStoreId,loginUser.getSysUser().getStoreId())
|
||||||
|
.and(StringUtils.isNotBlank(keyword),wrapper -> {
|
||||||
|
wrapper.eq(StringUtils.isNotBlank(keyword),Device::getMuid,keyword)
|
||||||
|
.or()
|
||||||
|
.eq(StringUtils.isNotBlank(keyword),Device::getDeviceId,keyword);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getTotal")
|
||||||
|
public long getTotal(){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (Objects.isNull(sysUser) || sysUser.getStoreId() == null){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return deviceService.count(new LambdaQueryWrapper<Device>().eq(Device::getStoreId,sysUser.getStoreId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/forcePaySwitch")
|
||||||
|
public ResultData forcePaySwitch(@RequestParam("deviceId") String deviceId,@RequestParam("forcePay") Integer forcePay){
|
||||||
|
if (forcePay != 0 && forcePay != 1){
|
||||||
|
throw new ServiceException("参数不合法");
|
||||||
|
}
|
||||||
|
Device device = new Device();
|
||||||
|
device.setDeviceId(deviceId);
|
||||||
|
device.setForcePay(forcePay);
|
||||||
|
if (forcePay == 1){
|
||||||
|
device.setStatus("0");
|
||||||
|
}else {
|
||||||
|
device.setStatus("1");
|
||||||
|
}
|
||||||
|
return deviceService.updateById(device) ? ResultData.success() : ResultData.failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,468 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.entity.dto.CashOutDTO;
|
||||||
|
import cn.unizk.entity.dto.CashOutResponse;
|
||||||
|
import cn.unizk.entity.po.*;
|
||||||
|
import cn.unizk.entity.vo.*;
|
||||||
|
import cn.unizk.enums.OrderAfterSaleStatus;
|
||||||
|
import cn.unizk.enums.OrderStatus;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.CashOutRecordMapper;
|
||||||
|
import cn.unizk.mapper.DeviceUsageRecordMapper;
|
||||||
|
import cn.unizk.mapper.StoreAccountMapper;
|
||||||
|
import cn.unizk.service.*;
|
||||||
|
import cn.unizk.utils.HttpUtil;
|
||||||
|
import cn.unizk.utils.QRcodeUtil;
|
||||||
|
import cn.unizk.utils.SecurityUtils;
|
||||||
|
import cn.unizk.utils.ServletUtils;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/26 10:46
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@Slf4j
|
||||||
|
@RequestMapping("/pc/store")
|
||||||
|
public class ChildStoreController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceService deviceService;
|
||||||
|
@Resource
|
||||||
|
private WxAuthService wxAuthService;
|
||||||
|
@Resource
|
||||||
|
private BusinessChannelService businessChannelService;
|
||||||
|
@Resource
|
||||||
|
private StoreService storeService;
|
||||||
|
@Resource
|
||||||
|
private ChildStoreService childStoreService;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageRecordMapper deviceUsageRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private SysOrderService orderService;
|
||||||
|
@Resource
|
||||||
|
private PhysioService physioService;
|
||||||
|
@Resource
|
||||||
|
private StoreAccountMapper storeAccountMapper;
|
||||||
|
@Resource
|
||||||
|
private CashOutRecordMapper cashOutRecordMapper;
|
||||||
|
|
||||||
|
@PostMapping("/addAccountData")
|
||||||
|
public ResultData addAccountData(@Valid @RequestBody XunfuAccountVO vo){
|
||||||
|
if (Objects.isNull(vo)){
|
||||||
|
throw new ServiceException("参数不正确");
|
||||||
|
}
|
||||||
|
List<XunfuAccountImage> images = vo.getImages();
|
||||||
|
List<String> imageTypes = Lists.newArrayList("idCardFront","idCardBack","personWithIdCard","bankCard",
|
||||||
|
"license","openAccountLicenses");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getAppletQrCode")
|
||||||
|
public void getAppletQrCode(HttpServletResponse response, @RequestParam(value = "type",required = false) String type){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
JkStore jkStore = storeService.getById(sysUser.getStoreId());
|
||||||
|
if (Objects.isNull(jkStore)){
|
||||||
|
log.error("无此门店:storeId={}",sysUser.toString());
|
||||||
|
throw new ServiceException("服务异常");
|
||||||
|
}
|
||||||
|
String accessToken = wxAuthService.getAccessToken();
|
||||||
|
String url = String.format("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s",accessToken);
|
||||||
|
log.info("url={}",url);
|
||||||
|
JSONObject jsonBody = JSONObject.of();
|
||||||
|
Integer channelId = jkStore.getChannelId();
|
||||||
|
jsonBody.put("scene",channelId);
|
||||||
|
// jsonBody.put("check_path",false);
|
||||||
|
// jsonBody.put("env_version","trial");
|
||||||
|
jsonBody.put("width",280);
|
||||||
|
byte[] bytes = HttpUtil.postRtnBytes(url, null, jsonBody);
|
||||||
|
if (bytes == null || bytes.length == 0){
|
||||||
|
ServletUtils.renderString(response,"qrcode res is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String fileName = "";
|
||||||
|
if (channelId != null){
|
||||||
|
BusinessChannel businessChannel = businessChannelService.getById(channelId);
|
||||||
|
fileName = Objects.nonNull(businessChannel) ? businessChannel.getChannelName() : "";
|
||||||
|
}
|
||||||
|
// response.setContentType("image/jpeg");
|
||||||
|
response.setContentLength(bytes.length);
|
||||||
|
if ("download".equals(type)){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=渠道商-"+channelId+now+".png");
|
||||||
|
}
|
||||||
|
try (OutputStream os = response.getOutputStream()) {
|
||||||
|
os.write(bytes);
|
||||||
|
os.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/devicePage")
|
||||||
|
public Page<Device> devicePage(UniPage uniPage,@RequestParam(value = "keyword",required = false) String keyword){
|
||||||
|
|
||||||
|
Page<Device> page = new Page<>(uniPage.getCurrentPage(),uniPage.getPageSize());
|
||||||
|
if (StringUtils.isNotBlank(keyword)){
|
||||||
|
LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(Device::getDeviceId,keyword).or().eq(Device::getMuid,keyword);
|
||||||
|
return deviceService.page(page,wrapper);
|
||||||
|
}else {
|
||||||
|
return deviceService.page(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/usageRecord")
|
||||||
|
public Page<DeviceUsageRecordVO> usageRecord(@RequestParam("deviceId") String deviceId,UniPage uniPage){
|
||||||
|
Page<DeviceUsageRecord> page = new Page<>(uniPage.getCurrentPage(),uniPage.getPageSize());
|
||||||
|
LambdaQueryWrapper<DeviceUsageRecord> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(DeviceUsageRecord::getDeviceId,deviceId).orderByDesc(DeviceUsageRecord::getStartTime);
|
||||||
|
Page<DeviceUsageRecord> recordPage = deviceUsageRecordMapper.selectPage(page, wrapper);
|
||||||
|
List<DeviceUsageRecord> records = recordPage.getRecords();
|
||||||
|
List<DeviceUsageRecordVO> voList = new ArrayList<>();
|
||||||
|
for (DeviceUsageRecord record : records) {
|
||||||
|
DeviceUsageRecordVO vo = new DeviceUsageRecordVO();
|
||||||
|
BeanUtils.copyProperties(record,vo);
|
||||||
|
long minutes = Duration.between(record.getStartTime(), record.getEndTime()).toMinutes();
|
||||||
|
vo.setUseDuration(minutes);
|
||||||
|
voList.add(vo);
|
||||||
|
}
|
||||||
|
Page<DeviceUsageRecordVO> voPage = new Page<>();
|
||||||
|
voPage.setRecords(voList);
|
||||||
|
voPage.setCurrent(recordPage.getCurrent());
|
||||||
|
voPage.setSize(recordPage.getSize());
|
||||||
|
voPage.setTotal(recordPage.getTotal());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/agreeRefund")
|
||||||
|
public ResultData refund(@RequestParam("orderId") String orderId){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
MobileOrder wxOrder = orderService.getById(orderId);
|
||||||
|
if (Objects.isNull(wxOrder)){
|
||||||
|
throw new ServiceException(String.format("订单不存在,订单号:%s",orderId));
|
||||||
|
}
|
||||||
|
if (wxOrder.getStoreId() == null || !sysUser.getStoreId().equals(wxOrder.getStoreId())){
|
||||||
|
throw new ServiceException("警告:越权操作!");
|
||||||
|
}
|
||||||
|
return orderService.refund(wxOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/orderPage")
|
||||||
|
public Page<MobileOrderVO> orders(@RequestBody UniPage<OrderReqVO> uniPage){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException("请求不合法");
|
||||||
|
}
|
||||||
|
OrderReqVO queryBody = uniPage.getQueryBody();
|
||||||
|
if (queryBody == null){
|
||||||
|
queryBody = new OrderReqVO();
|
||||||
|
}
|
||||||
|
queryBody.setStoreId(sysUser.getStoreId());
|
||||||
|
return orderService.orderList(uniPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editOrder")
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public ResultData editOrder(@RequestParam("orderId") String orderId,@RequestParam("optionType") Integer optionType){
|
||||||
|
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
MobileOrder wxOrder = orderService.getById(orderId);
|
||||||
|
if (Objects.isNull(wxOrder)){
|
||||||
|
throw new ServiceException("该订单不存在");
|
||||||
|
}
|
||||||
|
if (sysUser == null || !sysUser.getStoreId().equals(wxOrder.getStoreId())){
|
||||||
|
throw new ServiceException("非法请求");
|
||||||
|
}
|
||||||
|
if (optionType == 1){
|
||||||
|
//发货
|
||||||
|
if (!OrderStatus.paid.name().equals(wxOrder.getStatus())){
|
||||||
|
throw new ServiceException(String.format("%s状态订单不支持发货",OrderStatus.valueOf(wxOrder.getStatus()).getValue()));
|
||||||
|
}
|
||||||
|
if (wxOrder.getProductId() == null) {
|
||||||
|
throw new ServiceException("该订单商品为非实体商品,不支持发货");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.shipped.name());
|
||||||
|
orderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
if (optionType == 2){
|
||||||
|
//核销
|
||||||
|
if (!OrderStatus.paid.name().equals(wxOrder.getStatus()) && !OrderStatus.unverified.name().equals(wxOrder.getStatus())){
|
||||||
|
throw new ServiceException(String.format("%s状态订单不支持核销",OrderStatus.valueOf(wxOrder.getStatus()).getValue()));
|
||||||
|
}
|
||||||
|
if (wxOrder.getComboId() == null){
|
||||||
|
throw new ServiceException("该订单商品为实体商品,不支持核销");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.verified.name());
|
||||||
|
orderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
/*if (optionType == 3){
|
||||||
|
if (!OrderStatus.request_refund.name().equals(wxOrder.getStatus())){
|
||||||
|
throw new ServiceException("该订单非申请退款,不能做退款操作!");
|
||||||
|
}
|
||||||
|
if (OrderStatus.refunded.name().equals(wxOrder.getStatus())){
|
||||||
|
throw new ServiceException("该订单已做退款处理");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.refunded.name());
|
||||||
|
orderService.updateById(wxOrder);
|
||||||
|
}*/
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getDeliveryTotal")
|
||||||
|
public Map<String,Long> getDeliveryTotal(){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
Map<String,Long> map = new HashMap<>();
|
||||||
|
Long ps = orderService.getBaseMapper().selectCount(new LambdaQueryWrapper<MobileOrder>().eq(MobileOrder::getDeliveryWay, "配送").eq(MobileOrder::getStoreId,sysUser.getStoreId()));
|
||||||
|
map.put("配送",ps);
|
||||||
|
Long zt = orderService.getBaseMapper().selectCount(new LambdaQueryWrapper<MobileOrder>().eq(MobileOrder::getDeliveryWay, "自提").eq(MobileOrder::getStoreId,sysUser.getStoreId()));
|
||||||
|
map.put("核销",zt);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/afterSales")
|
||||||
|
public Page<MobileOrderVO> afterSale(@RequestBody UniPage<OrderReqVO> uniPage){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException("请求不合法");
|
||||||
|
}
|
||||||
|
OrderReqVO queryBody = uniPage.getQueryBody();
|
||||||
|
if (queryBody == null){
|
||||||
|
queryBody = new OrderReqVO();
|
||||||
|
}
|
||||||
|
queryBody.setStoreId(sysUser.getStoreId());
|
||||||
|
return orderService.afterSale(uniPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/refundRefusal")
|
||||||
|
public boolean refundRefusal(@RequestBody MobileOrder order){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
MobileOrder wxOrder = orderService.getById(order.getOrderId());
|
||||||
|
if (Objects.isNull(wxOrder)){
|
||||||
|
throw new ServiceException("无此订单");
|
||||||
|
}
|
||||||
|
if (sysUser.getStoreId() == null || !sysUser.getStoreId().equals(wxOrder.getStoreId())){
|
||||||
|
throw new ServiceException("非法请求");
|
||||||
|
}
|
||||||
|
wxOrder.setRejectReason(order.getRejectReason());
|
||||||
|
wxOrder.setAfterSaleStatus(OrderAfterSaleStatus.REJECT_TUI_KUAN.getKey());
|
||||||
|
return orderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addPhysio")
|
||||||
|
public boolean addPhysio(@RequestBody JkPhysio jkPhysio){
|
||||||
|
return physioService.save(jkPhysio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/physioList")
|
||||||
|
public Page<JkPhysio> physioList(@RequestBody UniPage<PhysioVO> uniPage){
|
||||||
|
Integer storeId = authVerify();
|
||||||
|
Page<JkPhysio> page = (Page<JkPhysio>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<JkPhysio> queryWrapper = uniPage.buildQueryWrapper(q -> {
|
||||||
|
LambdaQueryWrapper<JkPhysio> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(JkPhysio::getStoreId, storeId);
|
||||||
|
wrapper.and(StringUtils.isNotBlank(q.getKeyword()), r -> {
|
||||||
|
r.eq(JkPhysio::getIdcard, q.getKeyword())
|
||||||
|
.or()
|
||||||
|
.eq(JkPhysio::getPhysioTel, q.getKeyword())
|
||||||
|
.or()
|
||||||
|
.eq(JkPhysio::getPhysioName, q.getKeyword());
|
||||||
|
});
|
||||||
|
wrapper.between(q.getCreateTime() != null, JkPhysio::getCreateTime, q.getSearchStartTime(), q.getSearchEndTime());
|
||||||
|
wrapper.eq(q.getAudit() != null, JkPhysio::getAudit, q.getAudit());
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
return physioService.page(page,queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editPhysio")
|
||||||
|
public Boolean editPhysio(@RequestBody JkPhysio jkPhysio){
|
||||||
|
jkPhysio.setAudit(0);
|
||||||
|
return physioService.updateById(jkPhysio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deletePhysio")
|
||||||
|
public boolean deletePhysio(@RequestParam("id") Integer id){
|
||||||
|
Integer storeId = authVerify();
|
||||||
|
JkPhysio byId = physioService.getById(id);
|
||||||
|
if (Objects.isNull(byId) || !storeId.equals(byId.getStoreId())){
|
||||||
|
throw new ServiceException(403,"非法访问");
|
||||||
|
}
|
||||||
|
return physioService.removeById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer authVerify(){
|
||||||
|
Integer storeId = SecurityUtils.getSysUser().getStoreId();
|
||||||
|
if (storeId == null){
|
||||||
|
throw new ServiceException(403,"非法访问");
|
||||||
|
}
|
||||||
|
return storeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getAppScanPayQRCode")
|
||||||
|
public void getAppScanPayQRCode(HttpServletResponse response,@RequestParam("deviceId") String deviceId,
|
||||||
|
@RequestParam("route") String route){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException(403,"非法访问");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(deviceId)){
|
||||||
|
throw new ServiceException("deviceId cannot be empty!");
|
||||||
|
}
|
||||||
|
Device device = deviceService.getById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
throw new ServiceException("ID->"+deviceId + "not exist");
|
||||||
|
}
|
||||||
|
String url = "uri=" + route + "&deviceId=" + deviceId + "&storeId=" + sysUser.getStoreId();
|
||||||
|
QRcodeUtil.generateQrcode(response,url,null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getScanPayQRCode")
|
||||||
|
public void getScanPayQRCode(HttpServletResponse response,@RequestParam("deviceId") String deviceId) throws UnsupportedEncodingException {
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException(403,"非法访问");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(deviceId)){
|
||||||
|
throw new ServiceException("deviceId cannot be empty!");
|
||||||
|
}
|
||||||
|
Device device = deviceService.getById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
throw new ServiceException("ID->"+deviceId + "not exist");
|
||||||
|
}
|
||||||
|
String accessToken = wxAuthService.getAccessToken();
|
||||||
|
String url = String.format("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s",accessToken);
|
||||||
|
log.info("url={}",url);
|
||||||
|
JSONObject jsonBody = JSONObject.of();
|
||||||
|
String scene = sysUser.getStoreId() + "$" + deviceId;
|
||||||
|
jsonBody.put("scene",scene);
|
||||||
|
if (device.getForcePay() == 0){
|
||||||
|
deviceId = "0";
|
||||||
|
}else {
|
||||||
|
jsonBody.put("page","pages/order/devicePayOnce");
|
||||||
|
}
|
||||||
|
jsonBody.put("width",280);
|
||||||
|
byte[] bytes = HttpUtil.postRtnBytes(url, null, jsonBody);
|
||||||
|
if (bytes == null || bytes.length == 0){
|
||||||
|
ServletUtils.renderString(response,"qrcode res is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setContentLength(bytes.length);
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String fileName = "设备ID-" + deviceId + "-" + now + ".png";
|
||||||
|
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
|
||||||
|
.replaceAll("\\+", "%20");
|
||||||
|
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
|
||||||
|
try (OutputStream os = response.getOutputStream()) {
|
||||||
|
os.write(bytes);
|
||||||
|
os.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getGrfScanPayQRCode")
|
||||||
|
public void getGrfScanPayQRCode(HttpServletResponse response,@RequestParam("deviceId") String deviceId) throws UnsupportedEncodingException {
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException(403,"非法访问");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(deviceId)){
|
||||||
|
throw new ServiceException("deviceId cannot be empty!");
|
||||||
|
}
|
||||||
|
Device device = deviceService.getById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
throw new ServiceException("ID->"+deviceId + "not exist");
|
||||||
|
}
|
||||||
|
String accessToken = wxAuthService.getAccessToken();
|
||||||
|
String url = String.format("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s",accessToken);
|
||||||
|
log.info("url={}",url);
|
||||||
|
JSONObject jsonBody = JSONObject.of();
|
||||||
|
String scene = sysUser.getStoreId() + "$" + deviceId;
|
||||||
|
jsonBody.put("scene",scene);
|
||||||
|
if (device.getForcePay() == 0){
|
||||||
|
deviceId = "0";
|
||||||
|
}else {
|
||||||
|
jsonBody.put("page","pages/memberRecharge/index");
|
||||||
|
}
|
||||||
|
jsonBody.put("width",280);
|
||||||
|
byte[] bytes = HttpUtil.postRtnBytes(url, null, jsonBody);
|
||||||
|
if (bytes == null || bytes.length == 0){
|
||||||
|
ServletUtils.renderString(response,"qrcode res is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setContentLength(bytes.length);
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String fileName = "设备ID-" + deviceId + "-" + now + ".png";
|
||||||
|
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
|
||||||
|
.replaceAll("\\+", "%20");
|
||||||
|
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
|
||||||
|
try (OutputStream os = response.getOutputStream()) {
|
||||||
|
os.write(bytes);
|
||||||
|
os.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/accounts")
|
||||||
|
public List<StoreAccountVO> accounts(){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException(403,"权限不足");
|
||||||
|
}
|
||||||
|
List<StoreAccount> storeAccounts = storeAccountMapper.selectList(new LambdaQueryWrapper<StoreAccount>().eq(StoreAccount::getStoreId,sysUser.getStoreId()));
|
||||||
|
List<StoreAccountVO> vos = new ArrayList<>();
|
||||||
|
for (StoreAccount storeAccount : storeAccounts) {
|
||||||
|
StoreAccountVO accountVO = new StoreAccountVO();
|
||||||
|
BeanUtils.copyProperties(storeAccount,accountVO);
|
||||||
|
JkStore jkStore = storeService.getById(storeAccount.getStoreId());
|
||||||
|
if (jkStore != null){
|
||||||
|
accountVO.setAccountName(jkStore.getStoreName());
|
||||||
|
}
|
||||||
|
vos.add(accountVO);
|
||||||
|
}
|
||||||
|
return vos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/cashOut")
|
||||||
|
public CashOutResponse cashOut(@RequestBody CashOutDTO dto){
|
||||||
|
return childStoreService.profitSharingPay(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/cashOutRecord")
|
||||||
|
public Page<CashOutRecord> cashOutRecordPage(@RequestBody UniPage<CashOutRecord> uniPage){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null){
|
||||||
|
throw new ServiceException(403,"权限不足");
|
||||||
|
}
|
||||||
|
Page<CashOutRecord> page = (Page<CashOutRecord>) uniPage.getPage();
|
||||||
|
return cashOutRecordMapper.selectPage(page,new LambdaQueryWrapper<CashOutRecord>().eq(CashOutRecord::getStoreId,sysUser.getStoreId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Combo;
|
||||||
|
import cn.unizk.entity.po.SubHealthDietaryRegulation;
|
||||||
|
import cn.unizk.entity.vo.ComboVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.enums.OrderStatus;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.SubHealthDietaryRegulationMapper;
|
||||||
|
import cn.unizk.service.ComboService;
|
||||||
|
import cn.unizk.service.SysOrderService;
|
||||||
|
import cn.unizk.utils.AESUtil;
|
||||||
|
import cn.unizk.utils.SendSmsUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/11 12:00
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/h5")
|
||||||
|
public class H5ComboController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysOrderService orderService;
|
||||||
|
@Resource
|
||||||
|
private ComboService comboService;
|
||||||
|
/*@Resource
|
||||||
|
private WxUserService wxUserService;*/
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("kryoRedisTemplate")
|
||||||
|
private RedisTemplate<String,Object> redisTemplate;
|
||||||
|
@Resource
|
||||||
|
private SubHealthDietaryRegulationMapper regulationMapper;
|
||||||
|
|
||||||
|
/* @GetMapping("/getCombos")
|
||||||
|
public List<ComboVO> getCombos(HttpServletRequest request, @RequestParam("deviceId") String deviceId, @RequestParam("phoneNumber") String phoneNumber,
|
||||||
|
@RequestParam("code") String code){
|
||||||
|
validatePhoneCode(phoneNumber,code);
|
||||||
|
WxUser one = wxUserService.getOne(new LambdaQueryWrapper<WxUser>().eq(WxUser::getPhoneNumber, phoneNumber));
|
||||||
|
if (Objects.isNull(one)){
|
||||||
|
throw new ServiceException("您不是吉客中医微信小程序的用户");
|
||||||
|
}
|
||||||
|
List<WxOrder> wxOrders = orderService.getBaseMapper().selectList(new LambdaQueryWrapper<WxOrder>()
|
||||||
|
.eq(WxOrder::getOpenid, one.getOpenid())
|
||||||
|
.eq(WxOrder::getDeviceId, deviceId));
|
||||||
|
if (CollectionUtils.isEmpty(wxOrders)){
|
||||||
|
throw new ServiceException("抱歉,您在此设备上没有购买套餐");
|
||||||
|
}
|
||||||
|
String encrypt = phoneNumber;
|
||||||
|
try {
|
||||||
|
encrypt = AESUtil.encrypt(phoneNumber);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("手机号加密异常",e);
|
||||||
|
}
|
||||||
|
request.getSession().setAttribute("session",encrypt);
|
||||||
|
List<ComboVO> list = new ArrayList<>();
|
||||||
|
for (WxOrder wxOrder : wxOrders) {
|
||||||
|
Combo combo = comboService.getById(wxOrder.getComboId());
|
||||||
|
ComboVO vo = new ComboVO();
|
||||||
|
BeanUtils.copyProperties(combo,vo);
|
||||||
|
vo.setOrderId(wxOrder.getOrderId());
|
||||||
|
list.add(vo);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/sendPhoneCode")
|
||||||
|
public ResultData sendPhoneCode(@RequestParam("phoneNumber") String phoneNumber){
|
||||||
|
String code = RandomStringUtils.randomNumeric(6);
|
||||||
|
try {
|
||||||
|
String s = SendSmsUtil.sendPhoneCode(phoneNumber, code);
|
||||||
|
JSONObject res = JSONObject.parseObject(s);
|
||||||
|
Integer statusCode = res.getInteger("statusCode");
|
||||||
|
if (statusCode != null && statusCode == 200){
|
||||||
|
redisTemplate.opsForValue().set("h5:"+phoneNumber,code,300, TimeUnit.SECONDS);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
return ResultData.failure(500,"验证码发送失败");
|
||||||
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new ServiceException("验证码发送失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/writeOff")
|
||||||
|
public boolean writeOff(HttpServletRequest request,@RequestParam("orderId") String orderId){
|
||||||
|
String encrypt = (String) request.getSession().getAttribute("session");
|
||||||
|
if (StringUtils.isBlank(encrypt)){
|
||||||
|
throw new ServiceException("No permission");
|
||||||
|
}
|
||||||
|
String decrypt = encrypt;
|
||||||
|
try {
|
||||||
|
decrypt = AESUtil.decrypt(encrypt);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("手机号解密异常",e);
|
||||||
|
}
|
||||||
|
WxOrder wxOrder = orderService.getOrderByIdAndPhone(orderId, decrypt);
|
||||||
|
if (Objects.isNull(wxOrder)){
|
||||||
|
throw new ServiceException("No permission");
|
||||||
|
}
|
||||||
|
wxOrder.setStatus(OrderStatus.verified.name());
|
||||||
|
return orderService.updateById(wxOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getAuthQrcode")
|
||||||
|
public void getAuthQrcode(HttpServletResponse response){
|
||||||
|
// QRcodeUtil.generateQrcode(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validatePhoneCode(String phone,String code){
|
||||||
|
String cacheCode = (String) redisTemplate.opsForValue().get("h5:"+phone);
|
||||||
|
if (StringUtils.isBlank(cacheCode) || !cacheCode.equals(code)){
|
||||||
|
throw new ServiceException("验证码错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/checkSubHealth")
|
||||||
|
public String checkSub(){
|
||||||
|
List<String> num = new ArrayList<>();
|
||||||
|
int i = 1;
|
||||||
|
while (i < 123){
|
||||||
|
num.add(String.valueOf(i));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (String s : num) {
|
||||||
|
SubHealthDietaryRegulation regulation = regulationMapper.selectById(s);
|
||||||
|
if (Objects.isNull(regulation)){
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "none";
|
||||||
|
}*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.constant.VideoUploadConstants;
|
||||||
|
import cn.unizk.entity.po.Course;
|
||||||
|
import cn.unizk.entity.vo.CourseVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.service.HuaWeiYunService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/3/6 15:09
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin/obs")
|
||||||
|
@Slf4j
|
||||||
|
public class HuaWeiYunController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private HuaWeiYunService huaWeiYunService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义场景生成临时url文档地址:https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0901.html#obs_21_0901__section11191986541
|
||||||
|
* @param file
|
||||||
|
* @param objName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
@PostMapping("/uploadVideo")
|
||||||
|
public ResultData uploadVideo(@RequestParam("file")MultipartFile file,@RequestParam("objName") String objName
|
||||||
|
){
|
||||||
|
if (file == null || file.isEmpty()){
|
||||||
|
throw new ServiceException("上传文件不能为空!");
|
||||||
|
}
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (originalFilename == null){
|
||||||
|
throw new ServiceException("无法获取文件名!");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(objName)){
|
||||||
|
throw new ServiceException("objName cannot be null");
|
||||||
|
}
|
||||||
|
String extension = "";
|
||||||
|
int dotIndex = originalFilename.lastIndexOf(".");
|
||||||
|
if (dotIndex > 0) {
|
||||||
|
extension = originalFilename.substring(dotIndex + 1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!"mp4".equals(extension)) {
|
||||||
|
throw new ServiceException("不支持的文件格式: " + extension + ",仅支持 .mp4");
|
||||||
|
}
|
||||||
|
String contentType = file.getContentType();
|
||||||
|
if (contentType == null || !isAllowedMimeType(contentType)) {
|
||||||
|
throw new ServiceException("文件内容类型不合法:"+contentType);
|
||||||
|
}
|
||||||
|
long maxSize = 500 * 1024 * 1024;
|
||||||
|
if (file.getSize() > maxSize) {
|
||||||
|
throw new ServiceException("文件大小超过最大限制500MB");
|
||||||
|
}
|
||||||
|
String objectKey = objName + "/" + originalFilename;
|
||||||
|
String s = huaWeiYunService.uploadVideo(file, objectKey);
|
||||||
|
ResultData resultData = new ResultData();
|
||||||
|
resultData.setData(s);
|
||||||
|
resultData.setCode(200);
|
||||||
|
return resultData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAllowedMimeType(String contentType) {
|
||||||
|
// 标准化 contentType (去除 charset 等参数)
|
||||||
|
String mainType = contentType.split(";")[0].trim().toLowerCase();
|
||||||
|
return VideoUploadConstants.ALLOWED_MIME_TYPES.contains(mainType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.entity.dto.IsoDTO;
|
||||||
|
import cn.unizk.entity.po.Device;
|
||||||
|
import cn.unizk.mapper.DeviceMapper;
|
||||||
|
import cn.unizk.mapper.SysDictMapper;
|
||||||
|
import cn.unizk.utils.AESUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/10/20 18:21
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/")
|
||||||
|
@Slf4j
|
||||||
|
public class IsoController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
@Resource
|
||||||
|
private SysDictMapper sysDictMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@RequestMapping("/satoken/ajaxlogin")
|
||||||
|
public IsoDTO test() {
|
||||||
|
log.info("satoken----ajaxlogin---ajaxlogin-ajaxlogin---ajaxlogin");
|
||||||
|
IsoDTO dto = new IsoDTO();
|
||||||
|
dto.setRescode(200);
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject o = new JSONObject();
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("yhid", "yhid");
|
||||||
|
jsonObject.put("yhxm", "yhxm");
|
||||||
|
jsonObject.put("yhzh", "yhzh");
|
||||||
|
o.put("userBase", jsonObject);
|
||||||
|
data.put("user", o);
|
||||||
|
data.put("tokenname", "abcde");
|
||||||
|
data.put("tokenvalue", "eyJhbGciOiJIUzI1NiJ9");
|
||||||
|
data.put("tokentimeout", 10000000);
|
||||||
|
dto.setData(data);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @RequestMapping("/manage/device/submitputstore")
|
||||||
|
public IsoDTO isoDTO(@RequestParam(value = "un",required = false) String un,
|
||||||
|
@RequestParam(value = "mu",required = false) String mu,
|
||||||
|
@RequestParam(value = "hw",required = false) String hw,
|
||||||
|
@RequestParam(value = "sw",required = false) String sw,
|
||||||
|
@RequestParam(value = "bt",required = false) String bt){
|
||||||
|
|
||||||
|
log.info("un={};mu={};hw={};sw={};bt={}",un,mu,hw,sw,bt);
|
||||||
|
Device one = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, mu));
|
||||||
|
String deviceId;
|
||||||
|
if (Objects.isNull(one)){
|
||||||
|
int year = DateUtil.year(new Date());
|
||||||
|
String s = String.valueOf(year);
|
||||||
|
String substring = s.substring(2);
|
||||||
|
Integer count = deviceMapper.selectCurrentYearDeviceCount();
|
||||||
|
int i = count + 1;
|
||||||
|
deviceId = un + "-" + substring + "-" + i;
|
||||||
|
Device device = new Device();
|
||||||
|
device.setDeviceId(deviceId);
|
||||||
|
device.setMuid(mu);
|
||||||
|
device.setWarehousingTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceMapper.insert(device);
|
||||||
|
}else {
|
||||||
|
deviceId = one.getDeviceId();
|
||||||
|
}
|
||||||
|
IsoDTO dto = new IsoDTO();
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
data.put("sbxlh",deviceId);
|
||||||
|
data.put("muid",mu);
|
||||||
|
dto.setData(data);
|
||||||
|
return dto;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* @RequestMapping("/manage/device/submitputstore")
|
||||||
|
public IsoDTO isoDTO(@RequestParam(value = "un", required = false) String un,
|
||||||
|
@RequestParam(value = "mu", required = false) String mu,
|
||||||
|
@RequestParam(value = "hw", required = false) String hw,
|
||||||
|
@RequestParam(value = "sw", required = false) String sw,
|
||||||
|
@RequestParam(value = "bt", required = false) String bt) {
|
||||||
|
|
||||||
|
log.info("un={};mu={};hw={};sw={};bt={}", un, mu, hw, sw, bt);
|
||||||
|
Device one = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, mu));
|
||||||
|
String deviceId;
|
||||||
|
if (Objects.isNull(one)) {
|
||||||
|
int year = DateUtil.year(new Date());
|
||||||
|
String s = String.valueOf(year);
|
||||||
|
String substring = s.substring(2);
|
||||||
|
Integer count = deviceMapper.selectCurrentYearDeviceCount();
|
||||||
|
int i = count + 1;
|
||||||
|
String buqi = buqi(i);
|
||||||
|
deviceId = un + "-" + substring + "-" + buqi;
|
||||||
|
Device device = new Device();
|
||||||
|
device.setDeviceId(deviceId);
|
||||||
|
device.setMuid(mu);
|
||||||
|
device.setWarehousingTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceMapper.insert(device);
|
||||||
|
} else {
|
||||||
|
if (one.getDeviceId().length() < 5){
|
||||||
|
int year = DateUtil.year(new Date());
|
||||||
|
String s = String.valueOf(year);
|
||||||
|
String substring = s.substring(2);
|
||||||
|
Integer count = deviceMapper.selectCurrentYearDeviceCount();
|
||||||
|
int i = count + 1;
|
||||||
|
String buqi = buqi(i);
|
||||||
|
deviceId = un + "-" + substring + "-" + buqi;
|
||||||
|
deviceMapper.modifyDeviceId(deviceId,one.getDeviceId());
|
||||||
|
}else {
|
||||||
|
deviceId = one.getDeviceId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IsoDTO dto = new IsoDTO();
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
data.put("sbxlh", deviceId);
|
||||||
|
data.put("muid", mu);
|
||||||
|
dto.setData(data);
|
||||||
|
return dto;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@GetMapping("/equipment/warehousing")
|
||||||
|
public IsoDTO isoDTO2(HttpServletRequest request, @RequestParam(value = "un", required = false) String un,
|
||||||
|
@RequestParam(value = "mu", required = false) String mu) throws Exception {
|
||||||
|
|
||||||
|
log.info("mu={},un={}",mu,un);
|
||||||
|
String sKey = request.getHeader("s-key");
|
||||||
|
String decrypt = AESUtil.decrypt(sKey);
|
||||||
|
IsoDTO isoDTO = new IsoDTO();
|
||||||
|
if (!decrypt.equals(mu)){
|
||||||
|
isoDTO.setRescode(500);
|
||||||
|
isoDTO.setResmsg("数据校验不通过!");
|
||||||
|
isoDTO.setSuccess(false);
|
||||||
|
return isoDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device one = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, mu));
|
||||||
|
String deviceId;
|
||||||
|
if (Objects.isNull(one)){
|
||||||
|
int year = DateUtil.year(new Date());
|
||||||
|
String s = String.valueOf(year);
|
||||||
|
String substring = s.substring(2);
|
||||||
|
List<Device> deviceList = deviceMapper.selectCurrentYearDevice(substring);
|
||||||
|
int max;
|
||||||
|
if (CollectionUtils.isNotEmpty(deviceList)){
|
||||||
|
List<Integer> integerList = deviceList.stream()
|
||||||
|
.map(t -> {
|
||||||
|
String su = t.getDeviceId().substring(8);
|
||||||
|
String num = su.replaceFirst("^0+", "");
|
||||||
|
return Integer.parseInt(num);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
max = integerList.stream().mapToInt(Integer::intValue)
|
||||||
|
.max()
|
||||||
|
.orElseThrow(RuntimeException::new);
|
||||||
|
}else {
|
||||||
|
max = 0;
|
||||||
|
}
|
||||||
|
int fid = max + 1;
|
||||||
|
String buqi = buqi(fid);
|
||||||
|
deviceId = un + "-" + substring + "-" + buqi;
|
||||||
|
Device device = new Device();
|
||||||
|
device.setDeviceId(deviceId);
|
||||||
|
device.setMuid(mu);
|
||||||
|
device.setWarehousingTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceMapper.insert(device);
|
||||||
|
}else {
|
||||||
|
String oneDeviceId = one.getDeviceId();
|
||||||
|
String fs = oneDeviceId.substring(8);
|
||||||
|
if (!fs.startsWith("0")){
|
||||||
|
String buqi = buqi(Integer.parseInt(fs));
|
||||||
|
String substring = oneDeviceId.substring(5,7);
|
||||||
|
deviceId = un + "-" + substring + "-" + buqi;
|
||||||
|
deviceMapper.modifyDeviceId(deviceId,one.getDeviceId());
|
||||||
|
}else {
|
||||||
|
deviceId = one.getDeviceId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IsoDTO dto = new IsoDTO();
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
data.put("deviceId", deviceId);
|
||||||
|
data.put("muid", mu);
|
||||||
|
dto.setData(data);
|
||||||
|
dto.setRescode(200);
|
||||||
|
dto.setResmsg("success");
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buqi(int i) {
|
||||||
|
String str = String.valueOf(i);
|
||||||
|
int len = 5 - str.length();
|
||||||
|
String zero = "";
|
||||||
|
while (len > 0) {
|
||||||
|
zero += "0";
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
return zero + str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.dto.IsoDTO;
|
||||||
|
import cn.unizk.entity.vo.SysUserVO;
|
||||||
|
import cn.unizk.entity.vo.SysUserVO2;
|
||||||
|
import cn.unizk.service.LoginService;
|
||||||
|
import cn.unizk.utils.HttpUtil;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 11:32
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RequestMapping("/pc")
|
||||||
|
@RestController
|
||||||
|
public class LoginController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private LoginService loginService;
|
||||||
|
|
||||||
|
@PostMapping("/loginByUsername")
|
||||||
|
public SysUserVO loginByUsername(@RequestBody SysUserVO sysUserVO){
|
||||||
|
return loginService.loginByUsername(sysUserVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/test")
|
||||||
|
public String test(@RequestParam("file") MultipartFile file){
|
||||||
|
/*byte[] fileHeader = new byte[16];
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
is = file.getInputStream();
|
||||||
|
int bytesRead = is.read(fileHeader);
|
||||||
|
is.close();
|
||||||
|
if (bytesRead < 4) {
|
||||||
|
throw new ServiceException("文件太小,无法识别");
|
||||||
|
}
|
||||||
|
FileMagicNumber magicNumber = FileMagicNumber.getMagicNumber(fileHeader);
|
||||||
|
return magicNumber.getMimeType();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;*/
|
||||||
|
Map<String,String> params = new HashMap<>();
|
||||||
|
params.put("un","un");
|
||||||
|
params.put("mu","mu");
|
||||||
|
params.put("hw","hw");
|
||||||
|
params.put("sw","sw");
|
||||||
|
params.put("bt","bt");
|
||||||
|
String s = HttpUtil.doGet("http://localhost:8083/device/submitputstore", null, params);
|
||||||
|
Gson gson = new Gson();
|
||||||
|
IsoDTO isoDTO = gson.fromJson(s, IsoDTO.class);
|
||||||
|
System.out.println(isoDTO.toString());
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Menu;
|
||||||
|
import cn.unizk.entity.vo.TreeMenu;
|
||||||
|
import cn.unizk.service.MenuService;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/26 11:29
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc")
|
||||||
|
public class MenuController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MenuService menuService;
|
||||||
|
|
||||||
|
@GetMapping("/admin/menuList")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public List<TreeMenu> getAllMenus(){
|
||||||
|
return menuService.getAllMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/store/menuList")
|
||||||
|
public List<TreeMenu> getStoreMenus(){
|
||||||
|
return menuService.getStoreMenus();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.RunConsultation;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.RunConsultationMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/7/15 11:33
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin/running")
|
||||||
|
public class RunningController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RunConsultationMapper runConsultationMapper;
|
||||||
|
|
||||||
|
@PostMapping("/getConsults")
|
||||||
|
public Page<RunConsultation> page(@RequestBody UniPage<RunConsultation> uniPage){
|
||||||
|
Page<RunConsultation> page = (Page<RunConsultation>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<RunConsultation> queryWrapper = uniPage.buildQueryWrapper(query -> {
|
||||||
|
LambdaQueryWrapper<RunConsultation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
lambdaQueryWrapper.like(StringUtils.isNotBlank(query.getLesion()), RunConsultation::getLesion, query.getLesion());
|
||||||
|
return lambdaQueryWrapper;
|
||||||
|
});
|
||||||
|
return runConsultationMapper.selectPage(page,queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/addOrUpdate")
|
||||||
|
public ResultData addOrUpdate(@RequestBody RunConsultation runConsultation){
|
||||||
|
List<String> msgs = new ArrayList<>();
|
||||||
|
if (StringUtils.isBlank(runConsultation.getLesion())){
|
||||||
|
msgs.add("lesion不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(runConsultation.getConclusion())){
|
||||||
|
msgs.add("conclusion不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(runConsultation.getQuestion())){
|
||||||
|
msgs.add("question不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(runConsultation.getPlan())){
|
||||||
|
msgs.add("plan不能为空");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(msgs)){
|
||||||
|
String msg = String.join(";", msgs);
|
||||||
|
throw new ServiceException(msg);
|
||||||
|
}
|
||||||
|
if (runConsultation.getId() == null){
|
||||||
|
runConsultationMapper.insert(runConsultation);
|
||||||
|
}else {
|
||||||
|
runConsultationMapper.updateById(runConsultation);
|
||||||
|
}
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public ResultData delete(@RequestParam("id") Integer id){
|
||||||
|
runConsultationMapper.deleteById(id);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.entity.dto.AppointmentDTO;
|
||||||
|
import cn.unizk.entity.po.DailySchedules;
|
||||||
|
import cn.unizk.entity.po.JkPhysio;
|
||||||
|
import cn.unizk.entity.po.MobileAppointments;
|
||||||
|
import cn.unizk.entity.vo.DailySchedulesVO;
|
||||||
|
import cn.unizk.entity.vo.RosterVO;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.mapper.DailySchedulesMapper;
|
||||||
|
import cn.unizk.mapper.JkPhysioMapper;
|
||||||
|
import cn.unizk.mapper.MobileAppointmentsMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/9/15 11:37
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin/appointment")
|
||||||
|
public class SysAppointmentController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DailySchedulesMapper dailySchedulesMapper;
|
||||||
|
@Resource
|
||||||
|
private JkPhysioMapper jkPhysioMapper;
|
||||||
|
@Resource
|
||||||
|
private MobileAppointmentsMapper mobileAppointmentsMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/roster")
|
||||||
|
public RosterVO roster(@RequestParam("physioId") Integer physioId){
|
||||||
|
/*List<DailySchedulesVO> dailySchedulesVOS = dailySchedulesMapper.selectRosterList(physioId);
|
||||||
|
dailySchedulesVOS.forEach(vo -> vo.setScheduleDateStr(vo.getScheduleDate().toString()));
|
||||||
|
dailySchedulesVOS.sort(((o1, o2) -> o1.getScheduleDate().compareTo(o2.getScheduleDate())));
|
||||||
|
Map<String, List<DailySchedulesVO>> collect = dailySchedulesVOS.stream()
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
DailySchedulesVO::getScheduleDateStr,
|
||||||
|
LinkedHashMap::new,
|
||||||
|
Collectors.toList()
|
||||||
|
));
|
||||||
|
Map<String, List<DailySchedulesVO>> rosterVO = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<String, List<DailySchedulesVO>> entry : collect.entrySet()) {
|
||||||
|
String s = DateUtil.dayOfWeekEnum(DateUtil.parseDate(entry.getKey())).toChinese();
|
||||||
|
rosterVO.put(entry.getKey() + " " + s,entry.getValue());
|
||||||
|
}
|
||||||
|
return rosterVO;*/
|
||||||
|
|
||||||
|
|
||||||
|
List<DailySchedulesVO> list = dailySchedulesMapper.selectRosterList(physioId);
|
||||||
|
list.forEach(vo -> vo.setScheduleDateStr(vo.getScheduleDate().toString()));
|
||||||
|
|
||||||
|
// 2) 全局日期列(去重 + 排序)
|
||||||
|
List<RosterVO.DateColumnVO> dates = list.stream()
|
||||||
|
.map(DailySchedulesVO::getScheduleDate)
|
||||||
|
.distinct()
|
||||||
|
.sorted()
|
||||||
|
.map(d -> {
|
||||||
|
RosterVO.DateColumnVO c = new RosterVO.DateColumnVO();
|
||||||
|
c.setDate(d.toString());
|
||||||
|
c.setWeekday(DateUtil.dayOfWeekEnum(DateUtil.parseDate(d.toString())).toChinese());
|
||||||
|
c.setLabel(d + " " + c.getWeekday());
|
||||||
|
return c;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 3) 全局时段行(去重 + 按开始时间排序,保证所有日期行序一致)
|
||||||
|
List<RosterVO.SlotVO> slots = list.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
DailySchedulesVO::getSlotCode,
|
||||||
|
vo -> new RosterVO.SlotVO(vo.getSlotCode(), vo.getSlotName(), vo.getStartTime(), vo.getEndTime()),
|
||||||
|
(a, b) -> a,
|
||||||
|
LinkedHashMap::new))
|
||||||
|
.values().stream()
|
||||||
|
.sorted(Comparator.comparing(RosterVO.SlotVO::getStartTime))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 建立索引:date + slotCode -> VO
|
||||||
|
Map<String, DailySchedulesVO> index = list.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
vo -> vo.getScheduleDateStr() + "|" + vo.getSlotCode(),
|
||||||
|
Function.identity(),
|
||||||
|
(a, b) -> a));
|
||||||
|
|
||||||
|
List<RosterVO.RosterRowVO> rows = new ArrayList<>();
|
||||||
|
for (RosterVO.SlotVO slot : slots) {
|
||||||
|
RosterVO.RosterRowVO row = new RosterVO.RosterRowVO();
|
||||||
|
row.setSlot(slot);
|
||||||
|
List<RosterVO.RosterCellVO> cells = new ArrayList<>();
|
||||||
|
for (RosterVO.DateColumnVO date : dates) {
|
||||||
|
DailySchedulesVO vo = index.get(date.getDate() + "|" + slot.getSlotCode());
|
||||||
|
RosterVO.RosterCellVO cell = new RosterVO.RosterCellVO();
|
||||||
|
cell.setDate(date.getDate());
|
||||||
|
if (vo == null) {
|
||||||
|
cell.setStatus("not_scheduled"); // 未排班
|
||||||
|
} else {
|
||||||
|
cell.setId(vo.getId());
|
||||||
|
cell.setStatus(vo.getStatus());
|
||||||
|
cell.setMaxBookings(vo.getMaxBookings());
|
||||||
|
cell.setBookedCount(vo.getBookedCount());
|
||||||
|
cell.setAvailableCount(vo.getAvailableCount());
|
||||||
|
}
|
||||||
|
cells.add(cell);
|
||||||
|
}
|
||||||
|
row.setCells(cells);
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
RosterVO vo = new RosterVO();
|
||||||
|
vo.setDates(dates);
|
||||||
|
vo.setSlots(slots);
|
||||||
|
vo.setRows(rows);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getAllPhysio")
|
||||||
|
public List<JkPhysio> getAllPhysio(@RequestParam(value = "physioName",required = false) String physioName){
|
||||||
|
LambdaQueryWrapper<JkPhysio> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(JkPhysio::getAudit,1).eq(JkPhysio::getStatus,"启用");
|
||||||
|
if (StringUtils.isNotBlank(physioName)){
|
||||||
|
wrapper.eq(JkPhysio::getPhysioName,physioName);
|
||||||
|
}
|
||||||
|
return jkPhysioMapper.selectList(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/appointmentList")
|
||||||
|
public Page<MobileAppointments> page(@RequestBody UniPage<AppointmentDTO> uniPage){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.entity.po.BusinessChannel;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.service.BusinessChannelService;
|
||||||
|
import cn.unizk.service.WxAuthService;
|
||||||
|
import cn.unizk.utils.HttpUtil;
|
||||||
|
import cn.unizk.utils.ServletUtils;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/10/9 14:33
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/channel")
|
||||||
|
@Slf4j
|
||||||
|
public class SysBusinessChannelController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BusinessChannelService businessChannelService;
|
||||||
|
@Resource
|
||||||
|
private WxAuthService wxAuthService;
|
||||||
|
|
||||||
|
@PostMapping("/page")
|
||||||
|
public Page<BusinessChannel> page(@RequestBody UniPage<BusinessChannel> page){
|
||||||
|
Page<BusinessChannel> pagePage = (Page<BusinessChannel>) page.getPage();
|
||||||
|
LambdaQueryWrapper<BusinessChannel> queryWrapper = page.buildQueryWrapper(wrapper -> {
|
||||||
|
LambdaQueryWrapper<BusinessChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
lambdaQueryWrapper.like(StringUtils.isNotBlank(wrapper.getChannelName()), BusinessChannel::getChannelName, wrapper.getChannelName());
|
||||||
|
return lambdaQueryWrapper;
|
||||||
|
});
|
||||||
|
return businessChannelService.page(pagePage,queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public boolean delete(@RequestParam("channelId") Integer channelId){
|
||||||
|
return businessChannelService.removeById(channelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addChannel")
|
||||||
|
public boolean addChannel(@RequestBody BusinessChannel channel){
|
||||||
|
List<BusinessChannel> channelList = businessChannelService.list(new LambdaQueryWrapper<BusinessChannel>().eq(BusinessChannel::getChannelName, channel.getChannelName()));
|
||||||
|
if (CollectionUtils.isNotEmpty(channelList)){
|
||||||
|
throw new ServiceException(String.format("渠道商名称:%s已存在",channel.getChannelName()));
|
||||||
|
}
|
||||||
|
return businessChannelService.save(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getAppletQrCode")
|
||||||
|
public void getAppletQrCode(HttpServletResponse response,@RequestParam(value = "channelId",required = false) Integer channelId,@RequestParam(value = "type",required = false) String type){
|
||||||
|
String accessToken = wxAuthService.getAccessToken();
|
||||||
|
String url = String.format("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s",accessToken);
|
||||||
|
log.info("url={}",url);
|
||||||
|
JSONObject jsonBody = JSONObject.of();
|
||||||
|
jsonBody.put("scene",channelId);
|
||||||
|
// jsonBody.put("check_path",false);
|
||||||
|
// jsonBody.put("env_version","trial");
|
||||||
|
jsonBody.put("width",280);
|
||||||
|
byte[] bytes = HttpUtil.postRtnBytes(url, null, jsonBody);
|
||||||
|
if (bytes == null || bytes.length == 0){
|
||||||
|
ServletUtils.renderString(response,"qrcode res is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String fileName = "";
|
||||||
|
if (channelId != null){
|
||||||
|
BusinessChannel businessChannel = businessChannelService.getById(channelId);
|
||||||
|
fileName = Objects.nonNull(businessChannel) ? businessChannel.getChannelName() : "";
|
||||||
|
}
|
||||||
|
// response.setContentType("image/jpeg");
|
||||||
|
response.setContentLength(bytes.length);
|
||||||
|
if ("download".equals(type)){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=渠道商-"+channelId+now+".png");
|
||||||
|
}
|
||||||
|
try (OutputStream os = response.getOutputStream()) {
|
||||||
|
os.write(bytes);
|
||||||
|
os.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Combo;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.service.ComboService;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/18 10:42
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/combo")
|
||||||
|
public class SysComboController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ComboService comboService;
|
||||||
|
|
||||||
|
@PostMapping("/comboPage")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public Page<Combo> page(@RequestBody UniPage<Combo> uniPage){
|
||||||
|
Page<Combo> page = (Page<Combo>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<Combo> lambdaQueryWrapper = uniPage.buildQueryWrapper(query -> {
|
||||||
|
LambdaQueryWrapper<Combo> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(StringUtils.isNotBlank(query.getDeviceId()), Combo::getDeviceId, query.getDeviceId())
|
||||||
|
.like(StringUtils.isNotBlank(query.getComboName()), Combo::getComboName, query.getComboName());
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
return comboService.page(page,lambdaQueryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editCombo")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean editCombo(@RequestBody Combo combo){
|
||||||
|
return comboService.updateById(combo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addCombo")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean addCombo(@RequestBody Combo combo){
|
||||||
|
if (StringUtils.isNotBlank(combo.getDeviceId()) && combo.getDeviceId().contains(",")){
|
||||||
|
String[] split = combo.getDeviceId().split(",");
|
||||||
|
List<Combo> list = new ArrayList<>();
|
||||||
|
for (String s : split) {
|
||||||
|
Combo c = new Combo();
|
||||||
|
c.setChannelId(combo.getChannelId());
|
||||||
|
c.setComboDuration(combo.getComboDuration());
|
||||||
|
c.setComboName(combo.getComboName());
|
||||||
|
c.setComboPrice(combo.getComboPrice());
|
||||||
|
c.setDeviceId(s);
|
||||||
|
c.setImage(combo.getImage());
|
||||||
|
list.add(c);
|
||||||
|
}
|
||||||
|
return comboService.saveBatch(list);
|
||||||
|
}
|
||||||
|
return comboService.save(combo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean delete(@RequestParam("comboId") Integer comboId){
|
||||||
|
return comboService.removeById(comboId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Chapter;
|
||||||
|
import cn.unizk.entity.po.Course;
|
||||||
|
import cn.unizk.entity.po.MobileUserVideoProgress;
|
||||||
|
import cn.unizk.entity.vo.CourseVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.ChapterMapper;
|
||||||
|
import cn.unizk.mapper.CourseMapper;
|
||||||
|
import cn.unizk.mapper.MobileUserVideoProgressMapper;
|
||||||
|
import cn.unizk.utils.BeanCopyUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/3/9 11:17
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin/course")
|
||||||
|
@Slf4j
|
||||||
|
public class SysCourseController {
|
||||||
|
|
||||||
|
private static final String OSS_DOMAIN = "http://oss.peaktcm.com/";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CourseMapper courseMapper;
|
||||||
|
@Resource
|
||||||
|
private ChapterMapper chapterMapper;
|
||||||
|
/*@Resource
|
||||||
|
private WxUserVideoProgressMapper wxUserVideoProgressMapper;*/
|
||||||
|
@Resource
|
||||||
|
private MobileUserVideoProgressMapper mobileUserVideoProgressMapper;
|
||||||
|
|
||||||
|
@PostMapping("/addCourse")
|
||||||
|
public ResultData addCourse(@Validated @RequestBody Course course){
|
||||||
|
course.setCreateTime(LocalDateTime.now());
|
||||||
|
return courseMapper.insert(course) > 0 ? ResultData.success() : ResultData.failure(500,"新增课程失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addChapter")
|
||||||
|
public ResultData addChapter(@Validated @RequestBody Chapter chapter){
|
||||||
|
chapter.setCreateTime(LocalDateTime.now());
|
||||||
|
chapter.setVideoUrl(OSS_DOMAIN + chapter.getVideoUrl());
|
||||||
|
return chapterMapper.insert(chapter) > 0 ? ResultData.success() : ResultData.failure(500,"新增章节失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/courseList")
|
||||||
|
public Page<CourseVO> coursePage(@RequestBody UniPage<Course> uniPage){
|
||||||
|
Page<Course> page = (Page<Course>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<Course> buildQueryWrapper = uniPage.buildQueryWrapper(wrapper -> {
|
||||||
|
LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.like(StringUtils.isNotBlank(wrapper.getTitle()), Course::getTitle, wrapper.getTitle());
|
||||||
|
return queryWrapper;
|
||||||
|
});
|
||||||
|
Page<Course> coursePage = courseMapper.selectPage(page, buildQueryWrapper);
|
||||||
|
Page<CourseVO> voPage = new Page<>(page.getCurrent(),page.getSize());
|
||||||
|
List<Course> records = coursePage.getRecords();
|
||||||
|
if (CollectionUtils.isEmpty(records)){
|
||||||
|
return new Page<>();
|
||||||
|
}
|
||||||
|
Collection<CourseVO> courseVOS = BeanCopyUtils.copyArrays(records, CourseVO::new);
|
||||||
|
for (CourseVO courseVO : courseVOS) {
|
||||||
|
List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>().eq(Chapter::getCourseId, courseVO.getCourseId()));
|
||||||
|
courseVO.setChapterTotal(chapters.size());
|
||||||
|
}
|
||||||
|
voPage.setRecords((List<CourseVO>) courseVOS);
|
||||||
|
voPage.setTotal(coursePage.getTotal());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/chapterList")
|
||||||
|
public Page<Chapter> chapterPage(@RequestBody UniPage<Chapter> uniPage){
|
||||||
|
Page<Chapter> page = (Page<Chapter>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<Chapter> queryWrapper = uniPage.buildQueryWrapper(wr -> {
|
||||||
|
if (wr.getCourseId() == null){
|
||||||
|
throw new ServiceException("courseId必传");
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<Chapter> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(Chapter::getCourseId,wr.getCourseId()).like(StringUtils.isNotBlank(wr.getTitle()), Chapter::getTitle, wr.getTitle());
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
return chapterMapper.selectPage(page,queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteCourse")
|
||||||
|
public ResultData deleteCourse(@RequestParam("courseId") Integer courseId){
|
||||||
|
List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>().eq(Chapter::getCourseId, courseId));
|
||||||
|
if (CollectionUtils.isNotEmpty(chapters)){
|
||||||
|
throw new ServiceException("此课程有内容,请先删除课程章节");
|
||||||
|
}
|
||||||
|
return courseMapper.deleteById(courseId) > 0 ? ResultData.success() : ResultData.failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteChapter")
|
||||||
|
public ResultData deleteChapter(@RequestParam("chapterId") Integer chapterId){
|
||||||
|
mobileUserVideoProgressMapper.delete(new LambdaQueryWrapper<MobileUserVideoProgress>().eq(MobileUserVideoProgress::getChapterId,chapterId));
|
||||||
|
mobileUserVideoProgressMapper.delete(new LambdaQueryWrapper<MobileUserVideoProgress>().eq(MobileUserVideoProgress::getChapterId,chapterId));
|
||||||
|
return chapterMapper.deleteById(chapterId) > 0 ? ResultData.success() : ResultData.failure();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,669 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateTime;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.constants.Constants;
|
||||||
|
import cn.unizk.entity.dto.DeviceExcelDTO;
|
||||||
|
import cn.unizk.entity.po.*;
|
||||||
|
import cn.unizk.entity.vo.*;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.*;
|
||||||
|
import cn.unizk.service.*;
|
||||||
|
import cn.unizk.utils.BeanCopyUtils;
|
||||||
|
import cn.unizk.utils.QRcodeUtil;
|
||||||
|
import cn.unizk.utils.XorUtil;
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.baomidou.mybatisplus.core.batch.MybatisBatch;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/12 10:46
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@Slf4j
|
||||||
|
@RequestMapping("/pc/admin/device")
|
||||||
|
public class SysDeviceController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceService deviceService;
|
||||||
|
@Resource
|
||||||
|
private UdpClientService udpClientService;
|
||||||
|
@Resource
|
||||||
|
private UdpServerService2 udpServerService;
|
||||||
|
@Resource
|
||||||
|
private StoreService storeService;
|
||||||
|
@Resource
|
||||||
|
private SqlSessionFactory sqlSessionFactory;
|
||||||
|
/*@Resource
|
||||||
|
private WxUserService wxUserService;*/
|
||||||
|
@Resource
|
||||||
|
private MobileAppUserMapper mobileAppUserMapper;
|
||||||
|
@Resource
|
||||||
|
private ComboService comboService;
|
||||||
|
@Resource
|
||||||
|
private Executor udpRetryExecutor;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageRecordMapper deviceUsageRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceRechargeRecordMapper rechargeRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageDetailMapper usageDetailMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceUpgradeMapper upgradeMapper;
|
||||||
|
@Resource
|
||||||
|
private WxAuthService wxAuthService;
|
||||||
|
@Resource
|
||||||
|
private TreatParameterMapper treatParameterMapper;
|
||||||
|
|
||||||
|
private static final Path UPLOAD = Paths.get(Constants.DEVICE_UPGRADE_PACKAGE_ROOT_PATH);
|
||||||
|
|
||||||
|
private static final String SAFE_FILENAME_REGEX = "^[\\w\\u4e00-\\u9fa5.-]+$";
|
||||||
|
|
||||||
|
private static String power_on_off_command = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
|
||||||
|
private static final String OPEN01 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
|
||||||
|
|
||||||
|
@PostMapping("/onResponse")
|
||||||
|
public boolean onResponse(@RequestParam("deviceId") String deviceId){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/closeOrOpen")
|
||||||
|
public boolean closeOrOpen(@RequestParam("deviceId") String deviceId,
|
||||||
|
@RequestParam("status") String status){
|
||||||
|
|
||||||
|
Device device = deviceService.getById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
if ("1".equals(status) && device.getSurplus() < 1){
|
||||||
|
throw new ServiceException("此设备无剩余使用次数,无法启用,请先充值!");
|
||||||
|
}
|
||||||
|
UdpServerService2.DeviceInfo deviceInfo = udpServerService.getDeviceInfo(device.getMuid());
|
||||||
|
if (Objects.isNull(deviceInfo)){
|
||||||
|
device.setStatus(status);
|
||||||
|
return deviceService.updateById(device);
|
||||||
|
}
|
||||||
|
udpRetryExecutor.execute(() -> retryUdp(device, status));
|
||||||
|
return true;
|
||||||
|
/*Device device = deviceService.getById(deviceId);
|
||||||
|
device.setStatus(status);
|
||||||
|
deviceService.updateById(device);
|
||||||
|
//发送UDP协议
|
||||||
|
UdpServerService.DeviceInfo deviceInfo = udpServerService.getDeviceInfo(device.getMuid());
|
||||||
|
if (Objects.isNull(deviceInfo)){
|
||||||
|
log.info("deviceInfo is null+++++++");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ("1".equals(deviceInfo.getStatus())){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = OPEN01.replace("{uid}", device.getMuid()).replace("{date}", now).replace("{1}", status);
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String msg = replace.replace("{CRC}", asciiHex);
|
||||||
|
log.info("传输的数据是:{}",msg);
|
||||||
|
return udpClientService.sendCommand(deviceInfo,msg);
|
||||||
|
}
|
||||||
|
if ("2".equals(deviceInfo.getStatus())){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
power_on_off_command = power_on_off_command.replace("{uid}",device.getMuid())
|
||||||
|
.replace("{date}",now).replace("{1}",status).replace("{2}","000");
|
||||||
|
String crc = power_on_off_command.substring(1, power_on_off_command.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
power_on_off_command = power_on_off_command.replace("{CRC}",asciiHex);
|
||||||
|
log.info("传输的数据是:{}",power_on_off_command);
|
||||||
|
return udpClientService.sendCommand(deviceInfo,power_on_off_command);
|
||||||
|
}
|
||||||
|
return false;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retryUdp(Device device, String status) {
|
||||||
|
int left = 10;
|
||||||
|
while (left-- > 0) {
|
||||||
|
if (udpServerService.reply(device, status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(10_000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.warn("UDP 回复重试耗尽,deviceId={}", device.getDeviceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/openStatus")
|
||||||
|
public boolean openStatus(@RequestParam("deviceId") String deviceId,
|
||||||
|
@RequestParam("status") String status){
|
||||||
|
Device device = deviceService.getById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
device.setStatus(status);
|
||||||
|
deviceService.updateById(device);
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = OPEN01.replace("{uid}", device.getMuid()).replace("{date}", now).replace("{1}", status);
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String msg = replace.replace("{CRC}", asciiHex);
|
||||||
|
UdpServerService2.DeviceInfo deviceInfo = udpServerService.getDeviceInfo(device.getMuid());
|
||||||
|
// return udpClientService.sendCommand(deviceInfo,msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/list")
|
||||||
|
public Page<Device> list(@RequestBody UniPage<DeviceVO> uniPage){
|
||||||
|
return deviceService.listPage(uniPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/exportDevices")
|
||||||
|
public void exportDevices(@RequestBody UniPage<DeviceVO> uniPage,HttpServletResponse response){
|
||||||
|
List<Device> records;
|
||||||
|
uniPage.setPageSize(-1);
|
||||||
|
DeviceVO queryBody = uniPage.getQueryBody();
|
||||||
|
if (CollectionUtils.isEmpty(queryBody.getDeviceIds())){
|
||||||
|
Page<Device> page = deviceService.listPage(uniPage);
|
||||||
|
records = page.getRecords();
|
||||||
|
}else {
|
||||||
|
records = deviceService.listByIds(queryBody.getDeviceIds());
|
||||||
|
}
|
||||||
|
Collection<DeviceExcelDTO> deviceExcelDTOS = BeanCopyUtils.copyArrays(records, DeviceExcelDTO::new);
|
||||||
|
deviceExcelDTOS.forEach(deviceExcelDTO -> {
|
||||||
|
if (deviceExcelDTO.getOutboundTime() == null){
|
||||||
|
deviceExcelDTO.setOutboundType("未出库");
|
||||||
|
}else {
|
||||||
|
deviceExcelDTO.setOutboundType("已出库");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
String fileName = URLEncoder.encode("设备信息", "UTF-8").replaceAll("\\+", "%20");
|
||||||
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
response.addHeader("Content-disposition","attachment;filename="+fileName+".xlsx");
|
||||||
|
EasyExcel.write(response.getOutputStream(),DeviceExcelDTO.class).sheet("设备信息").doWrite(deviceExcelDTOS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException("服务异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/remark")
|
||||||
|
public boolean remark(@RequestBody Device device){
|
||||||
|
Device dv = new Device();
|
||||||
|
dv.setDeviceId(device.getDeviceId());
|
||||||
|
String remark = device.getRemark();
|
||||||
|
if (remark == null){
|
||||||
|
remark = "";
|
||||||
|
}
|
||||||
|
dv.setRemark(remark);
|
||||||
|
return deviceService.updateById(dv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/outbound")
|
||||||
|
public ResultData outbound(@RequestBody DeviceOutboundVO vo){
|
||||||
|
if (vo.getStoreId() == null && StringUtils.isBlank(vo.getPhoneNumber())){
|
||||||
|
throw new ServiceException("请输入门店id或个人手机号");
|
||||||
|
}
|
||||||
|
List<String> deviceIds = vo.getDeviceIds();
|
||||||
|
List<Device> devices = deviceService.listByIds(deviceIds);
|
||||||
|
boolean b = devices.stream().allMatch(device -> device.getOutboundTime() == null);
|
||||||
|
if (!b){
|
||||||
|
throw new ServiceException("该批次出库设备中存在已出库的设备!");
|
||||||
|
}
|
||||||
|
if (vo.getStoreId() != null){
|
||||||
|
JkStore jkStore = storeService.getById(vo.getStoreId());
|
||||||
|
if (Objects.isNull(jkStore)){
|
||||||
|
throw new ServiceException("查无此店!");
|
||||||
|
}
|
||||||
|
//出库到门店
|
||||||
|
devices.forEach(device -> {
|
||||||
|
device.setStoreId(vo.getStoreId());
|
||||||
|
device.setAffiliatedWith(jkStore.getStoreName());
|
||||||
|
device.setOutboundTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
});
|
||||||
|
// batchUpdate(devices);
|
||||||
|
deviceService.updateBatchById(devices);
|
||||||
|
}else if (StringUtils.isNotBlank(vo.getPhoneNumber())){
|
||||||
|
//出库到个人
|
||||||
|
MobileAppUser wxUser = mobileAppUserMapper.selectOne(new LambdaQueryWrapper<MobileAppUser>().eq(MobileAppUser::getPhoneNumber, vo.getPhoneNumber()));
|
||||||
|
if (Objects.isNull(wxUser)){
|
||||||
|
throw new ServiceException("该手机号未注册!");
|
||||||
|
}
|
||||||
|
devices.forEach(device -> {
|
||||||
|
device.setUserId(wxUser.getId());
|
||||||
|
device.setAffiliatedWith(wxUser.getNickname());
|
||||||
|
device.setOutboundTime(LocalDateTime.now());
|
||||||
|
});
|
||||||
|
// batchUpdate(devices);
|
||||||
|
deviceService.updateBatchById(devices);
|
||||||
|
}else if (vo.getAgentId() != null){
|
||||||
|
//出库到代理商
|
||||||
|
log.info("出库到代理商--------");
|
||||||
|
}
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getOne")
|
||||||
|
public Device getOne(@RequestParam("deviceId") String deviceId){
|
||||||
|
Device device = deviceService.getById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getQRCode")
|
||||||
|
public void downloadQRcode(HttpServletResponse response,@RequestParam("deviceId") String deviceId,
|
||||||
|
@RequestParam(value = "optionType",required = false) String optionType){
|
||||||
|
QRcodeUtil.getDeviceQrCode(response,deviceId,optionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void batchUpdate(List<Device> devices){
|
||||||
|
MybatisBatch<Device> mybatisBatch = new MybatisBatch<>(sqlSessionFactory,devices);
|
||||||
|
MybatisBatch.Method<Device> method = new MybatisBatch.Method<>(DeviceMapper.class);
|
||||||
|
mybatisBatch.execute(method.insert());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getCztc")
|
||||||
|
public List<Combo> getCztc(){
|
||||||
|
return comboService.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/cz")
|
||||||
|
public boolean cz(@RequestBody Device device){
|
||||||
|
Device deviceServiceById = deviceService.getById(device.getDeviceId());
|
||||||
|
deviceServiceById.setBalance(device.getBalance());
|
||||||
|
return deviceService.updateById(deviceServiceById);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getDeviceByChannel")
|
||||||
|
public List<Device> getDeviceByChannel(@RequestParam(value = "channelId",required = false) Integer channelId,@RequestParam(value = "deviceId",required = false) String deviceId){
|
||||||
|
if (channelId != null){
|
||||||
|
List<JkStore> list = storeService.list(new LambdaQueryWrapper<JkStore>().eq(JkStore::getChannelId, channelId));
|
||||||
|
List<Integer> storeIds = list.stream().map(JkStore::getId).collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(storeIds)){
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return deviceService.list(new LambdaQueryWrapper<Device>().in(Device::getStoreId,storeIds).like(StringUtils.isNotBlank(deviceId),Device::getDeviceId,deviceId));
|
||||||
|
}
|
||||||
|
return deviceService.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/recharge")
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean recharge(@RequestBody Device device){
|
||||||
|
Device deviceServiceById = deviceService.getById(device.getDeviceId());
|
||||||
|
// deviceServiceById.setPaymentMethod(device.getPaymentMethod());
|
||||||
|
Integer surplus = deviceServiceById.getSurplus();
|
||||||
|
// deviceServiceById.setSurplus(surplus + device.getSurplus());
|
||||||
|
deviceServiceById.setBalance(deviceServiceById.getBalance().add(device.getBalance()));
|
||||||
|
if (device.getPaymentMethod() == 1){
|
||||||
|
if (deviceServiceById.getPaymentMethod() != null && deviceServiceById.getPaymentMethod() == 1){
|
||||||
|
DateTime dateTime = DateUtil.offsetDay(new Date(), device.getSurplus() + surplus);
|
||||||
|
String s = DateUtil.formatDate(dateTime);
|
||||||
|
deviceServiceById.setExpireTime(DateUtil.formatDateTime(DateUtil.parseDate(s)));
|
||||||
|
deviceServiceById.setSurplus(surplus + device.getSurplus());
|
||||||
|
}else {
|
||||||
|
DateTime dateTime = DateUtil.offsetDay(new Date(), device.getSurplus());
|
||||||
|
String s = DateUtil.formatDate(dateTime);
|
||||||
|
deviceServiceById.setExpireTime(DateUtil.formatDateTime(DateUtil.parseDate(s)));
|
||||||
|
deviceServiceById.setSurplus(device.getSurplus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (device.getPaymentMethod() == 2){
|
||||||
|
if (deviceServiceById.getPaymentMethod() != null && deviceServiceById.getPaymentMethod() == 2){
|
||||||
|
deviceServiceById.setExpireTime(String.valueOf(device.getSurplus() + surplus));
|
||||||
|
deviceServiceById.setSurplus(device.getSurplus() + surplus);
|
||||||
|
}else {
|
||||||
|
deviceServiceById.setExpireTime(String.valueOf(device.getSurplus()));
|
||||||
|
deviceServiceById.setSurplus(device.getSurplus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceServiceById.setRechargeCount(deviceServiceById.getRechargeCount() + 1);
|
||||||
|
deviceServiceById.setPaymentMethod(device.getPaymentMethod());
|
||||||
|
DeviceRechargeRecord rechargeRecord = new DeviceRechargeRecord();
|
||||||
|
rechargeRecord.setQuantity(device.getSurplus());
|
||||||
|
rechargeRecord.setDeviceId(device.getDeviceId());
|
||||||
|
rechargeRecord.setMoney(device.getBalance());
|
||||||
|
rechargeRecord.setRechargeType(device.getPaymentMethod());
|
||||||
|
rechargeRecord.setCreateTime(LocalDateTime.now());
|
||||||
|
rechargeRecordMapper.insert(rechargeRecord);
|
||||||
|
return deviceService.updateById(deviceServiceById);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/rechargeRecord")
|
||||||
|
public Page<DeviceRechargeRecord> page(@RequestBody UniPage<DeviceRechargeRecord> uniPage){
|
||||||
|
Page<DeviceRechargeRecord> page = (Page<DeviceRechargeRecord>) uniPage.getPage();
|
||||||
|
DeviceRechargeRecord queryBody = uniPage.getQueryBody();
|
||||||
|
return rechargeRecordMapper.selectPage(page,new LambdaQueryWrapper<DeviceRechargeRecord>().eq(DeviceRechargeRecord::getDeviceId,queryBody.getDeviceId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/usageRecord")
|
||||||
|
public Page<DeviceUsageRecordVO> usageRecord(@RequestBody UniPage<UsageDetailVO> uniPage){
|
||||||
|
Page<DeviceUsageRecord> page = new Page<>(uniPage.getCurrentPage(),uniPage.getPageSize());
|
||||||
|
UsageDetailVO queryBody = uniPage.getQueryBody();
|
||||||
|
LambdaQueryWrapper<DeviceUsageRecord> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(StringUtils.isNotBlank(queryBody.getDeviceId()),DeviceUsageRecord::getDeviceId,queryBody.getDeviceId());
|
||||||
|
if (queryBody.getStoreId() != null){
|
||||||
|
List<Device> devices = deviceService.list(new LambdaQueryWrapper<Device>().eq(Device::getStoreId, queryBody.getStoreId()));
|
||||||
|
List<String> deviceIds = devices.stream().map(Device::getDeviceId).collect(Collectors.toList());
|
||||||
|
wrapper.in(DeviceUsageRecord::getDeviceId,deviceIds);
|
||||||
|
}
|
||||||
|
if (queryBody.getStartTime() != null && queryBody.getEndTime() != null){
|
||||||
|
wrapper.between(DeviceUsageRecord::getStartTime,queryBody.getStartTime(),queryBody.getEndTime());
|
||||||
|
}
|
||||||
|
wrapper.and(StringUtils.isNotBlank(queryBody.getKeyword()),r -> {
|
||||||
|
r.eq(DeviceUsageRecord::getDeviceId,queryBody.getKeyword())
|
||||||
|
.or()
|
||||||
|
.eq(DeviceUsageRecord::getMuid,queryBody.getKeyword());
|
||||||
|
});
|
||||||
|
wrapper.orderByDesc(DeviceUsageRecord::getStartTime);
|
||||||
|
Page<DeviceUsageRecord> recordPage = deviceUsageRecordMapper.selectPage(page, wrapper);
|
||||||
|
List<DeviceUsageRecord> records = recordPage.getRecords();
|
||||||
|
List<DeviceUsageRecordVO> voList = new ArrayList<>();
|
||||||
|
for (DeviceUsageRecord record : records) {
|
||||||
|
DeviceUsageRecordVO vo = new DeviceUsageRecordVO();
|
||||||
|
BeanUtils.copyProperties(record,vo);
|
||||||
|
if (record.getStartTime() != null && record.getEndTime() != null){
|
||||||
|
long minutes = Duration.between(record.getStartTime(), record.getEndTime()).toMinutes();
|
||||||
|
vo.setUseDuration(minutes);
|
||||||
|
}
|
||||||
|
voList.add(vo);
|
||||||
|
}
|
||||||
|
Page<DeviceUsageRecordVO> voPage = new Page<>();
|
||||||
|
voPage.setRecords(voList);
|
||||||
|
voPage.setCurrent(recordPage.getCurrent());
|
||||||
|
voPage.setSize(recordPage.getSize());
|
||||||
|
voPage.setTotal(recordPage.getTotal());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/changeConfig")
|
||||||
|
public boolean changeConfig(@RequestBody DeviceConfigVO vo){
|
||||||
|
List<String> deviceIds = vo.getDeviceIds();
|
||||||
|
if (CollectionUtils.isEmpty(deviceIds)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<Device> deviceList = new ArrayList<>();
|
||||||
|
deviceIds.forEach(id -> {
|
||||||
|
Device device = new Device();
|
||||||
|
device.setDeviceId(id);
|
||||||
|
device.setCf(vo.getCf());
|
||||||
|
device.setStatus(vo.getCanUse());
|
||||||
|
device.setUpgradeSwitch(vo.getUpgradeSwitch());
|
||||||
|
deviceList.add(device);
|
||||||
|
});
|
||||||
|
deviceService.updateBatchById(deviceList);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/upgrade")
|
||||||
|
public ResultData upgrade(@RequestParam(value = "id",required = false) Integer id,
|
||||||
|
@RequestParam(value = "file",required = false) MultipartFile file,
|
||||||
|
@RequestParam String sVersion,
|
||||||
|
@RequestParam String hVersion,
|
||||||
|
@RequestParam String fileName,
|
||||||
|
@RequestParam(value = "releaseNotes",required = false) String releaseNotes,
|
||||||
|
@RequestParam Integer beCurrentVersion){
|
||||||
|
validateFile(id,file);
|
||||||
|
LambdaQueryWrapper<DeviceUpgrade> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
if (id == null){
|
||||||
|
wrapper.eq(DeviceUpgrade::getHVersion, hVersion).eq(DeviceUpgrade::getSVersion, sVersion);
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(wrapper);
|
||||||
|
if (Objects.nonNull(deviceUpgrade)){
|
||||||
|
throw new ServiceException("已存在相同版本的硬件号和软件号");
|
||||||
|
}
|
||||||
|
if (beCurrentVersion == 1){
|
||||||
|
upgradeMapper.updateCurrentVersion();
|
||||||
|
}
|
||||||
|
createFile(file);
|
||||||
|
DeviceUpgrade upgrade = new DeviceUpgrade();
|
||||||
|
upgrade.setBeCurrentVersion(beCurrentVersion);
|
||||||
|
upgrade.setFileName(fileName);
|
||||||
|
upgrade.setHVersion(hVersion);
|
||||||
|
upgrade.setSVersion(sVersion);
|
||||||
|
upgrade.setReleaseNotes(releaseNotes);
|
||||||
|
upgrade.setCreateTime(LocalDateTime.now());
|
||||||
|
return ResultData.success(upgradeMapper.insert(upgrade));
|
||||||
|
}else {
|
||||||
|
wrapper.eq(DeviceUpgrade::getHVersion, hVersion).eq(DeviceUpgrade::getSVersion, sVersion).ne(DeviceUpgrade::getId,id);
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(wrapper);
|
||||||
|
if (Objects.nonNull(deviceUpgrade)){
|
||||||
|
throw new ServiceException("已存在相同版本的硬件号和软件号");
|
||||||
|
}
|
||||||
|
if (beCurrentVersion == 1){
|
||||||
|
upgradeMapper.updateCurrentVersion();
|
||||||
|
}
|
||||||
|
if (file != null && !file.isEmpty()){
|
||||||
|
DeviceUpgrade selectById = upgradeMapper.selectById(id);
|
||||||
|
if (Objects.nonNull(selectById)){
|
||||||
|
deleteFile(selectById.getFileName());
|
||||||
|
}
|
||||||
|
createFile(file);
|
||||||
|
}
|
||||||
|
DeviceUpgrade upgrade = new DeviceUpgrade();
|
||||||
|
upgrade.setId(id);
|
||||||
|
upgrade.setBeCurrentVersion(beCurrentVersion);
|
||||||
|
upgrade.setFileName(fileName);
|
||||||
|
upgrade.setHVersion(hVersion);
|
||||||
|
upgrade.setSVersion(sVersion);
|
||||||
|
upgrade.setReleaseNotes(releaseNotes);
|
||||||
|
upgrade.setUpdateTime(LocalDateTime.now());
|
||||||
|
return ResultData.success(upgradeMapper.updateById(upgrade));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFile(MultipartFile file){
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
try {
|
||||||
|
Files.createDirectories(UPLOAD);
|
||||||
|
Path dest = UPLOAD.resolve(originalFilename);
|
||||||
|
file.transferTo(dest);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("文件上传失败",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/uploadUpgradeFile")
|
||||||
|
public ResultData uploadUpgradeFile(@RequestParam("file")MultipartFile file,@RequestParam(value = "id",required = false) Integer id) throws IOException {
|
||||||
|
if (file == null || file.isEmpty()){
|
||||||
|
throw new ServiceException("请上传文件");
|
||||||
|
}
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (StringUtils.isBlank(originalFilename) || originalFilename.endsWith(".bin")){
|
||||||
|
throw new ServiceException("文件类型不正确,请重新上传");
|
||||||
|
}
|
||||||
|
if (originalFilename.startsWith(".") || !Pattern.matches(SAFE_FILENAME_REGEX,originalFilename)){
|
||||||
|
throw new ServiceException("文件名不合法!");
|
||||||
|
}
|
||||||
|
// validateFile(id,originalFilename,true);
|
||||||
|
Files.createDirectories(UPLOAD);
|
||||||
|
Path dest = UPLOAD.resolve(originalFilename);
|
||||||
|
file.transferTo(dest);
|
||||||
|
ResultData<String> data = new ResultData<>();
|
||||||
|
data.setData(originalFilename);
|
||||||
|
data.setMessage("上传成功");
|
||||||
|
data.setCode(200);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/revokeUpgradeFile")
|
||||||
|
public void revokeUpgradeFile(@RequestParam("filename") String filename){
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getFileName, filename));
|
||||||
|
if (Objects.nonNull(deviceUpgrade)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deleteFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateFile(Integer id,MultipartFile file){
|
||||||
|
if ((file == null || file.isEmpty()) && id == null){
|
||||||
|
throw new ServiceException("请上传文件");
|
||||||
|
}
|
||||||
|
if (file != null && !file.isEmpty()){
|
||||||
|
final long maxLen = 1024 * 32;
|
||||||
|
if (file.getSize() > maxLen){
|
||||||
|
throw new ServiceException("文件太大,请重新上传");
|
||||||
|
}
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (StringUtils.isBlank(originalFilename) || !originalFilename.endsWith(".bin")){
|
||||||
|
throw new ServiceException("文件类型不正确,请重新上传");
|
||||||
|
}
|
||||||
|
if (originalFilename.startsWith(".") || !Pattern.matches(SAFE_FILENAME_REGEX,originalFilename)){
|
||||||
|
throw new ServiceException("文件名不合法!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id == null){
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getFileName, originalFilename));
|
||||||
|
if (Objects.nonNull(deviceUpgrade)){
|
||||||
|
throw new ServiceException(String.format("已存在文件名为%s的文件!",originalFilename));
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if (file != null && !file.isEmpty()){
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getFileName, originalFilename).ne(DeviceUpgrade::getId, id));
|
||||||
|
if (Objects.nonNull(deviceUpgrade)){
|
||||||
|
throw new ServiceException(String.format("已存在文件名为%s的文件!",originalFilename));
|
||||||
|
}
|
||||||
|
DeviceUpgrade upgrade = upgradeMapper.selectById(id);
|
||||||
|
if (Objects.isNull(upgrade)){
|
||||||
|
throw new ServiceException(String.format("id为%d的文件不存在!",id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*if (isUpload){
|
||||||
|
deleteFile(upgrade.getFileName());
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteFile(String filename){
|
||||||
|
Path path = Paths.get(Constants.DEVICE_UPGRADE_PACKAGE_ROOT_PATH + filename);
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("{}删除失败!",filename,e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/zeroClearing")
|
||||||
|
public boolean zeroClearing(@RequestBody List<String> deviceIds){
|
||||||
|
for (String deviceId : deviceIds) {
|
||||||
|
LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
updateWrapper.eq(Device::getDeviceId,deviceId)
|
||||||
|
.set(Device::getPaymentMethod,null)
|
||||||
|
.set(Device::getSurplus,0)
|
||||||
|
.set(Device::getExpireTime,"0");
|
||||||
|
deviceService.update(updateWrapper);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addDevice")
|
||||||
|
public void addDevice(@RequestBody Device device){
|
||||||
|
deviceService.save(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/usageDetail")
|
||||||
|
public Page<DeviceUsageDetail> page(@RequestParam("usageRecordId") Integer usageRecordId,UniPage uniPage){
|
||||||
|
Page<DeviceUsageDetail> page = new Page<>(uniPage.getCurrentPage(),uniPage.getPageSize());
|
||||||
|
return usageDetailMapper.selectPage(page,new LambdaQueryWrapper<DeviceUsageDetail>().eq(DeviceUsageDetail::getUsageRecordId,usageRecordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/reset")
|
||||||
|
public boolean reset(@RequestBody List<String> deviceIds){
|
||||||
|
if (CollectionUtils.isEmpty(deviceIds)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return deviceService.lambdaUpdate()
|
||||||
|
.set(Device::getStoreId, null)
|
||||||
|
.set(Device::getAffiliatedWith, null)
|
||||||
|
.set(Device::getOutboundTime, null)
|
||||||
|
.set(Device::getExpireTime, null)
|
||||||
|
.set(Device::getSurplus, 0)
|
||||||
|
.set(Device::getBalance, 0)
|
||||||
|
.set(Device::getPaymentMethod, null)
|
||||||
|
.set(Device::getUserId, null)
|
||||||
|
.set(Device::getAgentId, null)
|
||||||
|
.set(Device::getForcePay,0)
|
||||||
|
.in(Device::getDeviceId, deviceIds)
|
||||||
|
.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/software")
|
||||||
|
public Page<DeviceUpgrade> page(UniPage uniPage,@RequestParam(value = "keyword",required = false) String keyword){
|
||||||
|
Page<DeviceUpgrade> page = new Page<>(uniPage.getCurrentPage(),uniPage.getPageSize());
|
||||||
|
LambdaQueryWrapper<DeviceUpgrade> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.and(StringUtils.isNotBlank(keyword),r -> {
|
||||||
|
r.eq(DeviceUpgrade::getHVersion,keyword)
|
||||||
|
.or()
|
||||||
|
.eq(DeviceUpgrade::getSVersion,keyword);
|
||||||
|
});
|
||||||
|
return upgradeMapper.selectPage(page,wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteSoftware")
|
||||||
|
public Integer deleteSoftware(@RequestParam("id") Integer id){
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectById(id);
|
||||||
|
if (deviceUpgrade == null){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
deleteFile(deviceUpgrade.getFileName());
|
||||||
|
return upgradeMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getTopThree")
|
||||||
|
public ResultData<List<DeviceUsageDetailVO>> getTopThree(@RequestParam("usageRecordId") Integer usageRecordId){
|
||||||
|
List<DeviceUsageDetail> deviceUsageDetails = usageDetailMapper.selectTopThree(usageRecordId);
|
||||||
|
List<String> plList = deviceUsageDetails.stream().map(DeviceUsageDetail::getPl).distinct().collect(Collectors.toList());
|
||||||
|
List<DeviceUsageDetailVO> detailList = new ArrayList<>();
|
||||||
|
for (String s : plList) {
|
||||||
|
DeviceUsageDetail maxTime = deviceUsageDetails.stream().filter(detail -> detail.getPl().equals(s)).max((o1, o2) -> o1.getCreateTime().compareTo(o2.getCreateTime())).get();
|
||||||
|
DeviceUsageDetail minTime = deviceUsageDetails.stream().filter(detail -> detail.getPl().equals(s)).min((o1, o2) -> o1.getCreateTime().compareTo(o2.getCreateTime())).get();
|
||||||
|
long seconds = Duration.between(minTime.getCreateTime(), maxTime.getCreateTime()).getSeconds();
|
||||||
|
DeviceUsageDetailVO vo = new DeviceUsageDetailVO();
|
||||||
|
BeanUtils.copyProperties(maxTime,vo);
|
||||||
|
vo.setSustainTime(seconds);
|
||||||
|
detailList.add(vo);
|
||||||
|
}
|
||||||
|
MobileAppUser wxUser = mobileAppUserMapper.selectById(9);
|
||||||
|
TreatParameter treatParameter = treatParameterMapper.selectById(wxUser.getPainNumber());
|
||||||
|
detailList.forEach(detail -> {
|
||||||
|
detail.setUl(treatParameter.getUl());
|
||||||
|
detail.setPw(treatParameter.getPw());
|
||||||
|
detail.setFr(treatParameter.getFr());
|
||||||
|
// detail.setCreateTime(null);
|
||||||
|
});
|
||||||
|
detailList.sort((o1, o2) -> (int) (o2.getSustainTime() - o1.getSustainTime()));
|
||||||
|
return ResultData.success(detailList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysFile;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.enums.FileType;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.service.SysFileService;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
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 javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/27 18:06
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc")
|
||||||
|
public class SysFileController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysFileService sysFileService;
|
||||||
|
|
||||||
|
@PostMapping("/uploadFile")
|
||||||
|
public ResultData uploadFile(@RequestParam("file") MultipartFile file) {
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (StringUtils.isBlank(originalFilename) || originalFilename.lastIndexOf(".") == -1){
|
||||||
|
throw new ServiceException("文件格式不正确");
|
||||||
|
}
|
||||||
|
String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||||
|
Set<String> types = ImmutableSet.of(".png",".jpg",".jpeg",".ico");
|
||||||
|
/*if (!types.contains(fileType)){
|
||||||
|
throw new ServiceException("目前只支持上传png,jpg,jpeg,ico类型文件");
|
||||||
|
}*/
|
||||||
|
String bucketName = FileType.getMinioBucketName(file.getContentType()).getBucketName();
|
||||||
|
return sysFileService.simpleUpload(file, bucketName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editFile")
|
||||||
|
public boolean editFile(){
|
||||||
|
List<SysFile> sysFiles = sysFileService.list();
|
||||||
|
sysFiles.forEach(sysFile -> {
|
||||||
|
String fileUrl = sysFile.getFileUrl();
|
||||||
|
String replace = fileUrl.replace("http://139.9.2.195:8002/", "https://peaktcm.com:8000/");
|
||||||
|
sysFile.setFileUrl(replace);
|
||||||
|
});
|
||||||
|
return sysFileService.updateBatchById(sysFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.*;
|
||||||
|
import cn.unizk.entity.vo.PhysioExamVO;
|
||||||
|
import cn.unizk.entity.vo.PhysioVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.*;
|
||||||
|
import cn.unizk.poi.SubHealthReadListener;
|
||||||
|
import cn.unizk.service.PhysioService;
|
||||||
|
import cn.unizk.service.StoreService;
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.alibaba.excel.read.listener.PageReadListener;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.File;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/9 14:45
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin")
|
||||||
|
public class SysPhysioController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PhysioService physioService;
|
||||||
|
@Resource
|
||||||
|
private StoreService storeService;
|
||||||
|
@Resource
|
||||||
|
private ReportTemplateMapper reportTemplateMapper;
|
||||||
|
@Resource
|
||||||
|
private MobileAppUserMapper mobileAppUserMapper;
|
||||||
|
@Resource
|
||||||
|
private TreatParameterMapper treatParameterMapper;
|
||||||
|
@Resource
|
||||||
|
private SubHealthDietaryRegulationMapper subHealthDietaryRegulationMapper;
|
||||||
|
@Resource
|
||||||
|
private PhysioExamMapper examMapper;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("kryoRedisTemplate")
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
private static final String CACHE_TOKEN_KEY = "jk-applet-";
|
||||||
|
private static final String CACHE_TOKEN_PREFIX = "mobile-t:";
|
||||||
|
|
||||||
|
@PostMapping("/listExamTitle")
|
||||||
|
public Page<PhysioExamVO> listExamTitle(@RequestBody UniPage<PhysioExam> uniPage ){
|
||||||
|
Page<PhysioExam> page = (Page<PhysioExam>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<PhysioExam> lambdaQueryWrapper = uniPage.buildQueryWrapper(q -> {
|
||||||
|
LambdaQueryWrapper<PhysioExam> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.like(StringUtils.isNotBlank(q.getTitle()),PhysioExam::getTitle, q.getTitle());
|
||||||
|
wrapper.orderByAsc(PhysioExam::getSubject);
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
Page<PhysioExam> physioExamPage = examMapper.selectPage(page, lambdaQueryWrapper);
|
||||||
|
List<PhysioExam> records = physioExamPage.getRecords();
|
||||||
|
if (CollectionUtils.isEmpty(records)){
|
||||||
|
return new Page<>();
|
||||||
|
}
|
||||||
|
List<PhysioExamVO> vos = new ArrayList<>();
|
||||||
|
for (PhysioExam exam : records) {
|
||||||
|
PhysioExamVO vo = new PhysioExamVO();
|
||||||
|
String answer = exam.getAnswer();
|
||||||
|
List<String> answers = Arrays.asList(answer.split("&"));
|
||||||
|
vo.setTitle(exam.getTitle());
|
||||||
|
vo.setAnswers(answers);
|
||||||
|
vo.setCorrectAnswer(exam.getCorrectAnswer());
|
||||||
|
vo.setType(exam.getType());
|
||||||
|
vo.setId(exam.getId());
|
||||||
|
vo.setSubject(exam.getSubject());
|
||||||
|
vos.add(vo);
|
||||||
|
}
|
||||||
|
Page<PhysioExamVO> voPage = new Page<>();
|
||||||
|
voPage.setRecords(vos);
|
||||||
|
voPage.setTotal(physioExamPage.getTotal());
|
||||||
|
voPage.setCurrent(physioExamPage.getCurrent());
|
||||||
|
voPage.setSize(physioExamPage.getSize());
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/saveOrUpdate")
|
||||||
|
public Integer saveOrUpdate(@RequestBody PhysioExam exam){
|
||||||
|
if (exam.getAnswer() == null || !exam.getAnswer().contains("&")){
|
||||||
|
throw new ServiceException("选项格式不正确");
|
||||||
|
}
|
||||||
|
if (exam.getSubject() == null){
|
||||||
|
throw new ServiceException("subject必填");
|
||||||
|
}
|
||||||
|
if (exam.getId() == null){
|
||||||
|
return examMapper.insert(exam);
|
||||||
|
}else {
|
||||||
|
return examMapper.updateById(exam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteExamTitle")
|
||||||
|
public Integer deleteExamTitle(@RequestParam(value = "id",required = true) Integer id){
|
||||||
|
return examMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addPhysio")
|
||||||
|
public boolean addPhysio(@RequestBody JkPhysio jkPhysio){
|
||||||
|
JkPhysio one = physioService.getOne(new LambdaQueryWrapper<JkPhysio>().eq(JkPhysio::getPhysioTel, jkPhysio.getPhysioTel()));
|
||||||
|
if (Objects.nonNull(one)){
|
||||||
|
throw new ServiceException("该手机号已被其他理疗师注册");
|
||||||
|
}
|
||||||
|
jkPhysio.setAudit(1);
|
||||||
|
return physioService.save(jkPhysio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/physioList")
|
||||||
|
public Page<PhysioVO> page(@RequestBody UniPage<PhysioVO> uniPage){
|
||||||
|
Page<JkPhysio> page = (Page<JkPhysio>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<JkPhysio> queryWrapper = uniPage.buildQueryWrapper(query -> {
|
||||||
|
LambdaQueryWrapper<JkPhysio> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
if (query.getAudit() == null){
|
||||||
|
wrapper.eq(JkPhysio::getAudit,1);
|
||||||
|
}else {
|
||||||
|
wrapper.eq(JkPhysio::getAudit,query.getAudit());
|
||||||
|
}
|
||||||
|
boolean hasKeyword = StringUtils.isNotBlank(query.getKeyword());
|
||||||
|
wrapper.eq(query.getStoreId() != null, JkPhysio::getStoreId, query.getStoreId())
|
||||||
|
.and(hasKeyword,w -> {
|
||||||
|
w.eq(hasKeyword, JkPhysio::getId, query.getId())
|
||||||
|
.or()
|
||||||
|
.eq(hasKeyword, JkPhysio::getPhysioTel, query.getKeyword())
|
||||||
|
.or()
|
||||||
|
.eq(hasKeyword, JkPhysio::getIdcard, query.getKeyword())
|
||||||
|
.or()
|
||||||
|
.like(hasKeyword, JkPhysio::getPhysioName, query.getKeyword());
|
||||||
|
});
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
Page<JkPhysio> physioPage = physioService.page(page, queryWrapper);
|
||||||
|
List<JkPhysio> records = physioPage.getRecords();
|
||||||
|
List<PhysioVO> list = new ArrayList<>();
|
||||||
|
records.forEach(jkPhysio -> {
|
||||||
|
PhysioVO vo = new PhysioVO();
|
||||||
|
BeanUtils.copyProperties(jkPhysio,vo);
|
||||||
|
JkStore jkStore = storeService.getById(jkPhysio.getStoreId());
|
||||||
|
vo.setStoreName(jkStore.getStoreName());
|
||||||
|
list.add(vo);
|
||||||
|
});
|
||||||
|
Page<PhysioVO> physioVOPage = new Page<>();
|
||||||
|
physioVOPage.setRecords(list);
|
||||||
|
physioVOPage.setCurrent(physioPage.getCurrent());
|
||||||
|
physioVOPage.setSize(physioPage.getSize());
|
||||||
|
physioVOPage.setTotal(physioPage.getTotal());
|
||||||
|
return physioVOPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editPhysioStatus")
|
||||||
|
public boolean editStatus(@RequestParam("id") Integer id,@RequestParam("status") String status){
|
||||||
|
JkPhysio jkPhysio = new JkPhysio();
|
||||||
|
jkPhysio.setId(id);
|
||||||
|
jkPhysio.setStatus(status);
|
||||||
|
return physioService.updateById(jkPhysio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editPhysio")
|
||||||
|
public boolean editPhysio(@RequestBody JkPhysio jkPhysio){
|
||||||
|
JkPhysio one = physioService.getOne(new LambdaQueryWrapper<JkPhysio>().eq(JkPhysio::getPhysioTel, jkPhysio.getPhysioTel()).ne(JkPhysio::getId, jkPhysio.getId()));
|
||||||
|
if (Objects.nonNull(one)){
|
||||||
|
throw new ServiceException("该手机号已被其他理疗师注册");
|
||||||
|
}
|
||||||
|
JkPhysio physio = physioService.getById(jkPhysio.getId());
|
||||||
|
if (!jkPhysio.getPhysioTel().equals(physio.getPhysioTel())){
|
||||||
|
MobileAppUser user = mobileAppUserMapper.selectOne(new LambdaQueryWrapper<MobileAppUser>().eq(MobileAppUser::getPhoneNumber, physio.getPhysioTel()));
|
||||||
|
if (Objects.nonNull(user) && user.getUserType().equals("P")){
|
||||||
|
user.setUserType("C");
|
||||||
|
mobileAppUserMapper.updateById(user);
|
||||||
|
redisTemplate.delete(CACHE_TOKEN_KEY + physio.getPhysioTel());
|
||||||
|
redisTemplate.delete(CACHE_TOKEN_PREFIX + physio.getPhysioTel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return physioService.updateById(jkPhysio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/reports")
|
||||||
|
public List<ReportTemplate> list(){
|
||||||
|
return reportTemplateMapper.selectList(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addReportTemplate")
|
||||||
|
public int addReportTemplate(@RequestBody ReportTemplate template){
|
||||||
|
if (template.getId() == null){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ReportTemplate reportTemplate = reportTemplateMapper.selectById(template.getId());
|
||||||
|
if (Objects.nonNull(reportTemplate)){
|
||||||
|
reportTemplate.setText(template.getText());
|
||||||
|
reportTemplate.setUpdateTime(LocalDateTime.now());
|
||||||
|
return reportTemplateMapper.updateById(reportTemplate);
|
||||||
|
}
|
||||||
|
template.setCreateTime(LocalDateTime.now());
|
||||||
|
return reportTemplateMapper.insert(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/review")
|
||||||
|
public Boolean review(@RequestParam("status") Integer status,@RequestBody JkPhysio physio){
|
||||||
|
Integer id = physio.getId();
|
||||||
|
JkPhysio jkPhysio = new JkPhysio();
|
||||||
|
if (status == 1){
|
||||||
|
jkPhysio.setId(id);
|
||||||
|
jkPhysio.setAudit(1);
|
||||||
|
return physioService.updateById(jkPhysio);
|
||||||
|
}
|
||||||
|
if (status == 2){
|
||||||
|
jkPhysio.setId(id);
|
||||||
|
jkPhysio.setAudit(2);
|
||||||
|
jkPhysio.setRejectReason(physio.getRejectReason());
|
||||||
|
return physioService.updateById(jkPhysio);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/treatParameter")
|
||||||
|
public List<TreatParameter> treatParameters(@RequestParam(value = "name",required = false) String name){
|
||||||
|
return treatParameterMapper.selectList(new LambdaQueryWrapper<TreatParameter>()
|
||||||
|
.like(StringUtils.isNotBlank(name),TreatParameter::getSymptomsName,name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addOrUpdateTreatParameter")
|
||||||
|
public Integer addOrUpdateTreatParameter(@RequestBody TreatParameter parameter){
|
||||||
|
if (parameter.getId() == null){
|
||||||
|
return 0;
|
||||||
|
}else {
|
||||||
|
parameter.setFr(together(parameter.getFr(),true));
|
||||||
|
parameter.setPl(together(parameter.getPl(),true));
|
||||||
|
parameter.setPw(together(parameter.getPw(),true));
|
||||||
|
parameter.setUl(together(parameter.getUl(),true));
|
||||||
|
parameter.setTl(together(parameter.getTl(),false));
|
||||||
|
return treatParameterMapper.updateById(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String together(String p,boolean f){
|
||||||
|
if (StringUtils.isBlank(p)){
|
||||||
|
throw new ServiceException("参数不能为空");
|
||||||
|
}
|
||||||
|
if (f){
|
||||||
|
if (p.length() > 1){
|
||||||
|
return p;
|
||||||
|
}else {
|
||||||
|
return "0" + p;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if (p.length() > 2){
|
||||||
|
return p;
|
||||||
|
}else if (p.length() > 1){
|
||||||
|
return "0" + p;
|
||||||
|
}else {
|
||||||
|
return "00" + p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addDietaryRegulation")
|
||||||
|
public ResultData getPhysio(@Validated @RequestBody SubHealthDietaryRegulation regulation){
|
||||||
|
SubHealthDietaryRegulation subHealthDietaryRegulation = subHealthDietaryRegulationMapper.selectById(regulation.getSymptomNumber());
|
||||||
|
if (Objects.nonNull(subHealthDietaryRegulation)){
|
||||||
|
throw new ServiceException(String.format("已存在【%s】症状编号",regulation.getSymptomNumber()));
|
||||||
|
}
|
||||||
|
return ResultData.success(subHealthDietaryRegulationMapper.insert(regulation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editDietaryRegulation")
|
||||||
|
public ResultData editDietaryRegulation(@Validated @RequestBody SubHealthDietaryRegulation regulation){
|
||||||
|
return ResultData.success(subHealthDietaryRegulationMapper.updateById(regulation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteDietary")
|
||||||
|
public ResultData deleteDietary(@RequestParam("symptomNumber") String symptomNumber){
|
||||||
|
return ResultData.success(subHealthDietaryRegulationMapper.deleteById(symptomNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/listDietary")
|
||||||
|
public IPage<SubHealthDietaryRegulation> listDietary(@RequestBody UniPage<SubHealthDietaryRegulation> uniPage){
|
||||||
|
IPage<SubHealthDietaryRegulation> page = (IPage<SubHealthDietaryRegulation>) uniPage.getPage();
|
||||||
|
SubHealthDietaryRegulation queryBody = uniPage.getQueryBody();
|
||||||
|
String number = null,description=number;
|
||||||
|
if (queryBody != null){
|
||||||
|
number = queryBody.getSymptomNumber();
|
||||||
|
description = queryBody.getSymptomDescription();
|
||||||
|
}
|
||||||
|
List<SubHealthDietaryRegulation> regulations = subHealthDietaryRegulationMapper.selectSubHealth(page, number, description);
|
||||||
|
page.setRecords(regulations);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/readDietaryExcel")
|
||||||
|
public void readDietaryExcel(){
|
||||||
|
File file = new File("E:\\document\\unizk2\\112.xlsx");
|
||||||
|
EasyExcel.read(file,SubHealthDietaryRegulation.class,new SubHealthReadListener(subHealthDietaryRegulationMapper)).sheet().doRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.mapper.DailySchedulesMapper;
|
||||||
|
import cn.unizk.mapper.JkPhysioMapper;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/5/19 17:30
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/scheduling")
|
||||||
|
public class SysPhysioPaiBanController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DailySchedulesMapper dailySchedulesMapper;
|
||||||
|
@Resource
|
||||||
|
private JkPhysioMapper jkPhysioMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/getScheduling")
|
||||||
|
public void getScheduling(){}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkProduct;
|
||||||
|
import cn.unizk.entity.po.ProductCarousel;
|
||||||
|
import cn.unizk.entity.po.SysDict;
|
||||||
|
import cn.unizk.entity.vo.*;
|
||||||
|
import cn.unizk.enums.DictType;
|
||||||
|
import cn.unizk.enums.ProductType;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.service.ProductCarouselService;
|
||||||
|
import cn.unizk.service.ProductService;
|
||||||
|
import cn.unizk.service.SysDictService;
|
||||||
|
import cn.unizk.validatedGroup.DefaultGroup;
|
||||||
|
import cn.unizk.validatedGroup.UpdateGroup;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/3 11:51
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/product")
|
||||||
|
public class SysProductController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysDictService dictService;
|
||||||
|
@Resource
|
||||||
|
private ProductService productService;
|
||||||
|
@Resource
|
||||||
|
private ProductCarouselService carouselService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/list")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public Page<JkProduct> list(@RequestBody UniPage<ProductReqVO> uniPage) {
|
||||||
|
Page<JkProduct> page = new Page<>();
|
||||||
|
page.setCurrent(uniPage.getCurrentPage());
|
||||||
|
page.setSize(uniPage.getPageSize());
|
||||||
|
ProductReqVO queryBody = uniPage.getQueryBody();
|
||||||
|
if (Objects.isNull(queryBody)) {
|
||||||
|
return productService.page(page, null);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<JkProduct> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(StringUtils.isNotBlank(queryBody.getProductType()), JkProduct::getProductType, queryBody.getProductType())
|
||||||
|
.eq(StringUtils.isNotBlank(queryBody.getStatus()), JkProduct::getProductStatus, queryBody.getStatus())
|
||||||
|
.eq("0".equals(queryBody.getStockType()), JkProduct::getProductStock, 0)
|
||||||
|
.gt("1".equals(queryBody.getStockType()), JkProduct::getProductStock, 0)
|
||||||
|
.lt("2".equals(queryBody.getStockType()), JkProduct::getProductStock, 100)
|
||||||
|
.like(StringUtils.isNotBlank(queryBody.getProductName()), JkProduct::getProductName, queryBody.getProductName());
|
||||||
|
return productService.page(page, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/addProduct")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean addProduct(@Validated(DefaultGroup.class) @RequestBody JkProductVO productVO) {
|
||||||
|
SysDict one = dictService.getOne(new LambdaQueryWrapper<SysDict>()
|
||||||
|
.eq(SysDict::getDictType, DictType.product.name())
|
||||||
|
.eq(SysDict::getDictValue, productVO.getProductType()));
|
||||||
|
if (Objects.isNull(one)) {
|
||||||
|
throw new ServiceException("不存在此商品类型");
|
||||||
|
}
|
||||||
|
JkProduct product = new JkProduct();
|
||||||
|
BeanUtils.copyProperties(productVO,product);
|
||||||
|
List<ProductCarousel> productCarousels = productVO.getProductCarousels();
|
||||||
|
if (CollectionUtils.isNotEmpty(productCarousels)){
|
||||||
|
product.setProductImage(productCarousels.get(0).getImageUrl());
|
||||||
|
}
|
||||||
|
productService.save(product);
|
||||||
|
if (CollectionUtils.isNotEmpty(productCarousels)){
|
||||||
|
productCarousels.forEach(s -> {
|
||||||
|
s.setProductId(product.getProductId());
|
||||||
|
s.setType("inner");
|
||||||
|
});
|
||||||
|
carouselService.saveBatch(productCarousels);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editProduct")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean editPorduct(@Validated(UpdateGroup.class) @RequestBody JkProductVO vo) {
|
||||||
|
SysDict one = dictService.getOne(new LambdaQueryWrapper<SysDict>()
|
||||||
|
.eq(SysDict::getDictType, DictType.product.name())
|
||||||
|
.eq(SysDict::getDictValue, vo.getProductType()));
|
||||||
|
if (Objects.isNull(one)) {
|
||||||
|
throw new ServiceException("不存在此商品类型");
|
||||||
|
}
|
||||||
|
JkProduct product = new JkProduct();
|
||||||
|
BeanUtils.copyProperties(vo,product);
|
||||||
|
List<ProductCarousel> productCarousels = vo.getProductCarousels();
|
||||||
|
if (CollectionUtils.isNotEmpty(productCarousels)){
|
||||||
|
product.setProductImage(productCarousels.get(0).getImageUrl());
|
||||||
|
}
|
||||||
|
productService.updateById(product);
|
||||||
|
if (CollectionUtils.isNotEmpty(productCarousels)){
|
||||||
|
carouselService.remove(new LambdaQueryWrapper<ProductCarousel>()
|
||||||
|
.eq(ProductCarousel::getProductId,product.getProductId()));
|
||||||
|
productCarousels.forEach(s -> {
|
||||||
|
s.setProductId(product.getProductId());
|
||||||
|
s.setType("inner");
|
||||||
|
});
|
||||||
|
carouselService.saveBatch(productCarousels);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/echoEditProduct")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public JkProductVO echoEditProduct(@RequestParam("id") Integer id){
|
||||||
|
return productService.echo(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/listType")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public Page<ProductTypeVO> listType(UniPage uniPage, @RequestParam(value = "status", required = false) String status,
|
||||||
|
@RequestParam(value = "typeName", required = false) String typeName) {
|
||||||
|
Page<SysDict> page = new Page<>();
|
||||||
|
page.setSize(uniPage.getPageSize());
|
||||||
|
page.setCurrent(uniPage.getCurrentPage());
|
||||||
|
Page<SysDict> dictPage = dictService.page(page, new LambdaQueryWrapper<SysDict>()
|
||||||
|
.eq(SysDict::getDictType, DictType.product.name())
|
||||||
|
.eq(StringUtils.isNotBlank(status), SysDict::getStatus, status)
|
||||||
|
.like(StringUtils.isNotBlank(typeName), SysDict::getDictValue, typeName));
|
||||||
|
List<SysDict> list = dictPage.getRecords();
|
||||||
|
List<ProductTypeVO> productTypeVOS = new ArrayList<>();
|
||||||
|
list.forEach(sysDict -> {
|
||||||
|
ProductTypeVO vo = new ProductTypeVO();
|
||||||
|
vo.setDictCode(sysDict.getDictCode());
|
||||||
|
vo.setPcDisplayImage(sysDict.getPcDisplayImage());
|
||||||
|
vo.setStatus(sysDict.getStatus());
|
||||||
|
vo.setTypeName(sysDict.getDictValue());
|
||||||
|
productTypeVOS.add(vo);
|
||||||
|
});
|
||||||
|
Page<ProductTypeVO> productTypeVOPage = new Page<>();
|
||||||
|
productTypeVOPage.setCurrent(dictPage.getCurrent());
|
||||||
|
productTypeVOPage.setSize(dictPage.getSize());
|
||||||
|
productTypeVOPage.setRecords(productTypeVOS);
|
||||||
|
productTypeVOPage.setTotal(dictPage.getTotal());
|
||||||
|
return productTypeVOPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addType")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public ResultData addType(@RequestBody ProductTypeVO vo) {
|
||||||
|
if (StringUtils.isBlank(vo.getTypeName()) || StringUtils.isBlank(vo.getStatus())) {
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
SysDict one = dictService.getOne(new LambdaQueryWrapper<SysDict>()
|
||||||
|
.eq(SysDict::getDictType, DictType.product.name())
|
||||||
|
.eq(SysDict::getDictValue, vo.getTypeName()));
|
||||||
|
if (Objects.nonNull(one)) {
|
||||||
|
return ResultData.failure(500, "已存在该商品类型");
|
||||||
|
}
|
||||||
|
SysDict sysDict = new SysDict();
|
||||||
|
sysDict.setDictType(DictType.product.name());
|
||||||
|
sysDict.setDictValue(vo.getTypeName());
|
||||||
|
sysDict.setPcDisplayImage(vo.getPcDisplayImage());
|
||||||
|
sysDict.setStatus(vo.getStatus());
|
||||||
|
dictService.save(sysDict);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editProductType")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public ResultData editProductType(@Valid @RequestBody ProductTypeVO vo) {
|
||||||
|
SysDict one = dictService.getOne(new LambdaQueryWrapper<SysDict>()
|
||||||
|
.eq(SysDict::getDictType, DictType.product.name())
|
||||||
|
.eq(SysDict::getDictValue, vo.getTypeName())
|
||||||
|
.ne(SysDict::getDictCode, vo.getDictCode()));
|
||||||
|
if (Objects.nonNull(one)) {
|
||||||
|
throw new ServiceException("已存在该商品类型");
|
||||||
|
}
|
||||||
|
SysDict sysDict = new SysDict();
|
||||||
|
sysDict.setDictValue(vo.getTypeName());
|
||||||
|
sysDict.setDictCode(vo.getDictCode());
|
||||||
|
sysDict.setPcDisplayImage(vo.getPcDisplayImage());
|
||||||
|
sysDict.setStatus(vo.getStatus());
|
||||||
|
sysDict.setDictType(DictType.product.name());
|
||||||
|
dictService.updateById(sysDict);
|
||||||
|
return ResultData.success();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteProductType/{dictCode}")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean deleteType(@PathVariable("dictCode") Integer dictCode){
|
||||||
|
SysDict sysDict = dictService.getById(dictCode);
|
||||||
|
List<JkProduct> products = productService.list(new LambdaQueryWrapper<JkProduct>().eq(JkProduct::getProductType, sysDict.getDictValue()));
|
||||||
|
if (CollectionUtils.isNotEmpty(products)){
|
||||||
|
throw new ServiceException("存在此类型的商品,请先删除商品");
|
||||||
|
}
|
||||||
|
return dictService.remove(new LambdaQueryWrapper<SysDict>()
|
||||||
|
.eq(SysDict::getDictType,DictType.product.name()).eq(SysDict::getDictCode,dictCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteProducts")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public boolean deleteProducts(@RequestBody List<Integer> productIds){
|
||||||
|
if (CollectionUtils.isEmpty(productIds)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return productService.removeBatchByIds(productIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/setUpCarousel")
|
||||||
|
public boolean setUpCarousel(@RequestParam("productId") Integer productId,@RequestParam("isCarousel") Integer isCarousel){
|
||||||
|
if (isCarousel == 1){
|
||||||
|
List<JkProduct> products = productService.list(new LambdaQueryWrapper<JkProduct>().eq(JkProduct::getProductStatus, "上架")
|
||||||
|
.eq(JkProduct::getWhetherCarousel, 1));
|
||||||
|
if (products != null && products.size() >= 3){
|
||||||
|
throw new ServiceException("首页轮播图最多设置3张,请先移除一张再设置");
|
||||||
|
}
|
||||||
|
JkProduct jkProduct = productService.getById(productId);
|
||||||
|
if (Objects.isNull(jkProduct)){
|
||||||
|
throw new ServiceException("此商品不存在");
|
||||||
|
}
|
||||||
|
jkProduct.setWhetherCarousel(1);
|
||||||
|
productService.updateById(jkProduct);
|
||||||
|
// carouselService.remove(new LambdaQueryWrapper<ProductCarousel>().eq(ProductCarousel::getType, "outer"));
|
||||||
|
ProductCarousel carousel = new ProductCarousel();
|
||||||
|
carousel.setProductId(productId);
|
||||||
|
carousel.setImageUrl(jkProduct.getProductImage());
|
||||||
|
carousel.setType("outer");
|
||||||
|
return carouselService.save(carousel);
|
||||||
|
}else if (isCarousel == 0){
|
||||||
|
List<JkProduct> products = productService.list(new LambdaQueryWrapper<JkProduct>().eq(JkProduct::getProductStatus, "上架")
|
||||||
|
.eq(JkProduct::getWhetherCarousel, 1));
|
||||||
|
if (products == null || products.size() < 2){
|
||||||
|
throw new ServiceException("至少保留一张轮播图");
|
||||||
|
}
|
||||||
|
JkProduct jkProduct = productService.getById(productId);
|
||||||
|
jkProduct.setWhetherCarousel(0);
|
||||||
|
productService.updateById(jkProduct);
|
||||||
|
return carouselService.remove(new LambdaQueryWrapper<ProductCarousel>()
|
||||||
|
.eq(ProductCarousel::getProductId,productId)
|
||||||
|
.eq(ProductCarousel::getType,"outer"));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.BusinessChannel;
|
||||||
|
import cn.unizk.entity.po.Device;
|
||||||
|
import cn.unizk.entity.po.JkStore;
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import cn.unizk.entity.vo.JkStoreReqVO;
|
||||||
|
import cn.unizk.entity.vo.JkStoreResVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.DeviceMapper;
|
||||||
|
import cn.unizk.service.BusinessChannelService;
|
||||||
|
import cn.unizk.service.StoreService;
|
||||||
|
import cn.unizk.service.SysUserService;
|
||||||
|
import cn.unizk.utils.BeanCopyUtils;
|
||||||
|
import cn.unizk.utils.MapUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/8 11:58
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin")
|
||||||
|
public class SysStoreController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StoreService storeService;
|
||||||
|
@Resource
|
||||||
|
private SysUserService userService;
|
||||||
|
@Resource
|
||||||
|
private BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||||
|
@Resource
|
||||||
|
private BusinessChannelService businessChannelService;
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
|
||||||
|
@PostMapping("/storeList")
|
||||||
|
public Page<JkStoreResVO> list(@RequestBody UniPage<JkStoreReqVO> uniPage){
|
||||||
|
Page<JkStore> page = (Page<JkStore>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<JkStore> lambdaQueryWrapper = uniPage.buildQueryWrapper(query -> {
|
||||||
|
LambdaQueryWrapper<JkStore> w = new LambdaQueryWrapper<>();
|
||||||
|
String keyword = query.getKeyword();
|
||||||
|
boolean hasKeyword = StringUtils.isNotBlank(keyword);
|
||||||
|
w.eq(StringUtils.isNotBlank(query.getStatus()),JkStore::getStatus,query.getStatus());
|
||||||
|
w.and(hasKeyword, wrapper ->
|
||||||
|
wrapper.like(hasKeyword, JkStore::getStoreName, keyword)
|
||||||
|
.or()
|
||||||
|
.like(hasKeyword, JkStore::getAddress, keyword)
|
||||||
|
.or()
|
||||||
|
.eq(hasKeyword, JkStore::getContactTel, keyword)
|
||||||
|
);
|
||||||
|
return w;
|
||||||
|
});
|
||||||
|
|
||||||
|
Page<JkStore> jkStorePage = storeService.page(page, lambdaQueryWrapper);
|
||||||
|
Page<JkStoreResVO> resVOPage = new Page<>();
|
||||||
|
resVOPage.setCurrent(jkStorePage.getCurrent());
|
||||||
|
resVOPage.setSize(jkStorePage.getSize());
|
||||||
|
resVOPage.setTotal(jkStorePage.getTotal());
|
||||||
|
List<JkStore> records = jkStorePage.getRecords();
|
||||||
|
Collection<JkStoreResVO> jkStoreResVOS = BeanCopyUtils.copyArrays(records, JkStoreResVO::new);
|
||||||
|
for (JkStoreResVO vo : jkStoreResVOS) {
|
||||||
|
Integer channelId = vo.getChannelId();
|
||||||
|
if (channelId == null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BusinessChannel businessChannel = businessChannelService.getById(channelId);
|
||||||
|
vo.setBusinessChannel(businessChannel);
|
||||||
|
}
|
||||||
|
resVOPage.setRecords((List<JkStoreResVO>) jkStoreResVOS);
|
||||||
|
return resVOPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/echoAccount")
|
||||||
|
public JkStoreResVO echoAccount(@RequestParam("storeId") Integer storeId){
|
||||||
|
SysUser one = userService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getStoreId, storeId));
|
||||||
|
JkStore byId = storeService.getById(storeId);
|
||||||
|
JkStoreResVO vo = new JkStoreResVO();
|
||||||
|
vo.setContactTel(byId.getContactTel());
|
||||||
|
if (Objects.nonNull(one)){
|
||||||
|
vo.setSysUser(one);
|
||||||
|
}
|
||||||
|
vo.setId(storeId);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/initAccount")
|
||||||
|
public ResultData initAccount(@RequestBody JkStoreReqVO vo){
|
||||||
|
if (vo.getId() == null){
|
||||||
|
throw new ServiceException("门店id必传");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(vo.getUsername()) || StringUtils.isBlank(vo.getPassword())){
|
||||||
|
throw new ServiceException("账号密码必传");
|
||||||
|
}
|
||||||
|
JkStore jkStore = storeService.getById(vo.getId());
|
||||||
|
if (Objects.isNull(jkStore)){
|
||||||
|
throw new ServiceException("无此门店,请核对信息");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(vo.getContactTel())){
|
||||||
|
jkStore.setContactTel(vo.getContactTel());
|
||||||
|
}
|
||||||
|
SysUser one = userService.getOne(new LambdaQueryWrapper<SysUser>()
|
||||||
|
.eq(SysUser::getStoreId, vo.getId()));
|
||||||
|
storeService.updateById(jkStore);
|
||||||
|
String encode = bCryptPasswordEncoder.encode(vo.getPassword());
|
||||||
|
if (Objects.isNull(one)){
|
||||||
|
SysUser user = new SysUser();
|
||||||
|
user.setPassword(encode);
|
||||||
|
user.setCreateTime(LocalDateTime.now());
|
||||||
|
user.setUsername(vo.getUsername());
|
||||||
|
userService.save(user);
|
||||||
|
}else {
|
||||||
|
one.setUsername(vo.getUsername());
|
||||||
|
one.setPassword(encode);
|
||||||
|
one.setStoreId(vo.getId());
|
||||||
|
one.setUpdateTime(LocalDateTime.now());
|
||||||
|
userService.updateById(one);
|
||||||
|
}
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/closeOrOpen")
|
||||||
|
public ResultData closed(@RequestParam("storeId") Integer storeId,@RequestParam("status") String status){
|
||||||
|
JkStore jkStore = storeService.getById(storeId);
|
||||||
|
if (Objects.isNull(jkStore)){
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
jkStore.setStatus(status);
|
||||||
|
storeService.updateById(jkStore);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addStore")
|
||||||
|
public ResultData addStore(@RequestBody JkStoreReqVO vo){
|
||||||
|
JkStore loLa = MapUtil.getLoLa(vo.getAddress());
|
||||||
|
JkStore jkStore = new JkStore();
|
||||||
|
BeanUtils.copyProperties(vo,jkStore);
|
||||||
|
if (loLa != null){
|
||||||
|
jkStore.setLatitude(loLa.getLatitude());
|
||||||
|
jkStore.setLongitude(loLa.getLongitude());
|
||||||
|
}
|
||||||
|
storeService.save(jkStore);
|
||||||
|
SysUser user = new SysUser();
|
||||||
|
user.setStoreId(jkStore.getId());
|
||||||
|
user.setUsername(vo.getUsername());
|
||||||
|
user.setPassword(bCryptPasswordEncoder.encode(vo.getPassword()));
|
||||||
|
user.setCreateTime(LocalDateTime.now());
|
||||||
|
userService.save(user);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editStore")
|
||||||
|
public boolean editStore(@RequestBody JkStore jkStore){
|
||||||
|
List<Device> deviceList = deviceMapper.selectList(new LambdaQueryWrapper<Device>().eq(Device::getStoreId, jkStore.getId()));
|
||||||
|
if (CollectionUtils.isNotEmpty(deviceList)){
|
||||||
|
deviceList.forEach(device -> {
|
||||||
|
device.setAffiliatedWith(jkStore.getStoreName());
|
||||||
|
});
|
||||||
|
deviceMapper.updateById(deviceList);
|
||||||
|
}
|
||||||
|
JkStore loLa = MapUtil.getLoLa(jkStore.getAddress());
|
||||||
|
if (loLa != null){
|
||||||
|
jkStore.setLongitude(loLa.getLongitude());
|
||||||
|
jkStore.setLatitude(loLa.getLatitude());
|
||||||
|
}
|
||||||
|
return storeService.updateById(jkStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.SysUserVO2;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.service.SysUserService;
|
||||||
|
import cn.unizk.utils.SecurityUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/6/6 17:30
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/admin/sysUser")
|
||||||
|
public class SysUserController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysUserService sysUserService;
|
||||||
|
@Resource
|
||||||
|
private BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||||
|
|
||||||
|
@PostMapping("/getSysUsers")
|
||||||
|
public Page<SysUser> getSysUser(@RequestBody UniPage<SysUser> uniPage){
|
||||||
|
Page<SysUser> page = (Page<SysUser>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<SysUser> queryWrapper = uniPage.buildQueryWrapper(wrapper -> {
|
||||||
|
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
lambdaQueryWrapper.eq(StringUtils.isNotBlank(wrapper.getUsername()), SysUser::getUsername, wrapper.getUsername())
|
||||||
|
.eq(StringUtils.isNotBlank(wrapper.getStatus()), SysUser::getStatus, wrapper.getStatus())
|
||||||
|
.eq(SysUser::getRole,"ROLE_ADMIN");
|
||||||
|
return lambdaQueryWrapper;
|
||||||
|
});
|
||||||
|
return sysUserService.page(page,queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editPwd")
|
||||||
|
public ResultData addOrUpdate(@RequestBody SysUserVO2 sysUserVO2){
|
||||||
|
SysUser currentUser = SecurityUtils.getSysUser();
|
||||||
|
SysUser user = sysUserService.getById(currentUser.getId());
|
||||||
|
if (!currentUser.getUsername().equals("admin") && !bCryptPasswordEncoder.matches(sysUserVO2.getOriginalPassword(),user.getPassword())){
|
||||||
|
throw new ServiceException("您输入的原始密码不正确!");
|
||||||
|
}
|
||||||
|
/*if (!"admin".equals(currentUser.getUsername())){
|
||||||
|
if (!user.getId().equals(sysUserVO2.getId())){
|
||||||
|
throw new ServiceException("您无权修改他人的账户密码");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
SysUser byId = sysUserService.getById(sysUserVO2.getId());
|
||||||
|
if (Objects.isNull(byId)) throw new ServiceException("用户不存在");
|
||||||
|
if (byId.getUsername().equals("admin")){
|
||||||
|
throw new ServiceException("无权修改admin账户");
|
||||||
|
}
|
||||||
|
SysUser sysUser = new SysUser();
|
||||||
|
|
||||||
|
sysUser.setId(sysUserVO2.getId());
|
||||||
|
sysUser.setPassword(bCryptPasswordEncoder.encode(sysUserVO2.getNewPassword()));
|
||||||
|
sysUser.setRole("ROLE_ADMIN");
|
||||||
|
sysUser.setUpdateTime(LocalDateTime.now());
|
||||||
|
sysUserService.updateById(sysUser);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/editSysUser")
|
||||||
|
public ResultData editSysUser(@RequestBody SysUser sysUser){
|
||||||
|
SysUser user = SecurityUtils.getSysUser();
|
||||||
|
/*if (!user.getUsername().equals("admin") && !user.getId().equals(sysUser.getId())){
|
||||||
|
throw new ServiceException("您无权修改他人的账户密码!");
|
||||||
|
}*/
|
||||||
|
SysUser byId = sysUserService.getById(sysUser.getId());
|
||||||
|
if (Objects.isNull(byId)) throw new ServiceException("用户不存在");
|
||||||
|
if (byId.getUsername().equals("admin") && !user.getUsername().equals("admin")) throw new ServiceException("无权修改admin账户");
|
||||||
|
sysUser.setPassword(null);
|
||||||
|
sysUser.setUpdateTime(LocalDateTime.now());
|
||||||
|
sysUserService.updateById(sysUser);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/addSysUser")
|
||||||
|
public ResultData addSysUser(@RequestBody SysUser sysUser){
|
||||||
|
if ("admin".equals(sysUser.getDept())){
|
||||||
|
sysUser.setDept(null);
|
||||||
|
}
|
||||||
|
SysUser one = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, sysUser.getUsername()));
|
||||||
|
if (Objects.nonNull(one)){
|
||||||
|
throw new ServiceException(String.format("【%s】用户名已存在",one.getUsername()));
|
||||||
|
}
|
||||||
|
sysUser.setId(null);
|
||||||
|
String encode = bCryptPasswordEncoder.encode(sysUser.getPassword());
|
||||||
|
sysUser.setPassword(encode);
|
||||||
|
sysUser.setRole("ROLE_ADMIN");
|
||||||
|
sysUser.setCreateTime(LocalDateTime.now());
|
||||||
|
return sysUserService.save(sysUser) ? ResultData.success() : ResultData.failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/deleteSysUser")
|
||||||
|
public ResultData delete(@RequestParam("id") Integer id){
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (!sysUser.getId().equals(id) && !sysUser.getUsername().equals("admin")) throw new ServiceException("您无权删除他人账号!");
|
||||||
|
sysUserService.removeById(id);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.UserTreatmentParameters;
|
||||||
|
import cn.unizk.mapper.UserTreatmentParametersMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/5/8 11:50
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/userTreat")
|
||||||
|
public class UserTreatController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserTreatmentParametersMapper userTreatmentParametersMapper;
|
||||||
|
|
||||||
|
@GetMapping("/lookTreat")
|
||||||
|
public List<UserTreatmentParameters> lookTreat(@RequestParam(value = "deviceId",required = false) String deviceId){
|
||||||
|
if (StringUtils.isBlank(deviceId)){
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return userTreatmentParametersMapper.selectList(new LambdaQueryWrapper<UserTreatmentParameters>()
|
||||||
|
.eq(UserTreatmentParameters::getStatus,1).eq(UserTreatmentParameters::getDeviceId,deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.properties.SysWxProperties;
|
||||||
|
import cn.unizk.service.SysOrderService;
|
||||||
|
import cn.unizk.service.WxAuthLoginService;
|
||||||
|
import cn.unizk.utils.HttpUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/11 10:39
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/wx")
|
||||||
|
public class WxAuthLoginController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WxAuthLoginService wxAuthLoginService;
|
||||||
|
@Resource
|
||||||
|
private SysWxProperties wxProperties;
|
||||||
|
/*@Resource
|
||||||
|
private WxUserService userService;*/
|
||||||
|
@Resource
|
||||||
|
private SysOrderService orderService;
|
||||||
|
|
||||||
|
private static String getTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=${1}&secret=${2}&code=${3}&grant_type=authorization_code";
|
||||||
|
|
||||||
|
@GetMapping("/auth")
|
||||||
|
public void auth(HttpServletResponse response,@RequestParam("deviceId") String deviceId) throws IOException {
|
||||||
|
wxAuthLoginService.auth(response,deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @GetMapping("/authCallback")
|
||||||
|
public void authCallback(HttpServletResponse response,@RequestParam("code") String code,@RequestParam("state") String state) throws IOException {
|
||||||
|
getTokenUrl = getTokenUrl.replace("${1}",wxProperties.getAppid()).replace("${2}",wxProperties.getSecret())
|
||||||
|
.replace("${3}",code);
|
||||||
|
|
||||||
|
String s = HttpUtil.doGet(getTokenUrl, null, null);
|
||||||
|
JSONObject res = JSONObject.parseObject(s);
|
||||||
|
String openid = res.getString("openid");
|
||||||
|
WxUser wxUser = userService.getOne(new LambdaQueryWrapper<WxUser>().eq(WxUser::getOpenid, openid));
|
||||||
|
if (Objects.isNull(wxUser)){
|
||||||
|
throw new ServiceException("您不是吉客中医微信小程序的用户");
|
||||||
|
}
|
||||||
|
List<WxOrder> wxOrders = orderService.getBaseMapper().selectList(new LambdaQueryWrapper<WxOrder>().eq(WxOrder::getOpenid, openid)
|
||||||
|
.eq(WxOrder::getDeviceId, state));
|
||||||
|
if (CollectionUtils.isEmpty(wxOrders)){
|
||||||
|
throw new ServiceException("抱歉,您在此设备上没有购买套餐");
|
||||||
|
}
|
||||||
|
//重定向到h5页面,携带openid和deviceId
|
||||||
|
String redirectUrl = "http://369.peaktcm.com:9000/combo.html?deviceId=" + state + "&openid=" + openid;
|
||||||
|
response.sendRedirect(redirectUrl);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package cn.unizk.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkPhysio;
|
||||||
|
import cn.unizk.entity.po.JkStore;
|
||||||
|
import cn.unizk.entity.po.MobileAppUser;
|
||||||
|
import cn.unizk.entity.po.UserFreeTrialInfo;
|
||||||
|
import cn.unizk.entity.vo.AppUserDetailsVO;
|
||||||
|
import cn.unizk.entity.vo.MobileAppUserVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.JkPhysioMapper;
|
||||||
|
import cn.unizk.mapper.MobileAppUserMapper;
|
||||||
|
import cn.unizk.mapper.StoreMapper;
|
||||||
|
import cn.unizk.mapper.UserFreeTrialInfoMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/8 11:25
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pc/wxUser")
|
||||||
|
public class WxUserController {
|
||||||
|
|
||||||
|
/* @Resource
|
||||||
|
private WxUserService wxUserService;
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private MobileAppUserMapper mobileAppUserMapper;
|
||||||
|
@Resource
|
||||||
|
private UserFreeTrialInfoMapper userFreeTrialInfoMapper;
|
||||||
|
@Resource
|
||||||
|
private JkPhysioMapper jkPhysioMapper;
|
||||||
|
@Resource
|
||||||
|
private StoreMapper storeMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/list")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public Page<MobileAppUser> list(@RequestBody UniPage<MobileAppUserVO> uniPage){
|
||||||
|
Page<MobileAppUser> page = (Page<MobileAppUser>) uniPage.getPage();
|
||||||
|
LambdaQueryWrapper<MobileAppUser> queryWrapper = uniPage.buildQueryWrapper(query -> {
|
||||||
|
boolean hasKeyword = StringUtils.isNotBlank(query.getKeyword());
|
||||||
|
LambdaQueryWrapper<MobileAppUser> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(query.getId() != null, MobileAppUser::getId, query.getId())
|
||||||
|
.and(hasKeyword,w -> {
|
||||||
|
w.eq(hasKeyword, MobileAppUser::getPhoneNumber, query.getKeyword())
|
||||||
|
.or()
|
||||||
|
.like(hasKeyword, MobileAppUser::getNickname, query.getKeyword());
|
||||||
|
});
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
return mobileAppUserMapper.selectPage(page,queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getUserDetails")
|
||||||
|
public AppUserDetailsVO getUserDetails(@RequestParam("appUserId") Integer appUserId){
|
||||||
|
UserFreeTrialInfo userFreeTrialInfo = userFreeTrialInfoMapper.selectOne(new LambdaQueryWrapper<UserFreeTrialInfo>()
|
||||||
|
.eq(UserFreeTrialInfo::getUserId, appUserId));
|
||||||
|
MobileAppUser user = mobileAppUserMapper.selectById(appUserId);
|
||||||
|
AppUserDetailsVO vo = new AppUserDetailsVO();
|
||||||
|
if (user.getFirstPhysioId() != null && user.getFirstStoreId() != null){
|
||||||
|
JkPhysio jkPhysio = jkPhysioMapper.selectById(user.getFirstPhysioId());
|
||||||
|
JkStore jkStore = storeMapper.selectById(user.getFirstStoreId());
|
||||||
|
vo.setFirstPhysioName(jkPhysio.getPhysioName());
|
||||||
|
vo.setFirstStoreName(jkStore.getStoreName());
|
||||||
|
}
|
||||||
|
if (Objects.isNull(userFreeTrialInfo)){
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
vo.setSymptomPosition(userFreeTrialInfo.getSymptomPosition());
|
||||||
|
Map<Integer,String> castLevelMap = new HashMap<>();
|
||||||
|
castLevelMap.put(1,"轻度");
|
||||||
|
castLevelMap.put(2,"中度");
|
||||||
|
castLevelMap.put(3,"重度");
|
||||||
|
vo.setStrainLevel(castLevelMap.get(userFreeTrialInfo.getStrainLevel()));
|
||||||
|
vo.setRestrict(castLevelMap.get(userFreeTrialInfo.getRestrictedDegree()));
|
||||||
|
castLevelMap.clear();
|
||||||
|
castLevelMap.put(1,"低");
|
||||||
|
castLevelMap.put(2,"中");
|
||||||
|
castLevelMap.put(3,"高");
|
||||||
|
vo.setConsumptionLevel(castLevelMap.get(userFreeTrialInfo.getConsumptionLevel()));
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/writeOff")
|
||||||
|
public ResultData writeOff(@RequestParam("appUserId") Integer appUserId){
|
||||||
|
UserFreeTrialInfo userFreeTrialInfo = userFreeTrialInfoMapper.selectOne(new LambdaQueryWrapper<UserFreeTrialInfo>()
|
||||||
|
.eq(UserFreeTrialInfo::getUserId, appUserId));
|
||||||
|
if (Objects.isNull(userFreeTrialInfo)){
|
||||||
|
throw new ServiceException("用户尚未填写首次免费体验信息,无法核销!");
|
||||||
|
}
|
||||||
|
MobileAppUser user = new MobileAppUser();
|
||||||
|
user.setId(appUserId);
|
||||||
|
user.setFreeTrial(0);
|
||||||
|
mobileAppUserMapper.updateById(user);
|
||||||
|
return ResultData.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package cn.unizk.entity.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/9/17 11:55
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class AppointmentDTO {
|
||||||
|
|
||||||
|
private String physioName;
|
||||||
|
|
||||||
|
private String patientName;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd",timezone="GMT+8")
|
||||||
|
private LocalDate visitDate;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package cn.unizk.entity.dto;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkStore;
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:37
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoginUser implements UserDetails {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private SysUser sysUser;
|
||||||
|
|
||||||
|
private Long loginTime;
|
||||||
|
|
||||||
|
private Long expireTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限列表
|
||||||
|
*/
|
||||||
|
private Set<String> permissions;
|
||||||
|
|
||||||
|
public LoginUser(){}
|
||||||
|
|
||||||
|
public LoginUser(Integer userId,SysUser sysUser,Set<String> permissions){
|
||||||
|
this.id = userId;
|
||||||
|
this.sysUser = sysUser;
|
||||||
|
this.permissions = permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginUser(SysUser sysUser){
|
||||||
|
this.sysUser = sysUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
if (this.permissions == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return permissions.stream()
|
||||||
|
.map(SimpleGrantedAuthority::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
return sysUser.getPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return sysUser.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonLocked() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package cn.unizk.entity.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/10/20 18:31
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
public class InStockVO {
|
||||||
|
|
||||||
|
private Integer rescode;
|
||||||
|
|
||||||
|
private Boolean success = true;
|
||||||
|
|
||||||
|
private String resmsg = "success_";
|
||||||
|
|
||||||
|
private JSONObject data;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package cn.unizk.entity.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/5/19 17:33
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class PhysioScheduleVO {
|
||||||
|
|
||||||
|
private String m1;
|
||||||
|
|
||||||
|
private String m2;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package cn.unizk.entity.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/3 11:56
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class ProductTypeVO {
|
||||||
|
|
||||||
|
@NotNull(message = "dictCode cannot be null")
|
||||||
|
private Integer dictCode;
|
||||||
|
@NotBlank(message = "typeName cannot be null")
|
||||||
|
private String typeName;
|
||||||
|
private String pcDisplayImage;
|
||||||
|
@NotBlank(message = "status cannot be null")
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package cn.unizk.entity.vo;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/25 15:04
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SysUserVO extends SysUser {
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private String storeName;
|
||||||
|
|
||||||
|
private String storeImage;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkPhysio;
|
||||||
|
|
||||||
|
public interface JkPhysioMapper extends UniBaseMapper<JkPhysio> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkProduct;
|
||||||
|
import cn.unizk.entity.vo.JkProductVO;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
public interface JkProductMapper extends UniBaseMapper<JkProduct> {
|
||||||
|
|
||||||
|
JkProductVO selectProductVO(@Param("id") Integer id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Menu;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MenuMapper extends UniBaseMapper<Menu> {
|
||||||
|
|
||||||
|
List<Menu> selectAdminMenuList();
|
||||||
|
|
||||||
|
List<Menu> selectStoreMenuList();
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.ProductCarousel;
|
||||||
|
|
||||||
|
public interface ProductCarouselMapper extends UniBaseMapper<ProductCarousel> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkStore;
|
||||||
|
|
||||||
|
public interface StoreMapper extends UniBaseMapper<JkStore> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysDict;
|
||||||
|
|
||||||
|
public interface SysDictMapper extends UniBaseMapper<SysDict> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysFile;
|
||||||
|
|
||||||
|
public interface SysFileMapper extends UniBaseMapper<SysFile> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
|
||||||
|
public interface SysUserMapper extends UniBaseMapper<SysUser> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
public interface UniBaseMapper<T> extends BaseMapper<T> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.WxOrder;
|
||||||
|
import cn.unizk.entity.vo.OrderReqVO;
|
||||||
|
import cn.unizk.entity.vo.WxOrderVO;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
public interface WxOrderMapper extends UniBaseMapper<WxOrder> {
|
||||||
|
|
||||||
|
Page<WxOrderVO> selectOrders(Page<WxOrderVO> page, @Param("vo") OrderReqVO vo);
|
||||||
|
|
||||||
|
WxOrder selectOrderByIdAndPhone(@Param("orderId") String orderId,@Param("phone") String phone);
|
||||||
|
|
||||||
|
Page<WxOrderVO> selectAfterSaleOrders(Page<WxOrderVO> page, @Param("vo") OrderReqVO vo);
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
package cn.unizk.mapper;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.WxUser;
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/8 11:27
|
||||||
|
* @Version 1.0
|
||||||
|
**//*
|
||||||
|
|
||||||
|
public interface WxUserMapper extends UniBaseMapper<WxUser> {
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package cn.unizk.properties;
|
||||||
|
|
||||||
|
import cn.unizk.annotation.Anonymous;
|
||||||
|
import org.apache.commons.lang3.RegExUtils;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 19:21
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware
|
||||||
|
{
|
||||||
|
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)}");
|
||||||
|
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
private List<String> urls = new ArrayList<>();
|
||||||
|
|
||||||
|
public String ASTERISK = "*";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet()
|
||||||
|
{
|
||||||
|
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
|
||||||
|
|
||||||
|
map.keySet().forEach(info -> {
|
||||||
|
HandlerMethod handlerMethod = map.get(info);
|
||||||
|
|
||||||
|
// 获取方法上边的注解 替代path variable 为 *
|
||||||
|
Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
|
||||||
|
Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
|
||||||
|
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
|
||||||
|
|
||||||
|
// 获取类上边的注解, 替代path variable 为 *
|
||||||
|
Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
|
||||||
|
Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
|
||||||
|
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext context) throws BeansException
|
||||||
|
{
|
||||||
|
this.applicationContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getUrls()
|
||||||
|
{
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrls(List<String> urls)
|
||||||
|
{
|
||||||
|
this.urls = urls;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package cn.unizk.properties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/11 10:12
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "wx")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class SysWxProperties {
|
||||||
|
|
||||||
|
private String appid;
|
||||||
|
|
||||||
|
private String secret;
|
||||||
|
|
||||||
|
private String redirectUrl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package cn.unizk.security.context;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/25 14:49
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
public class AuthenticationContextHolder {
|
||||||
|
|
||||||
|
private static final ThreadLocal<Authentication> AUTHENTICATION_THREAD_LOCAL = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public static Authentication getContext(){
|
||||||
|
return AUTHENTICATION_THREAD_LOCAL.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setContext(Authentication authentication){
|
||||||
|
AUTHENTICATION_THREAD_LOCAL.set(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeContext(){
|
||||||
|
AUTHENTICATION_THREAD_LOCAL.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package cn.unizk.security.filter;
|
||||||
|
|
||||||
|
import cn.unizk.entity.dto.LoginUser;
|
||||||
|
import cn.unizk.service.TokenService;
|
||||||
|
import cn.unizk.utils.SecurityUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:54
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Component
|
||||||
|
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private TokenService tokenService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain chain)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
LoginUser loginUser = tokenService.getLoginUser(request);
|
||||||
|
if (Objects.nonNull(loginUser) && Objects.isNull(SecurityUtils.getAuthentication()))
|
||||||
|
{
|
||||||
|
tokenService.verifyToken(loginUser);
|
||||||
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
||||||
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||||
|
}
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package cn.unizk.security.handler;
|
||||||
|
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.utils.ServletUtils;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:23
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Component
|
||||||
|
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable {
|
||||||
|
private static final long serialVersionUID = -8970718410437077606L;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RequestMappingHandlerMapping handlerMapping;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
|
||||||
|
throws IOException {
|
||||||
|
/*
|
||||||
|
该写法能让用户未登录的情况下访问不存在的路径返回404而非401,但springsecurity会让所有非放行路径名单里的路径(包括
|
||||||
|
不存在的路径)都需要登录认证。这是合乎逻辑的,所以我认为没有必要这样写.
|
||||||
|
而且,如果是登录后并且有权限的情况下,访问不存在的路径,是正常返回404的。
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*HandlerExecutionChain chain = null;
|
||||||
|
ServletRequestPathUtils.parseAndCache(request);
|
||||||
|
try {
|
||||||
|
chain = handlerMapping.getHandler(request);
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
if (chain == null){
|
||||||
|
String msg = String.format("请求访问:%s,资源路径不存在", request.getRequestURI());
|
||||||
|
ServletUtils.renderString(response, JSON.toJSONString(ResultData.failure(404, msg)));
|
||||||
|
}else {
|
||||||
|
String msg = String.format("请求访问:%s,认证失败,无法访问系统资源", request.getRequestURI());
|
||||||
|
ServletUtils.renderString(response, JSON.toJSONString(ResultData.failure(401, msg)));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
String msg = String.format("请求访问:%s,认证失败,无法访问系统资源", request.getRequestURI());
|
||||||
|
ServletUtils.renderString(response, JSON.toJSONString(ResultData.failure(401, msg)));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package cn.unizk.security.handler;
|
||||||
|
|
||||||
|
import cn.unizk.entity.dto.LoginUser;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.service.TokenService;
|
||||||
|
import cn.unizk.utils.ServletUtils;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:27
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private TokenService tokenService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出处理
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||||
|
throws IOException, ServletException
|
||||||
|
{
|
||||||
|
LoginUser loginUser = tokenService.getLoginUser(request);
|
||||||
|
if (Objects.nonNull(loginUser))
|
||||||
|
{
|
||||||
|
String userName = loginUser.getUsername();
|
||||||
|
// 删除用户缓存记录
|
||||||
|
tokenService.delLoginUser(loginUser.getToken());
|
||||||
|
// 记录用户退出日志
|
||||||
|
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
|
||||||
|
}
|
||||||
|
ServletUtils.renderString(response, JSON.toJSONString(ResultData.success("user.logout.success")));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.unizk.security.handler;
|
||||||
|
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/26 17:54
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
/*@RestControllerAdvice
|
||||||
|
public class SecurityExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(AccessDeniedException.class)
|
||||||
|
public ResultData handlerAccessDeniedException(AccessDeniedException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
return ResultData.failure(403,"无权限访问该资源");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package cn.unizk.security.handler;
|
||||||
|
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.utils.ServletUtils;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/26 17:02
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Component
|
||||||
|
public class UserAccessDeniedHandler implements AccessDeniedHandler, Serializable {
|
||||||
|
private static final long serialVersionUID = 1922706320435419878L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
|
||||||
|
ServletUtils.renderString(response, JSON.toJSONString(ResultData.failure(403,"权限不足,无法访问该资源")));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.BusinessChannel;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface BusinessChannelService extends IService<BusinessChannel> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.unizk.config.HuiFuVendorProperties;
|
||||||
|
import cn.unizk.entity.dto.CashOutDTO;
|
||||||
|
import cn.unizk.entity.dto.CashOutResponse;
|
||||||
|
import cn.unizk.entity.po.CashOutRecord;
|
||||||
|
import cn.unizk.entity.po.JkStore;
|
||||||
|
import cn.unizk.entity.po.StoreAccount;
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.mapper.CashOutRecordMapper;
|
||||||
|
import cn.unizk.mapper.StoreAccountMapper;
|
||||||
|
import cn.unizk.mapper.StoreMapper;
|
||||||
|
import cn.unizk.utils.HttpUtil;
|
||||||
|
import cn.unizk.utils.HuifuSignUtil;
|
||||||
|
import cn.unizk.utils.SecurityUtils;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2026/3/13 15:31
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class ChildStoreService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private HuiFuVendorProperties vendorProperties;
|
||||||
|
@Resource
|
||||||
|
private StoreMapper jkStoreMapper;
|
||||||
|
@Resource
|
||||||
|
private CashOutRecordMapper cashOutRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private StoreAccountMapper storeAccountMapper;
|
||||||
|
|
||||||
|
|
||||||
|
private static final String YUE_PAY_API = "https://api.huifu.com/v2/trade/acctpayment/pay";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门店提现接口
|
||||||
|
*
|
||||||
|
* @param dto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public CashOutResponse profitSharingPay(CashOutDTO dto) {
|
||||||
|
SysUser sysUser = SecurityUtils.getSysUser();
|
||||||
|
if (sysUser.getStoreId() == null || !sysUser.getStoreId().equals(dto.getStoreId())){
|
||||||
|
throw new ServiceException(403,"非法访问");
|
||||||
|
}
|
||||||
|
JSONObject data = JSONObject.of();
|
||||||
|
String snowId = IdUtil.getSnowflakeNextIdStr();
|
||||||
|
data.put("req_seq_id", snowId);
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMdd");
|
||||||
|
data.put("req_date", now);
|
||||||
|
data.put("out_huifu_id", vendorProperties.getHuifuId());
|
||||||
|
BigDecimal bd = new BigDecimal(dto.getAmount());
|
||||||
|
bd = bd.setScale(2, RoundingMode.DOWN);
|
||||||
|
data.put("ord_amt", bd.toString());
|
||||||
|
JkStore jkStore = jkStoreMapper.selectById(dto.getStoreId());
|
||||||
|
if (Objects.isNull(jkStore)) {
|
||||||
|
return new CashOutResponse(500,String.format("门店ID【%d】不存在",dto.getStoreId()));
|
||||||
|
}
|
||||||
|
StoreAccount storeAccount = storeAccountMapper.selectOne(new LambdaQueryWrapper<StoreAccount>().eq(StoreAccount::getStoreId, dto.getStoreId()));
|
||||||
|
if (Objects.isNull(storeAccount) || storeAccount.getAvailableBalance().compareTo(bd) < 0){
|
||||||
|
throw new ServiceException("提现金额不能大于账户可用余额!");
|
||||||
|
}
|
||||||
|
JSONObject acct_split_bunch = JSONObject.of();
|
||||||
|
JSONArray acct_infos = new JSONArray();
|
||||||
|
JSONObject accInfo = new JSONObject();
|
||||||
|
accInfo.put("div_amt",bd.toString());
|
||||||
|
accInfo.put("huifu_id", jkStore.getHuifuId());
|
||||||
|
accInfo.put("percentage_div", "100.00");
|
||||||
|
acct_infos.add(accInfo);
|
||||||
|
acct_split_bunch.put("acct_infos", acct_infos);
|
||||||
|
acct_split_bunch.put("percentage_flag", "Y");
|
||||||
|
data.put("acct_split_bunch", acct_split_bunch);
|
||||||
|
String sign = HuifuSignUtil.sign(data, vendorProperties.getPrivateKey());
|
||||||
|
JSONObject commonParams = new JSONObject();
|
||||||
|
commonParams.put("sys_id", vendorProperties.getSysId());
|
||||||
|
commonParams.put("product_id", vendorProperties.getProductId());
|
||||||
|
commonParams.put("sign", sign);
|
||||||
|
commonParams.put("data", data);
|
||||||
|
log.info("参数:{}", commonParams);
|
||||||
|
String res = HttpUtil.doPostJson(YUE_PAY_API, null, commonParams);
|
||||||
|
log.info("余额支付接口返回数据:{}", res);
|
||||||
|
JSONObject response = JSONObject.parseObject(res);
|
||||||
|
if (response == null) {
|
||||||
|
return new CashOutResponse(300,"提现失败!");
|
||||||
|
}
|
||||||
|
JSONObject responseData = response.getJSONObject("data");
|
||||||
|
String resp_code = responseData.getString("resp_code");
|
||||||
|
String req_seq_id = responseData.getString("req_seq_id");
|
||||||
|
String req_date = responseData.getString("req_date");
|
||||||
|
String out_huifu_id = responseData.getString("out_huifu_id");
|
||||||
|
String ord_amt = responseData.getString("ord_amt");
|
||||||
|
if ("00000000".equals(resp_code)) {
|
||||||
|
log.info("提现成功,流水号:{}", snowId);
|
||||||
|
CashOutRecord cashOutRecord = new CashOutRecord();
|
||||||
|
cashOutRecord.setAmount(bd);
|
||||||
|
cashOutRecord.setOutHuifuId(vendorProperties.getHuifuId());
|
||||||
|
cashOutRecord.setStoreId(dto.getStoreId());
|
||||||
|
cashOutRecord.setCreateTime(LocalDateTime.now());
|
||||||
|
cashOutRecordMapper.insert(cashOutRecord);
|
||||||
|
BigDecimal supBalance = storeAccount.getBalance().subtract(bd).setScale(2, RoundingMode.DOWN);
|
||||||
|
BigDecimal supAvaBalance = storeAccount.getAvailableBalance().subtract(bd).setScale(2, RoundingMode.DOWN);
|
||||||
|
storeAccount.setBalance(supBalance);
|
||||||
|
storeAccount.setAvailableBalance(supAvaBalance);
|
||||||
|
storeAccountMapper.updateById(storeAccount);
|
||||||
|
return new CashOutResponse(200,"success");
|
||||||
|
}
|
||||||
|
throw new ServiceException(String.format("余额支付接口返回状态码:%s,提现失败!",resp_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动取现,从商户账户提现到银行卡
|
||||||
|
* https://paas.huifu.com/open/doc/api/#/jyjs/qx/api_qx
|
||||||
|
*/
|
||||||
|
public void realWithdrawCash(){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Combo;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface ComboService extends IService<Combo> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Device;
|
||||||
|
import cn.unizk.entity.vo.DeviceVO;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface DeviceService extends IService<Device> {
|
||||||
|
|
||||||
|
Page<Device> listPage(UniPage<DeviceVO> uniPage);
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/11/3 18:36
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class FileService {
|
||||||
|
|
||||||
|
private static final int CHUNK_SIZE = 1024;
|
||||||
|
|
||||||
|
public List<byte[]> splitFile(String filePath) throws IOException {
|
||||||
|
File file = new File(filePath);
|
||||||
|
return splitFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte[]> splitFileWithNIO(String filePath) throws IOException {
|
||||||
|
File file = new File(filePath);
|
||||||
|
Path path = file.toPath();
|
||||||
|
log.info("开始分包,文件路径: {}, 文件大小: {} 字节", filePath, file.length());
|
||||||
|
return splitFileWithNIO(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte[]> splitFile(File file) throws IOException {
|
||||||
|
List<byte[]> chunks = new ArrayList<>();
|
||||||
|
|
||||||
|
try (FileInputStream fis = new FileInputStream(file);
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(fis)) {
|
||||||
|
|
||||||
|
byte[] buffer = new byte[CHUNK_SIZE];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
while ((bytesRead = bis.read(buffer)) != -1) {
|
||||||
|
// 如果读取的字节数不足1024,创建正确大小的数组
|
||||||
|
if (bytesRead < CHUNK_SIZE) {
|
||||||
|
byte[] lastChunk = new byte[bytesRead];
|
||||||
|
System.arraycopy(buffer, 0, lastChunk, 0, bytesRead);
|
||||||
|
chunks.add(lastChunk);
|
||||||
|
} else {
|
||||||
|
chunks.add(buffer.clone());
|
||||||
|
}
|
||||||
|
buffer = new byte[CHUNK_SIZE];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte[]> splitFileWithNIO(Path filePath) throws IOException {
|
||||||
|
List<byte[]> chunks = new ArrayList<>();
|
||||||
|
|
||||||
|
try (FileChannel fileChannel = FileChannel.open(filePath, StandardOpenOption.READ)) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(CHUNK_SIZE);
|
||||||
|
|
||||||
|
int chunkIndex = 0;
|
||||||
|
while (fileChannel.read(buffer) != -1) {
|
||||||
|
buffer.flip(); // 切换为读模式
|
||||||
|
|
||||||
|
byte[] chunk = new byte[buffer.remaining()];
|
||||||
|
buffer.get(chunk);
|
||||||
|
log.info("第{}块,实际大小: {} 字节", chunkIndex, chunk.length);
|
||||||
|
chunks.add(chunk);
|
||||||
|
|
||||||
|
buffer.clear(); // 清空缓冲区,准备下一次读取
|
||||||
|
chunkIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("分包完成,总块数: {}", chunks.size());
|
||||||
|
int lastIndex = chunks.size() - 1;
|
||||||
|
byte[] lastPackage = chunks.get(lastIndex);
|
||||||
|
if (lastPackage.length < 1024) {
|
||||||
|
// 最后一个包不足1024字节,用0xFF填充
|
||||||
|
byte[] paddedPackage = new byte[1024];
|
||||||
|
System.arraycopy(lastPackage, 0, paddedPackage, 0, lastPackage.length);
|
||||||
|
Arrays.fill(paddedPackage, lastPackage.length, 1024, (byte) 0xFF);
|
||||||
|
chunks.set(lastIndex, paddedPackage);
|
||||||
|
log.info("最后一个包从{}字节填充到1024字节", lastPackage.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印每块的大小
|
||||||
|
/*for (int i = 0; i < chunks.size(); i++) {
|
||||||
|
log.debug("块{}: {}字节", i, chunks.get(i).length);
|
||||||
|
}*/
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.dto.PrDTO;
|
||||||
|
import cn.unizk.entity.po.MobileAppUser;
|
||||||
|
import cn.unizk.entity.po.TreatParameter;
|
||||||
|
import cn.unizk.mapper.MobileAppUserMapper;
|
||||||
|
import cn.unizk.mapper.TreatParameterMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/12/18 17:00
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
public class GeneratePrService {
|
||||||
|
@Resource
|
||||||
|
private MobileAppUserMapper mobileAppUserMapper;
|
||||||
|
@Resource
|
||||||
|
private TreatParameterMapper treatParameterMapper;
|
||||||
|
|
||||||
|
public PrDTO generatePr(Integer userId){
|
||||||
|
if (userId == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
MobileAppUser user = mobileAppUserMapper.selectById(userId);
|
||||||
|
if (user == null || StringUtils.isBlank(user.getPainNumber())){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PrDTO prDTO = new PrDTO();
|
||||||
|
String uuid = RandomStringUtils.randomNumeric(16);
|
||||||
|
prDTO.setId(uuid);
|
||||||
|
List<PrDTO.PrItem> prItems = new ArrayList<>();
|
||||||
|
String painNumber = user.getPainNumber();
|
||||||
|
if (painNumber.contains(",")){
|
||||||
|
String[] split = painNumber.split(",");
|
||||||
|
for (String s : split) {
|
||||||
|
PrDTO.PrItem prItem = fill(s);
|
||||||
|
prItems.add(prItem);
|
||||||
|
}
|
||||||
|
prDTO.setPrItems(prItems);
|
||||||
|
}else {
|
||||||
|
PrDTO.PrItem prItem = fill(painNumber);
|
||||||
|
prItems.add(prItem);
|
||||||
|
prDTO.setPrItems(prItems);
|
||||||
|
}
|
||||||
|
return prDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PrDTO.PrItem fill(String painNumber){
|
||||||
|
TreatParameter treatParameter = treatParameterMapper.selectById(Integer.parseInt(painNumber));
|
||||||
|
PrDTO.PrItem prItem = new PrDTO.PrItem();
|
||||||
|
prItem.setFr(treatParameter.getFr());
|
||||||
|
prItem.setPl(treatParameter.getPl());
|
||||||
|
prItem.setPw(treatParameter.getPw());
|
||||||
|
prItem.setUl(treatParameter.getUl());
|
||||||
|
prItem.setTl(treatParameter.getTl());
|
||||||
|
return prItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.vo.SysUserVO;
|
||||||
|
import cn.unizk.entity.vo.SysUserVO2;
|
||||||
|
|
||||||
|
public interface LoginService {
|
||||||
|
|
||||||
|
SysUserVO loginByUsername(SysUserVO sysUserVO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.Menu;
|
||||||
|
import cn.unizk.entity.vo.TreeMenu;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MenuService extends IService<Menu> {
|
||||||
|
|
||||||
|
List<TreeMenu> getAllMenus();
|
||||||
|
|
||||||
|
List<TreeMenu> getStoreMenus();
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import cn.unizk.exception.ServiceException;
|
||||||
|
import cn.unizk.security.context.AuthenticationContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/25 14:47
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class PasswordService {
|
||||||
|
|
||||||
|
public void validate(SysUser sysUser){
|
||||||
|
Authentication context = AuthenticationContextHolder.getContext();
|
||||||
|
String rawPassword = (String) context.getCredentials();
|
||||||
|
if (!matchPwd(sysUser,rawPassword)){
|
||||||
|
throw new ServiceException("密码错误!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchPwd(SysUser sysUser,String rawPassword){
|
||||||
|
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
|
||||||
|
String encode = bCryptPasswordEncoder.encode(rawPassword);
|
||||||
|
log.info("encode={}",encode);
|
||||||
|
return bCryptPasswordEncoder.matches(rawPassword,sysUser.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkPhysio;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface PhysioService extends IService<JkPhysio> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.ProductCarousel;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface ProductCarouselService extends IService<ProductCarousel> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkProduct;
|
||||||
|
import cn.unizk.entity.vo.JkProductVO;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface ProductService extends IService<JkProduct> {
|
||||||
|
|
||||||
|
JkProductVO echo(Integer id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.JkStore;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface StoreService extends IService<JkStore> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysDict;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface SysDictService extends IService<SysDict> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysFile;
|
||||||
|
import cn.unizk.entity.vo.MinioRespVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
public interface SysFileService extends IService<SysFile> {
|
||||||
|
|
||||||
|
ResultData<MinioRespVO> simpleUpload(MultipartFile file, String bucketName);
|
||||||
|
|
||||||
|
void deleteFile(String bucketName,String fileName) throws Exception;
|
||||||
|
|
||||||
|
void deleteFileById(Integer fileId) throws Exception;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.MobileOrder;
|
||||||
|
import cn.unizk.entity.vo.MobileOrderVO;
|
||||||
|
import cn.unizk.entity.vo.OrderReqVO;
|
||||||
|
import cn.unizk.entity.vo.ResultData;
|
||||||
|
import cn.unizk.entity.vo.UniPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface SysOrderService extends IService<MobileOrder> {
|
||||||
|
|
||||||
|
Page<MobileOrderVO> orderList(UniPage<OrderReqVO> uniPage);
|
||||||
|
|
||||||
|
MobileOrder getOrderByIdAndPhone(String orderId,String phone);
|
||||||
|
|
||||||
|
ResultData refund(MobileOrder wxOrder);
|
||||||
|
|
||||||
|
Page<MobileOrderVO> afterSale(UniPage<OrderReqVO> uniPage);
|
||||||
|
|
||||||
|
ResultData agreeRefund(String orderId,String platformType);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.SysUser;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface SysUserService extends IService<SysUser> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.constants.CacheConstant;
|
||||||
|
import cn.unizk.constants.Constants;
|
||||||
|
import cn.unizk.entity.dto.LoginUser;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/8/22 18:47
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class TokenService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("kryoRedisTemplate")
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
@Value("${token.header}")
|
||||||
|
private String tokenHeader;
|
||||||
|
|
||||||
|
private SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
|
||||||
|
|
||||||
|
|
||||||
|
@Value("${token.expireTime}")
|
||||||
|
private Integer expireTime;
|
||||||
|
|
||||||
|
private static final long TWENTY_MINUTES = 20 * 60 * 1000L;
|
||||||
|
|
||||||
|
private static final long MINUTE_CAST_MILLISECOND_UNIT = 60 * 1000L;
|
||||||
|
|
||||||
|
|
||||||
|
public LoginUser getLoginUser(HttpServletRequest request){
|
||||||
|
String token = getToken(request);
|
||||||
|
if (StringUtils.isNotBlank(token)){
|
||||||
|
try {
|
||||||
|
Claims claims = parseToken(token);
|
||||||
|
String uuid = (String) claims.get(Constants.JWT_TOKEN_KEY);
|
||||||
|
String redisTokenKey = getRedisTokenKey(uuid);
|
||||||
|
LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(redisTokenKey);
|
||||||
|
if (Objects.isNull(loginUser)){
|
||||||
|
return loginUser;
|
||||||
|
}
|
||||||
|
verifyToken(loginUser);
|
||||||
|
return loginUser;
|
||||||
|
//在这里调用verifyToken(),不然1小时会过期
|
||||||
|
}catch (Exception e){
|
||||||
|
// e.printStackTrace();
|
||||||
|
log.info("token解析异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createToken(LoginUser user) {
|
||||||
|
String uuid = RandomStringUtils.randomAlphanumeric(16);
|
||||||
|
user.setToken(uuid);
|
||||||
|
user.setLoginTime(System.currentTimeMillis());
|
||||||
|
refreshToken(user, true);
|
||||||
|
Map<String, Object> claims = new HashMap<>();
|
||||||
|
claims.put(Constants.JWT_TOKEN_KEY, uuid);
|
||||||
|
return createToken(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createToken(Map<String, Object> claims) {
|
||||||
|
|
||||||
|
return Jwts.builder()
|
||||||
|
.setClaims(claims)
|
||||||
|
.signWith(secretKey)
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Claims parseToken(String token) {
|
||||||
|
|
||||||
|
return Jwts.parserBuilder()
|
||||||
|
.setSigningKey(secretKey)
|
||||||
|
.build()
|
||||||
|
.parseClaimsJws(token)
|
||||||
|
.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void verifyToken(LoginUser user) {
|
||||||
|
Long expireTime = user.getExpireTime();
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (expireTime - currentTime <= TWENTY_MINUTES) {
|
||||||
|
refreshToken(user, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshToken(LoginUser user, Boolean refreshLoginTime) {
|
||||||
|
long currentTimeMillis = System.currentTimeMillis();
|
||||||
|
if (refreshLoginTime) {
|
||||||
|
user.setLoginTime(currentTimeMillis);
|
||||||
|
}
|
||||||
|
user.setExpireTime(currentTimeMillis + expireTime * MINUTE_CAST_MILLISECOND_UNIT);
|
||||||
|
String tokenKey = getRedisTokenKey(user.getToken());
|
||||||
|
redisTemplate.opsForValue().set(tokenKey, user,expireTime, TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRedisTokenKey(String uuid) {
|
||||||
|
return CacheConstant.LOGIN_TOKEN_KEY + uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken(HttpServletRequest request){
|
||||||
|
String token = request.getHeader(tokenHeader);
|
||||||
|
if (StringUtils.isNotBlank(token) && token.startsWith(Constants.TOKEN_PREFIX)){
|
||||||
|
token = token.replace(Constants.TOKEN_PREFIX,"");
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delLoginUser(String token){
|
||||||
|
if (StringUtils.isNotBlank(token)){
|
||||||
|
String redisTokenKey = getRedisTokenKey(token);
|
||||||
|
redisTemplate.delete(redisTokenKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/10 16:54
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class UdpClientService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向指定设备发送UDP指令
|
||||||
|
* @param deviceIp 设备IP地址
|
||||||
|
* @param devicePort 设备端口
|
||||||
|
* @param command 要发送的指令
|
||||||
|
* @return 发送是否成功
|
||||||
|
*/
|
||||||
|
public boolean sendCommand(String deviceIp, int devicePort, String command) {
|
||||||
|
try (DatagramSocket clientSocket = new DatagramSocket(9999)) { // 创建临时socket
|
||||||
|
InetAddress address = InetAddress.getByName(deviceIp);
|
||||||
|
byte[] sendData = command.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
address,
|
||||||
|
devicePort
|
||||||
|
);
|
||||||
|
clientSocket.setSoTimeout(3000);
|
||||||
|
clientSocket.send(sendPacket);
|
||||||
|
System.out.printf("Command sent to %s:%d - %s%n", deviceIp, devicePort, command);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.printf("Failed to send command to %s:%d: %s%n",
|
||||||
|
deviceIp, devicePort, e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean sendCommand(UdpServerService.DeviceInfo deviceInfo, String command) {
|
||||||
|
if (deviceInfo == null) {
|
||||||
|
System.err.println("DeviceInfo is null, cannot send command.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return sendCommand(deviceInfo.getIp(), deviceInfo.getPort(), command);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,718 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.constant.UniConstant;
|
||||||
|
import cn.unizk.entity.po.Device;
|
||||||
|
import cn.unizk.entity.po.DeviceUpgrade;
|
||||||
|
import cn.unizk.entity.po.DeviceUsageDetail;
|
||||||
|
import cn.unizk.entity.po.DeviceUsageRecord;
|
||||||
|
import cn.unizk.mapper.DeviceMapper;
|
||||||
|
import cn.unizk.mapper.DeviceUpgradeMapper;
|
||||||
|
import cn.unizk.mapper.DeviceUsageDetailMapper;
|
||||||
|
import cn.unizk.mapper.DeviceUsageRecordMapper;
|
||||||
|
import cn.unizk.task.DeviceTask;
|
||||||
|
import cn.unizk.utils.XorUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/10 16:17
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
//@Service
|
||||||
|
@Slf4j
|
||||||
|
public class UdpServerService {
|
||||||
|
private ConcurrentHashMap<String, DeviceInfo> deviceMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private DatagramSocket serverSocket;
|
||||||
|
private volatile boolean running = false;
|
||||||
|
private ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
|
private static final int LISTEN_PORT = 61100;
|
||||||
|
private static final long SESSION_TIMEOUT = 60_000;
|
||||||
|
@Resource
|
||||||
|
private UdpClientService udpClientService;
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageRecordMapper deviceUsageRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceTask deviceTask;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageDetailMapper usageDetailMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceUpgradeMapper upgradeMapper;
|
||||||
|
@Resource
|
||||||
|
private FileService fileService;
|
||||||
|
@Resource(name = "kryoRedisTemplate")
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
private static final String UPGRADE_PACKAGE_ROOT_PATH = "/opt/jkadmin/upgrade/";
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class DeviceInfo {
|
||||||
|
private String muid;
|
||||||
|
private String status;
|
||||||
|
private String ip;
|
||||||
|
private int port;
|
||||||
|
private Boolean startCount = false;
|
||||||
|
private final long lastActiveTime;
|
||||||
|
|
||||||
|
// DeviceInfo(){}
|
||||||
|
|
||||||
|
/*public boolean getStartCount(){
|
||||||
|
return this.startCount;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
DeviceInfo(String muid, String status, String ip, int port){
|
||||||
|
this.muid = muid;
|
||||||
|
this.status = status;
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
this.startCount = false;
|
||||||
|
this.lastActiveTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceInfo(String muid, String status, String ip, int port,boolean startCount){
|
||||||
|
this.muid = muid;
|
||||||
|
this.status = status;
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
this.startCount = startCount;
|
||||||
|
this.lastActiveTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void startServer() {
|
||||||
|
try {
|
||||||
|
serverSocket = new DatagramSocket(LISTEN_PORT);
|
||||||
|
running = true;
|
||||||
|
log.info("UDP Server started on port: {}",LISTEN_PORT);
|
||||||
|
|
||||||
|
executorService.execute(this::receivePackets);
|
||||||
|
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("Failed to start UDP server on port: {}" ,LISTEN_PORT , e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void stopServer() {
|
||||||
|
running = false;
|
||||||
|
if (serverSocket != null && !serverSocket.isClosed()) {
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
executorService.shutdown();
|
||||||
|
log.info("UDP Server stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receivePackets() {
|
||||||
|
byte[] receiveBuffer = new byte[1024]; // 缓冲区
|
||||||
|
|
||||||
|
log.info("持续接收UDP数据包,{}",serverSocket.isClosed());
|
||||||
|
|
||||||
|
while (running && !serverSocket.isClosed()) {
|
||||||
|
try {
|
||||||
|
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
|
||||||
|
serverSocket.receive(receivePacket); // 阻塞等待接收数据
|
||||||
|
log.info("处理接收到的数据包");
|
||||||
|
// 处理接收到的数据包(可以在新线程中处理,避免阻塞接收)
|
||||||
|
handlePacket(receivePacket);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (running) { // 只有在运行状态下的异常才打印
|
||||||
|
log.error("Error receiving packet: " , e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePacket(DatagramPacket packet) {
|
||||||
|
|
||||||
|
String deviceIp = packet.getAddress().getHostAddress();
|
||||||
|
int devicePort = packet.getPort();
|
||||||
|
|
||||||
|
String receivedMessage = new String(packet.getData(), 0, packet.getLength());
|
||||||
|
|
||||||
|
System.out.printf("Received from %s:%d - Message: %s%n",
|
||||||
|
deviceIp, devicePort, receivedMessage);
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(receivedMessage)){
|
||||||
|
log.info("接收到的数据包为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 需要根据实际协议格式进行解析
|
||||||
|
String muid = parsemuid(receivedMessage); // 需要实现此方法
|
||||||
|
String status = receivedMessage.substring(2, 3);
|
||||||
|
log.info("解析得到的muid={}",muid);
|
||||||
|
log.info("解析得到的状态码是:{}",status);
|
||||||
|
|
||||||
|
if (muid != null && !muid.isEmpty()) {
|
||||||
|
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
// 将设备信息存入Map
|
||||||
|
System.out.println("Device registered: " + muid + " at " + deviceIp + ":" + devicePort);
|
||||||
|
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
log.info("数据库不存在该设备,muid={}",muid);
|
||||||
|
}else {
|
||||||
|
DeviceInfo deviceInfo = deviceMap.get(muid);
|
||||||
|
if ("1".equals(status)){
|
||||||
|
if (Objects.isNull(deviceInfo)){
|
||||||
|
log.info("deviceMap缓存中没有{}这个设备",muid);
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
}else {
|
||||||
|
if (deviceInfo.getStartCount() && device.getSurplus() > 0){
|
||||||
|
log.info("设备状态为01开机,开始计数startCount为true");
|
||||||
|
int count = device.getSurplus() - 1;
|
||||||
|
device.setSurplus(count);
|
||||||
|
device.setExpireTime(String.valueOf(count));
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
}
|
||||||
|
String lo = null, la = null;
|
||||||
|
String[] items = receivedMessage.split("\\|");
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("LO")){
|
||||||
|
lo = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("LA")){
|
||||||
|
la = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lo != null && la != null){
|
||||||
|
device.setLo(lo);
|
||||||
|
device.setLa(la);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}
|
||||||
|
parseDeviceInfo(device,receivedMessage);
|
||||||
|
/**
|
||||||
|
* 拿device的硬件版本和软件版本去查device_upgrade表,如果跟当前版本不一致则升级
|
||||||
|
*/
|
||||||
|
if ("000B57020457D4B100001F98".equals(muid)){
|
||||||
|
log.info("muid=***F97,回复升级心跳");
|
||||||
|
replyUpgradeHeartbeat(deviceMap.get(muid),packet);
|
||||||
|
}else {
|
||||||
|
replyHeartbeat(deviceMap.get(muid),packet);
|
||||||
|
}
|
||||||
|
DeviceUsageDetail detail = new DeviceUsageDetail();
|
||||||
|
detail.setStatus(status);
|
||||||
|
recordUse(device,detail);
|
||||||
|
if (device.getOperatingStatus() == 0){
|
||||||
|
changeDeviceOperatingStatus(device.getDeviceId(),2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("1".equals(status) && device.getSurplus() < 1){
|
||||||
|
log.info("设备状态为1,无剩余使用次数,马上停");
|
||||||
|
String c1 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c1.replace("{uid}", muid).replace("{date}", now).replace("{1}", "0");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String s = replace.replace("{CRC}", asciiHex);
|
||||||
|
byte[] sendData = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
deviceMapper.updateStatus(device.getDeviceId(),"0");
|
||||||
|
}
|
||||||
|
if ("2".equals(status)){
|
||||||
|
updateLastRunTime(device);
|
||||||
|
String mo = parseMo(device, receivedMessage);
|
||||||
|
if (device.getSurplus() < 1) {
|
||||||
|
log.info("设备状态为2,五剩余使用次数,马上听");
|
||||||
|
//马上停
|
||||||
|
String c2 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c2.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now).replace("{1}", "0").replace("{2}", "000");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String s = replace.replace("{CRC}", asciiHex);
|
||||||
|
byte[] sendData = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
deviceMapper.updateStatus(device.getDeviceId(),"0");
|
||||||
|
}else {
|
||||||
|
try {
|
||||||
|
Device dvie = toLiliao(device.getDeviceId());
|
||||||
|
DeviceUsageDetail detail = parseMsgToDetail(receivedMessage);
|
||||||
|
detail.setStatus(status);
|
||||||
|
recordUse(dvie,detail);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("记录设备使用发生异常",e);
|
||||||
|
}
|
||||||
|
if (device.getPaymentMethod() == 1){
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
}else {
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort,true));
|
||||||
|
}
|
||||||
|
replyHeartbeat(deviceMap.get(muid),packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Objects.isNull(deviceInfo)){
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
deviceInfo = deviceMap.get(muid);
|
||||||
|
}
|
||||||
|
if ("4".equals(status) && deviceInfo.getStartCount()){
|
||||||
|
log.info("设备状态为4,关机,并且startCount为true");
|
||||||
|
int count = device.getSurplus() - 1;
|
||||||
|
device.setSurplus(count);
|
||||||
|
device.setExpireTime(String.valueOf(count));
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
}
|
||||||
|
if ("4".equals(status)){
|
||||||
|
try {
|
||||||
|
changeDeviceOperatingStatus(device.getDeviceId(),1);
|
||||||
|
updateRecord(device.getDeviceId());
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("更新设备使用记录发生异常",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//马上回
|
||||||
|
/*log.info("马上回------");
|
||||||
|
// udpClientService.sendCommand(deviceIp,devicePort,"$01|MU000B57020457D4B100001F97|DT20251011163826|ON0|CF1|WM1|TC000|*7E\r\n");
|
||||||
|
InetAddress address = null;
|
||||||
|
try {
|
||||||
|
address = InetAddress.getByName(deviceIp);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
|
||||||
|
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
String command = "$01|MU000B57020457D4B100001F97|DT20251011163826|ON0|CF1|WM1|TC000|*7E\r\n";
|
||||||
|
if ("1".equals(status)){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", "0");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
command = replace.replace("{CRC}", asciiHex);
|
||||||
|
}
|
||||||
|
if ("2".equals(status)){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c02.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now).replace("{1}", "0").replace("{2}", "000");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
command = replace.replace("{CRC}", asciiHex);
|
||||||
|
}
|
||||||
|
byte[] sendData = command.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyHeartbeat(DeviceInfo info,DatagramPacket packet){
|
||||||
|
if (Objects.isNull(info)){
|
||||||
|
log.info("method->replyHeartbeat,DeviceInfo is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String status = info.getStatus();
|
||||||
|
String muid = info.getMuid();
|
||||||
|
switch (status){
|
||||||
|
case "1":
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|*{CRC}\r\n";
|
||||||
|
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", device.getStatus()).replace("{2}",device.getCf());
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String message = replace.replace("{CRC}", asciiHex);
|
||||||
|
byte[] sendData = message.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "2":
|
||||||
|
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
Device device2 = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
String now2 = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace2 = c02.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now2).replace("{1}", device2.getStatus()).replace("{2}", "000");
|
||||||
|
String crc2 = replace2.substring(1, replace2.lastIndexOf("*"));
|
||||||
|
String asciiHex2 = XorUtil.xorAsciiHex(crc2);
|
||||||
|
String msg = replace2.replace("{CRC}", asciiHex2);
|
||||||
|
byte[] sendData2 = msg.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket2 = new DatagramPacket(
|
||||||
|
sendData2,
|
||||||
|
sendData2.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket2);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseDeviceInfo(Device device,String msg){
|
||||||
|
String[] items = msg.split("\\|");
|
||||||
|
String hw = null,sw = null,ic = null,cf = null,wm = null,cr = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("HW")){
|
||||||
|
hw = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("SW")){
|
||||||
|
sw = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("IC")){
|
||||||
|
ic = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("CF")){
|
||||||
|
cf = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("WM")){
|
||||||
|
wm = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("CR")){
|
||||||
|
cr = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
device.setHw(hw);
|
||||||
|
device.setSw(sw);
|
||||||
|
device.setIccid(ic);
|
||||||
|
if (StringUtils.isBlank(device.getCf())){
|
||||||
|
device.setCf(cf);
|
||||||
|
}
|
||||||
|
device.setWm(wm);
|
||||||
|
device.setCr(cr);
|
||||||
|
device.setOperatingStatus(3);
|
||||||
|
device.setLastRunTime(LocalDateTime.now());
|
||||||
|
log.info("服务器上的LocalDateTime.now()========={}",LocalDateTime.now());
|
||||||
|
deviceMapper.updateDeviceInfo(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseMo(Device device,String msg){
|
||||||
|
String[] items = msg.split("\\|");
|
||||||
|
String mo = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("MO")){
|
||||||
|
mo = item.substring(2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
device.setMo(mo);
|
||||||
|
Device dv = new Device();
|
||||||
|
dv.setDeviceId(device.getDeviceId());
|
||||||
|
dv.setMo(mo);
|
||||||
|
deviceMapper.updateById(dv);
|
||||||
|
return mo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeviceUsageDetail parseMsgToDetail(String msg){
|
||||||
|
String[] items = msg.split("\\|");
|
||||||
|
String fr = null,pw = null,pl = null,ul = null,wt = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("FR")){
|
||||||
|
fr = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PW")){
|
||||||
|
pw = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PL")){
|
||||||
|
pl = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("UL")){
|
||||||
|
ul = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("WT")){
|
||||||
|
wt = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeviceUsageDetail detail = new DeviceUsageDetail();
|
||||||
|
detail.setFr(fr);
|
||||||
|
detail.setPw(pw);
|
||||||
|
detail.setPl(pl);
|
||||||
|
detail.setUl(ul);
|
||||||
|
detail.setWt(wt);
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLastRunTime(Device device){
|
||||||
|
Device d = new Device();
|
||||||
|
d.setDeviceId(device.getDeviceId());
|
||||||
|
d.setLastRunTime(LocalDateTime.now());
|
||||||
|
deviceMapper.updateById(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Device toLiliao(String deviceId){
|
||||||
|
Device device = deviceMapper.selectById(deviceId);
|
||||||
|
if (Objects.nonNull(device) && device.getOperatingStatus() != 0){
|
||||||
|
device.setOperatingStatus(0);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
deviceTask.addAbnormalDeviceTask(deviceId);
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordUse(Device device, DeviceUsageDetail detail){
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
log.info("设备使用记录recordUse->device is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
device.setLastRunTime(LocalDateTime.now());
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
DeviceUsageRecord record = deviceUsageRecordMapper.selectOne(new LambdaQueryWrapper<DeviceUsageRecord>()
|
||||||
|
.eq(DeviceUsageRecord::getDeviceId, device.getDeviceId())
|
||||||
|
.eq(DeviceUsageRecord::getStartUseFlag, "true"));
|
||||||
|
if (Objects.nonNull(record)){
|
||||||
|
if ("2".equals(detail.getStatus())){
|
||||||
|
detail.setUsageRecordId(record.getId());
|
||||||
|
detail.setCreateTime(LocalDateTime.now());
|
||||||
|
usageDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
log.info("设备正在运行");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DeviceUsageRecord deviceUsageRecord = new DeviceUsageRecord();
|
||||||
|
deviceUsageRecord.setStartTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceUsageRecord.setDeviceId(device.getDeviceId());
|
||||||
|
deviceUsageRecord.setStartUseFlag(UniConstant.CONST_TRUE);
|
||||||
|
deviceUsageRecord.setWm(device.getWm());
|
||||||
|
deviceUsageRecord.setBelong(device.getAffiliatedWith());
|
||||||
|
deviceUsageRecord.setMuid(device.getMuid());
|
||||||
|
deviceUsageRecordMapper.insert(deviceUsageRecord);
|
||||||
|
detail.setCreateTime(LocalDateTime.now());
|
||||||
|
detail.setUsageRecordId(deviceUsageRecord.getId());
|
||||||
|
/*
|
||||||
|
如果真要记录待机状态,那么把status=1的recordUse()放开,在这里加上根据deviceUsageRecord.getId()和status=1去查DeviceUsageDetail表,
|
||||||
|
如果不为空则不插入数据,即只记录一条状态为待机的数据
|
||||||
|
*/
|
||||||
|
List<DeviceUsageDetail> usageDetails = usageDetailMapper.selectList(new LambdaQueryWrapper<DeviceUsageDetail>().eq(DeviceUsageDetail::getUsageRecordId, deviceUsageRecord.getId())
|
||||||
|
.eq(DeviceUsageDetail::getStatus, "1"));
|
||||||
|
if (CollectionUtils.isEmpty(usageDetails)){
|
||||||
|
usageDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRecord(String deviceId){
|
||||||
|
DeviceUsageRecord deviceUsageRecord = deviceUsageRecordMapper.selectOne(new LambdaQueryWrapper<DeviceUsageRecord>()
|
||||||
|
.eq(DeviceUsageRecord::getDeviceId, deviceId)
|
||||||
|
.eq(DeviceUsageRecord::getStartUseFlag, UniConstant.CONST_TRUE));
|
||||||
|
if (Objects.isNull(deviceUsageRecord)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deviceUsageRecord.setEndTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceUsageRecord.setStartUseFlag(UniConstant.CONST_FALSE);
|
||||||
|
deviceUsageRecordMapper.updateById(deviceUsageRecord);
|
||||||
|
DeviceUsageDetail detail = new DeviceUsageDetail();
|
||||||
|
detail.setStatus("4");
|
||||||
|
detail.setCreateTime(LocalDateTime.now());
|
||||||
|
detail.setUsageRecordId(deviceUsageRecord.getId());
|
||||||
|
usageDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeDeviceOperatingStatus(String deviceId,Integer status){
|
||||||
|
Device device = deviceMapper.selectById(deviceId);
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
device.setOperatingStatus(status);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean reply(Device device,String status){
|
||||||
|
String muid = device.getMuid();
|
||||||
|
DeviceInfo deviceInfo = getDeviceInfo(muid);
|
||||||
|
if (deviceInfo == null){
|
||||||
|
log.info("设备会话已过期,请设备先上报一次数据");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String message = "";
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|*{CRC}\r\n";
|
||||||
|
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
if ("1".equals(deviceInfo.getStatus())){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", status).replace("{2}",device.getCf());
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
message = replace.replace("{CRC}", asciiHex);
|
||||||
|
}else if ("2".equals(deviceInfo.getStatus())){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c02.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now).replace("{1}", status).replace("{2}", "000");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
message = replace.replace("{CRC}", asciiHex);
|
||||||
|
}else if ("4".equals(deviceInfo.getStatus())){
|
||||||
|
log.info("设备为关机状态");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
log.info("最终发送的数据为:{}",message);
|
||||||
|
byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
||||||
|
InetAddress address = InetAddress.getByName(deviceInfo.getIp());
|
||||||
|
DatagramPacket packet = new DatagramPacket(data, data.length, address, deviceInfo.getPort());
|
||||||
|
serverSocket.send(packet);
|
||||||
|
System.out.printf("UDP Reply sent to %s:%d -> %s%n", deviceInfo.getIp(), deviceInfo.getPort(), message);
|
||||||
|
device.setStatus(status);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.info("回复设备UDP消息发送异常");
|
||||||
|
e.printStackTrace();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据实际协议解析设备ID
|
||||||
|
* 这是一个示例,您需要根据硬件数据包的实际格式重写此方法
|
||||||
|
* @param message 收到的原始消息
|
||||||
|
* @return 解析出的设备ID
|
||||||
|
*/
|
||||||
|
private String parsemuid(String message) {
|
||||||
|
Pattern p = Pattern.compile("^[^|]*\\|([^|]+)\\|");
|
||||||
|
Matcher matcher = p.matcher(message);
|
||||||
|
if (matcher.find()){
|
||||||
|
return matcher.group(1).substring(2);
|
||||||
|
}
|
||||||
|
// 如果协议里没有ID,也可以用IP:端口作为唯一标识
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备信息
|
||||||
|
* @param muid 设备ID
|
||||||
|
* @return 设备信息,如果不存在则返回null
|
||||||
|
*/
|
||||||
|
public DeviceInfo getDeviceInfo(String muid) {
|
||||||
|
DeviceInfo deviceInfo = deviceMap.get(muid);
|
||||||
|
if (Objects.nonNull(deviceInfo) && System.currentTimeMillis() - deviceInfo.getLastActiveTime() < SESSION_TIMEOUT){
|
||||||
|
return deviceInfo;
|
||||||
|
}else {
|
||||||
|
if (Objects.isNull(deviceInfo)){
|
||||||
|
deviceMap.remove(muid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!deviceInfo.getStartCount()){
|
||||||
|
deviceMap.remove(muid);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有在线设备
|
||||||
|
*/
|
||||||
|
public ConcurrentHashMap<String, DeviceInfo> getOnlineDevices() {
|
||||||
|
return new ConcurrentHashMap<>(deviceMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyUpgradeHeartbeat(DeviceInfo info,DatagramPacket packet){
|
||||||
|
if (Objects.isNull(info)){
|
||||||
|
log.info("method->replyHeartbeat,DeviceInfo is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|UP{3}|WM1|TC000|*{CRC}\r\n";
|
||||||
|
/*
|
||||||
|
查device_upgrade表拿到当前版本升级包名称,然后去/opt/jkadmin/upgrade下面拿到升级包
|
||||||
|
调fileService拆包,得到包数量,替换{3},然后回复
|
||||||
|
*/
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
|
||||||
|
if (Objects.isNull(deviceUpgrade)){
|
||||||
|
replyHeartbeat(info,packet);
|
||||||
|
}else {
|
||||||
|
String fileUrl = UPGRADE_PACKAGE_ROOT_PATH + deviceUpgrade.getFileName();
|
||||||
|
List<byte[]> packages = null;
|
||||||
|
try {
|
||||||
|
packages = fileService.splitFileWithNIO(fileUrl);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("拆包发生异常-.-.-.-.-.-.-.-.-.",e);
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(packages) && packages.size() <= 32){
|
||||||
|
String muid = info.getMuid();
|
||||||
|
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
if (Objects.isNull(device)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String r = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", device.getStatus())
|
||||||
|
.replace("{2}", device.getCf()).replace("{3}", String.valueOf(packages.size()));
|
||||||
|
String crc = r.substring(1, r.lastIndexOf("*"));
|
||||||
|
String xorAsciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String msg = r.replace("{CRC}", xorAsciiHex);
|
||||||
|
log.info("回复升级心跳数据:{}",msg);
|
||||||
|
byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(bytes,bytes.length,packet.getSocketAddress());
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("回复升级心跳包发生异常",e);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
log.info("升级包为空或升级包大小超过1024*32");
|
||||||
|
replyHeartbeat(info, packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,920 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.unizk.constant.UniConstant;
|
||||||
|
import cn.unizk.entity.dto.PrDTO;
|
||||||
|
import cn.unizk.entity.po.*;
|
||||||
|
import cn.unizk.mapper.*;
|
||||||
|
import cn.unizk.task.DeviceTask;
|
||||||
|
import cn.unizk.utils.XorUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/10 16:17
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class UdpServerService2 {
|
||||||
|
// 存储设备地址的Map,Key可以是设备ID,Value是设备的IP和端口
|
||||||
|
private ConcurrentHashMap<String, DeviceInfo> deviceMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private DatagramSocket serverSocket;
|
||||||
|
private volatile boolean running = false;
|
||||||
|
private ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
|
private static final int LISTEN_PORT = 61100; // 监听的端口
|
||||||
|
private static final long SESSION_TIMEOUT = 60_000;
|
||||||
|
@Resource
|
||||||
|
private UdpClientService udpClientService;
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageRecordMapper deviceUsageRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceTask deviceTask;
|
||||||
|
@Resource
|
||||||
|
private DeviceUsageDetailMapper usageDetailMapper;
|
||||||
|
@Resource
|
||||||
|
private DeviceUpgradeMapper upgradeMapper;
|
||||||
|
@Resource
|
||||||
|
private FileService fileService;
|
||||||
|
@Resource(name = "kryoRedisTemplate")
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
@Resource
|
||||||
|
private GeneratePrService generatePrService;
|
||||||
|
@Resource
|
||||||
|
private UserTreatmentParametersMapper userTreatmentParametersMapper;
|
||||||
|
|
||||||
|
|
||||||
|
private static final String UPGRADE_PACKAGE_ROOT_PATH = "/opt/jkadmin/upgrade/";
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class DeviceInfo {
|
||||||
|
private String muid;
|
||||||
|
private String status;
|
||||||
|
private String ip;
|
||||||
|
private int port;
|
||||||
|
private Boolean startCount = false;
|
||||||
|
private final long lastActiveTime;
|
||||||
|
|
||||||
|
// DeviceInfo(){}
|
||||||
|
|
||||||
|
/*public boolean getStartCount(){
|
||||||
|
return this.startCount;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
DeviceInfo(String muid, String status, String ip, int port) {
|
||||||
|
this.muid = muid;
|
||||||
|
this.status = status;
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
this.startCount = false;
|
||||||
|
this.lastActiveTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceInfo(String muid, String status, String ip, int port, boolean startCount) {
|
||||||
|
this.muid = muid;
|
||||||
|
this.status = status;
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
this.startCount = startCount;
|
||||||
|
this.lastActiveTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void startServer() {
|
||||||
|
try {
|
||||||
|
serverSocket = new DatagramSocket(LISTEN_PORT);
|
||||||
|
running = true;
|
||||||
|
log.info("UDP Server started on port: {}", LISTEN_PORT);
|
||||||
|
|
||||||
|
// 启动一个线程来持续接收消息
|
||||||
|
executorService.execute(this::receivePackets);
|
||||||
|
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("Failed to start UDP server on port: {}", LISTEN_PORT, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void stopServer() {
|
||||||
|
running = false;
|
||||||
|
if (serverSocket != null && !serverSocket.isClosed()) {
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
executorService.shutdown();
|
||||||
|
log.info("UDP Server stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 持续接收UDP数据包的方法
|
||||||
|
*/
|
||||||
|
private void receivePackets() {
|
||||||
|
byte[] receiveBuffer = new byte[1024]; // 缓冲区
|
||||||
|
|
||||||
|
log.info("持续接收UDP数据包,{}", serverSocket.isClosed());
|
||||||
|
|
||||||
|
while (running && !serverSocket.isClosed()) {
|
||||||
|
try {
|
||||||
|
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
|
||||||
|
serverSocket.receive(receivePacket); // 阻塞等待接收数据
|
||||||
|
log.info("处理接收到的数据包");
|
||||||
|
// 处理接收到的数据包(可以在新线程中处理,避免阻塞接收)
|
||||||
|
handlePacket(receivePacket);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (running) { // 只有在运行状态下的异常才打印
|
||||||
|
log.error("Error receiving packet: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理接收到的UDP数据包
|
||||||
|
*
|
||||||
|
* @param packet 接收到的数据包
|
||||||
|
*/
|
||||||
|
private void handlePacket(DatagramPacket packet) {
|
||||||
|
// 获取发送方的IP和端口
|
||||||
|
String deviceIp = packet.getAddress().getHostAddress();
|
||||||
|
int devicePort = packet.getPort();
|
||||||
|
|
||||||
|
// 获取数据内容并转换为字符串
|
||||||
|
String receivedMessage = new String(packet.getData(), 0, packet.getLength());
|
||||||
|
|
||||||
|
log.info("Received from {}:{} - Message: {}",
|
||||||
|
deviceIp, devicePort, receivedMessage);
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(receivedMessage)) {
|
||||||
|
log.info("接收到的数据包为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关键步骤:解析数据包,获取设备ID并注册设备地址
|
||||||
|
// 假设数据包格式为: "muid:XXXXX;Status:Online;"
|
||||||
|
// 您需要根据硬件同事提供的实际协议格式进行解析
|
||||||
|
String muid = parsemuid(receivedMessage); // 需要实现此方法
|
||||||
|
String status = receivedMessage.substring(2, 3);
|
||||||
|
String status2 = receivedMessage.substring(1, 3);
|
||||||
|
if ("30".equals(status2)) {
|
||||||
|
status = "9";
|
||||||
|
}
|
||||||
|
log.info("解析得到的muid={}", muid);
|
||||||
|
log.info("解析得到的状态码是:{}", status);
|
||||||
|
|
||||||
|
if (muid != null && !muid.isEmpty()) {
|
||||||
|
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
// 将设备信息存入Map
|
||||||
|
System.out.println("Device registered: " + muid + " at " + deviceIp + ":" + devicePort);
|
||||||
|
|
||||||
|
if (Objects.isNull(device)) {
|
||||||
|
log.info("数据库不存在该设备,muid={}", muid);
|
||||||
|
} else {
|
||||||
|
DeviceInfo deviceInfo = deviceMap.get(muid);
|
||||||
|
if ("1".equals(status)) {
|
||||||
|
if (Objects.isNull(deviceInfo)) {
|
||||||
|
log.info("deviceMap缓存中没有{}这个设备", muid);
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
|
||||||
|
} else {
|
||||||
|
/*if (deviceInfo.getStartCount() && device.getSurplus() > 0 && device.getPaymentMethod() != null && device.getPaymentMethod() == 2){
|
||||||
|
log.info("设备状态为01开机,开始计数startCount为true");
|
||||||
|
int count = device.getSurplus() - 1;
|
||||||
|
device.setSurplus(count);
|
||||||
|
device.setExpireTime(String.valueOf(count));
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}*/
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
|
||||||
|
}
|
||||||
|
String lo = null, la = null;
|
||||||
|
String[] items = receivedMessage.split("\\|");
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("LO")) {
|
||||||
|
lo = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("LA")) {
|
||||||
|
la = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lo != null && la != null) {
|
||||||
|
device.setLo(lo);
|
||||||
|
device.setLa(la);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}
|
||||||
|
parseDeviceInfo(device, receivedMessage);
|
||||||
|
/**
|
||||||
|
* 拿device的硬件版本和软件版本去查device_upgrade表,如果跟当前版本不一致则升级
|
||||||
|
*/
|
||||||
|
DeviceUpgrade upgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
|
||||||
|
Device nDevice = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
if (Objects.nonNull(upgrade) && upgrade.getHVersion().equals(nDevice.getHw()) && !upgrade.getSVersion().equals(nDevice.getSw()) && nDevice.getUpgradeSwitch() == 1) {
|
||||||
|
log.info("回复升级心跳,回复升级心跳回复升级心跳,回复升级心跳,回复升级心跳");
|
||||||
|
replyUpgradeHeartbeat(deviceMap.get(muid), packet);
|
||||||
|
} else {
|
||||||
|
/*String o = (String) redisTemplate.opsForValue().get(UniConstant.REDIS_CURRENT_DEVICE_USER + device.getDeviceId());
|
||||||
|
PrDTO prDTO = generatePrService.generatePr(o);
|
||||||
|
PrDTO cachePrdto = (PrDTO) redisTemplate.opsForValue().get(o + device.getDeviceId());*/
|
||||||
|
replyHeartbeat(deviceMap.get(muid), packet, null, null);
|
||||||
|
}
|
||||||
|
DeviceUsageDetail detail = new DeviceUsageDetail();
|
||||||
|
detail.setStatus(status);
|
||||||
|
recordUse(device, detail);
|
||||||
|
if (device.getOperatingStatus() == 0) {
|
||||||
|
changeDeviceOperatingStatus(device.getDeviceId(), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((("1".equals(status) && device.getSurplus() < 1) || device.getForcePay() == 1) && device.getFreeCount() < 1) {
|
||||||
|
log.info("设备状态为1,无剩余使用次数,马上停,强制付费");
|
||||||
|
String c1 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c1.replace("{uid}", muid).replace("{date}", now).replace("{1}", "0");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String s = replace.replace("{CRC}", asciiHex);
|
||||||
|
byte[] sendData = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
deviceMapper.updateStatus(device.getDeviceId(), "0");
|
||||||
|
}
|
||||||
|
if ("2".equals(status)) {
|
||||||
|
updateLastRunTime(device);
|
||||||
|
String mo = parseMo(device, receivedMessage);
|
||||||
|
if ((device.getSurplus() < 1 || device.getForcePay() == 1) && device.getFreeCount() < 1) {
|
||||||
|
log.info("设备状态为2,五剩余使用次数,马上听");
|
||||||
|
//马上停
|
||||||
|
String c2 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c2.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now).replace("{1}", "0").replace("{2}", "000");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String s = replace.replace("{CRC}", asciiHex);
|
||||||
|
byte[] sendData = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
|
||||||
|
deviceMapper.updateStatus(device.getDeviceId(), "0");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Device dvie = toLiliao(device.getDeviceId());
|
||||||
|
DeviceUsageDetail detail = parseMsgToDetail(receivedMessage);
|
||||||
|
detail.setStatus(status);
|
||||||
|
recordUse(dvie, detail);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("记录设备使用发生异常", e);
|
||||||
|
}
|
||||||
|
if (device.getPaymentMethod() == 1) {
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
|
||||||
|
} else {
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort, true));
|
||||||
|
}
|
||||||
|
replyHeartbeat(deviceMap.get(muid), packet, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("3".equals(status)) {
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
|
||||||
|
|
||||||
|
// String o = (String) redisTemplate.opsForValue().get(UniConstant.REDIS_CURRENT_DEVICE_USER + device.getDeviceId());
|
||||||
|
// PrDTO o1 = (PrDTO) redisTemplate.opsForValue().get(o + device.getDeviceId());
|
||||||
|
//openid是扫码开机的时候放到redis的
|
||||||
|
// String openid = (String) redisTemplate.opsForValue().get(UniConstant.DEVICE_ID + device.getDeviceId());
|
||||||
|
// String openid = "oATNGvnMbu6tbNgbnFZPWtJBGvFM";
|
||||||
|
Integer appUserId = 9;
|
||||||
|
PrDTO prDTO = generatePrService.generatePr(appUserId);
|
||||||
|
if (Objects.nonNull(prDTO)){
|
||||||
|
List<PrDTO.PrItem> prItems = prDTO.getPrItems();
|
||||||
|
if (CollectionUtils.isNotEmpty(prItems)){
|
||||||
|
List<UserTreatmentParameters> list = new ArrayList<>();
|
||||||
|
for (PrDTO.PrItem prItem : prItems) {
|
||||||
|
UserTreatmentParameters userTreatmentParameters = new UserTreatmentParameters();
|
||||||
|
userTreatmentParameters.setAppUserId(appUserId);
|
||||||
|
userTreatmentParameters.setDeviceId(device.getDeviceId());
|
||||||
|
userTreatmentParameters.setFr(prItem.getFr());
|
||||||
|
userTreatmentParameters.setPl(prItem.getPl());
|
||||||
|
userTreatmentParameters.setPw(prItem.getPw());
|
||||||
|
userTreatmentParameters.setUl(prItem.getUl());
|
||||||
|
userTreatmentParameters.setTl(prItem.getTl());
|
||||||
|
userTreatmentParameters.setCreateTime(LocalDateTime.now());
|
||||||
|
userTreatmentParameters.setStatus(1);
|
||||||
|
list.add(userTreatmentParameters);
|
||||||
|
}
|
||||||
|
List<UserTreatmentParameters> userTreatmentParametersList = userTreatmentParametersMapper.selectList(new LambdaQueryWrapper<UserTreatmentParameters>().eq(UserTreatmentParameters::getAppUserId, appUserId));
|
||||||
|
if (CollectionUtils.isEmpty(userTreatmentParametersList)){
|
||||||
|
userTreatmentParametersMapper.insert(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replyHeartbeat(deviceMap.get(muid), packet, prDTO, null);
|
||||||
|
}
|
||||||
|
if (Objects.isNull(deviceInfo)) {
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
|
||||||
|
deviceInfo = deviceMap.get(muid);
|
||||||
|
}
|
||||||
|
if ("9".equals(status)) {
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
/*String o = (String) redisTemplate.opsForValue().get(UniConstant.REDIS_CURRENT_DEVICE_USER + device.getDeviceId());
|
||||||
|
PrDTO prDTO = (PrDTO) redisTemplate.opsForValue().get(o + device.getDeviceId());*/
|
||||||
|
String prId = null,tn = null;
|
||||||
|
String[] items = receivedMessage.split("\\|");
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("CI")){
|
||||||
|
prId = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("TN")){
|
||||||
|
tn = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrDTO prDTO = prId == null ? null : (PrDTO) redisTemplate.opsForValue().get(prId);
|
||||||
|
if (Objects.isNull(prDTO)) {
|
||||||
|
log.info("status=9,proDTO is null;status=9,proDTO is null;");
|
||||||
|
log.info("status=9,proDTO is null;status=9,proDTO is null;");
|
||||||
|
log.info("status=9,proDTO is null;status=9,proDTO is null;");
|
||||||
|
log.info("status=9,proDTO is null;status=9,proDTO is null;");
|
||||||
|
log.info("status=9,proDTO is null;status=9,proDTO is null;");
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceInfo = deviceMap.get(muid);
|
||||||
|
replyHeartbeat(deviceInfo, packet, prDTO, tn);
|
||||||
|
}
|
||||||
|
/*if ("4".equals(status) && deviceInfo.getStartCount() && device.getPaymentMethod() != null && device.getPaymentMethod() == 2){
|
||||||
|
log.info("设备状态为4,关机,并且startCount为true");
|
||||||
|
int count = device.getSurplus() - 1;
|
||||||
|
device.setSurplus(count);
|
||||||
|
device.setExpireTime(String.valueOf(count));
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
|
||||||
|
}*/
|
||||||
|
if ("4".equals(status)) {
|
||||||
|
try {
|
||||||
|
Device selectById = deviceMapper.selectById(device.getDeviceId());
|
||||||
|
if (selectById.getForcePay() == 2) {
|
||||||
|
Device dce = new Device();
|
||||||
|
dce.setDeviceId(device.getDeviceId());
|
||||||
|
dce.setForcePay(1);
|
||||||
|
dce.setStatus("0");
|
||||||
|
deviceMapper.updateById(dce);
|
||||||
|
}
|
||||||
|
if (selectById.getFreeCount() > 0) {
|
||||||
|
Device device5 = new Device();
|
||||||
|
device5.setDeviceId(device.getDeviceId());
|
||||||
|
device5.setFreeCount(selectById.getFreeCount() - 1);
|
||||||
|
deviceMapper.updateById(device5);
|
||||||
|
}
|
||||||
|
changeDeviceOperatingStatus(device.getDeviceId(), 1);
|
||||||
|
updateRecord(device.getDeviceId());
|
||||||
|
deleteUserTreatParam(device.getDeviceId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("更新设备使用记录发生异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//马上回
|
||||||
|
/*log.info("马上回------");
|
||||||
|
// udpClientService.sendCommand(deviceIp,devicePort,"$01|MU000B57020457D4B100001F97|DT20251011163826|ON0|CF1|WM1|TC000|*7E\r\n");
|
||||||
|
InetAddress address = null;
|
||||||
|
try {
|
||||||
|
address = InetAddress.getByName(deviceIp);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
|
||||||
|
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
String command = "$01|MU000B57020457D4B100001F97|DT20251011163826|ON0|CF1|WM1|TC000|*7E\r\n";
|
||||||
|
if ("1".equals(status)){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", "0");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
command = replace.replace("{CRC}", asciiHex);
|
||||||
|
}
|
||||||
|
if ("2".equals(status)){
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c02.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now).replace("{1}", "0").replace("{2}", "000");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
command = replace.replace("{CRC}", asciiHex);
|
||||||
|
}
|
||||||
|
byte[] sendData = command.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getPR(DeviceInfo info, DatagramPacket packet) {
|
||||||
|
if (Objects.isNull(info)) {
|
||||||
|
log.info("method->replyHeartbeat,DeviceInfo is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|PR1|*{CRC}\r\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyHeartbeat(DeviceInfo info, DatagramPacket packet, PrDTO prDTO, String tn) {
|
||||||
|
if (Objects.isNull(info)) {
|
||||||
|
log.info("method->replyHeartbeat,DeviceInfo is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String status = info.getStatus();
|
||||||
|
String muid = info.getMuid();
|
||||||
|
switch (status) {
|
||||||
|
case "1":
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|*{CRC}\r\n";
|
||||||
|
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c01.replace("{uid}", muid).replace("{date}", now)
|
||||||
|
.replace("{1}", device.getStatus()).replace("{2}", device.getCf());
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String message = replace.replace("{CRC}", asciiHex);
|
||||||
|
byte[] sendData = message.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(
|
||||||
|
sendData,
|
||||||
|
sendData.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "2":
|
||||||
|
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
Device device2 = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
String now2 = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace2 = c02.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now2).replace("{1}", device2.getStatus()).replace("{2}", "000");
|
||||||
|
String crc2 = replace2.substring(1, replace2.lastIndexOf("*"));
|
||||||
|
String asciiHex2 = XorUtil.xorAsciiHex(crc2);
|
||||||
|
String msg = replace2.replace("{CRC}", asciiHex2);
|
||||||
|
byte[] sendData2 = msg.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
DatagramPacket sendPacket2 = new DatagramPacket(
|
||||||
|
sendData2,
|
||||||
|
sendData2.length,
|
||||||
|
packet.getSocketAddress()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket2);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "3":
|
||||||
|
String defaultDm = "$03|MU{uid}|CI00|CN00|*{CRC}\r\n";
|
||||||
|
String dm = "$03|MU{uid}|CI{1}|CN{2}|*{CRC}\r\n";
|
||||||
|
if (prDTO == null) {
|
||||||
|
log.info("status==3;prDTO=====null;===null");
|
||||||
|
defaultDm = defaultDm.replace("{uid}", muid);
|
||||||
|
String substring = defaultDm.substring(1, defaultDm.lastIndexOf("*"));
|
||||||
|
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
|
||||||
|
String s = defaultDm.replace("{CRC}", xorAsciiHex);
|
||||||
|
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
|
||||||
|
try {
|
||||||
|
serverSocket.send(datagramPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("prDTO========={}", prDTO.toString());
|
||||||
|
redisTemplate.opsForValue().set(prDTO.getId(),prDTO,2,TimeUnit.HOURS);
|
||||||
|
List<PrDTO.PrItem> prItems = prDTO.getPrItems();
|
||||||
|
String cn = prItems.size() > 9 ? String.valueOf(prItems.size()) : "0"+prItems.size();
|
||||||
|
dm = dm.replace("{uid}", muid).replace("{1}", prDTO.getId()).replace("{2}", cn);
|
||||||
|
String substring = dm.substring(1, dm.lastIndexOf("*"));
|
||||||
|
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
|
||||||
|
String s = dm.replace("{CRC}", xorAsciiHex);
|
||||||
|
log.info("回传给硬件的数据:{}",s);
|
||||||
|
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
|
||||||
|
try {
|
||||||
|
serverSocket.send(datagramPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "9":
|
||||||
|
if (prDTO == null) {
|
||||||
|
log.info("case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null");
|
||||||
|
String defaultDm9 = "$03|MU{uid}|CI123456790123456|TN01|FR03|PW50|PL08|UL01|TL017|*{CRC}\r\n";
|
||||||
|
String substring = defaultDm9.substring(1, defaultDm9.lastIndexOf("*"));
|
||||||
|
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
|
||||||
|
String s = defaultDm9.replace("{CRC}", xorAsciiHex);
|
||||||
|
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
|
||||||
|
try {
|
||||||
|
serverSocket.send(datagramPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<PrDTO.PrItem> prItems = prDTO.getPrItems();
|
||||||
|
// String tn1 = tn.substring(1);
|
||||||
|
PrDTO.PrItem prItem = prItems.get(Integer.parseInt(tn)-1);
|
||||||
|
String cm9 = "$30|MU{uid}|CI{1}|TN{2}|FR{3}|PW{4}|PL{5}|UL{6}|TL{7}|*{CRC}\r\n";
|
||||||
|
cm9 = cm9.replace("{uid}", muid).replace("{1}", prDTO.getId()).replace("{2}", tn)
|
||||||
|
.replace("{3}", prItem.getFr()).replace("{4}", prItem.getPw()).replace("{5}", prItem.getPl())
|
||||||
|
.replace("{6}", prItem.getUl()).replace("{7}", prItem.getTl());
|
||||||
|
String substring = cm9.substring(1, cm9.lastIndexOf("*"));
|
||||||
|
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
|
||||||
|
String s = cm9.replace("{CRC}", xorAsciiHex);
|
||||||
|
log.info("status=9,远程下参数数据是:{}",s);
|
||||||
|
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
|
||||||
|
try {
|
||||||
|
serverSocket.send(datagramPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseDeviceInfo(Device device, String msg) {
|
||||||
|
String[] items = msg.split("\\|");
|
||||||
|
String hw = null, sw = null, ic = null, cf = null, wm = null, cr = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("HW")) {
|
||||||
|
hw = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("SW")) {
|
||||||
|
sw = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("IC")) {
|
||||||
|
ic = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("CF")) {
|
||||||
|
cf = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("WM")) {
|
||||||
|
wm = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("CR")) {
|
||||||
|
cr = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
device.setHw(hw);
|
||||||
|
device.setSw(sw);
|
||||||
|
device.setIccid(ic);
|
||||||
|
if (StringUtils.isBlank(device.getCf())) {
|
||||||
|
device.setCf(cf);
|
||||||
|
}
|
||||||
|
device.setWm(wm);
|
||||||
|
device.setCr(cr);
|
||||||
|
device.setOperatingStatus(3);
|
||||||
|
device.setLastRunTime(LocalDateTime.now());
|
||||||
|
log.info("解析设备回复的数据得到的硬件版本为:{},软件版本为:{}",hw,sw);
|
||||||
|
log.info("服务器上的LocalDateTime.now()========={}", LocalDateTime.now());
|
||||||
|
deviceMapper.updateDeviceInfo(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseMo(Device device, String msg) {
|
||||||
|
String[] items = msg.split("\\|");
|
||||||
|
String mo = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("MO")) {
|
||||||
|
mo = item.substring(2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
device.setMo(mo);
|
||||||
|
Device dv = new Device();
|
||||||
|
dv.setDeviceId(device.getDeviceId());
|
||||||
|
dv.setMo(mo);
|
||||||
|
deviceMapper.updateById(dv);
|
||||||
|
return mo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteUserTreatParam(String deviceId){
|
||||||
|
LambdaUpdateWrapper<UserTreatmentParameters> updateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
updateWrapper.set(UserTreatmentParameters::getStatus,0).eq(UserTreatmentParameters::getDeviceId,deviceId);
|
||||||
|
userTreatmentParametersMapper.update(updateWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeviceUsageDetail parseMsgToDetail(String msg) {
|
||||||
|
String[] items = msg.split("\\|");
|
||||||
|
String fr = null, pw = null, pl = null, ul = null, wt = null;
|
||||||
|
for (String item : items) {
|
||||||
|
if (item.startsWith("FR")) {
|
||||||
|
fr = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PW")) {
|
||||||
|
pw = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("PL")) {
|
||||||
|
pl = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("UL")) {
|
||||||
|
ul = item.substring(2);
|
||||||
|
}
|
||||||
|
if (item.startsWith("WT")) {
|
||||||
|
wt = item.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeviceUsageDetail detail = new DeviceUsageDetail();
|
||||||
|
detail.setFr(fr);
|
||||||
|
detail.setPw(pw);
|
||||||
|
detail.setPl(pl);
|
||||||
|
detail.setUl(ul);
|
||||||
|
detail.setWt(wt);
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLastRunTime(Device device) {
|
||||||
|
Device d = new Device();
|
||||||
|
d.setDeviceId(device.getDeviceId());
|
||||||
|
d.setLastRunTime(LocalDateTime.now());
|
||||||
|
deviceMapper.updateById(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Device toLiliao(String deviceId) {
|
||||||
|
Device device = deviceMapper.selectById(deviceId);
|
||||||
|
if (Objects.nonNull(device) && device.getOperatingStatus() != 0) {
|
||||||
|
device.setOperatingStatus(0);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
deviceTask.addAbnormalDeviceTask(deviceId);
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordUse(Device device, DeviceUsageDetail detail) {
|
||||||
|
if (Objects.isNull(device)) {
|
||||||
|
log.info("设备使用记录recordUse->device is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
device.setLastRunTime(LocalDateTime.now());
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
DeviceUsageRecord record = deviceUsageRecordMapper.selectOne(new LambdaQueryWrapper<DeviceUsageRecord>()
|
||||||
|
.eq(DeviceUsageRecord::getDeviceId, device.getDeviceId())
|
||||||
|
.eq(DeviceUsageRecord::getStartUseFlag, "true"));
|
||||||
|
if (Objects.nonNull(record)) {
|
||||||
|
DeviceUsageDetail selectOne = usageDetailMapper.selectOne(new LambdaQueryWrapper<DeviceUsageDetail>().
|
||||||
|
eq(DeviceUsageDetail::getUsageRecordId, record.getId()).orderByDesc(DeviceUsageDetail::getCreateTime).last("limit 1"));
|
||||||
|
long seconds = Duration.between(selectOne.getCreateTime(), LocalDateTime.now()).getSeconds();
|
||||||
|
if ("2".equals(detail.getStatus()) && seconds > 30) {
|
||||||
|
detail.setUsageRecordId(record.getId());
|
||||||
|
detail.setCreateTime(LocalDateTime.now());
|
||||||
|
usageDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
log.info("设备正在运行");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DeviceUsageRecord deviceUsageRecord = new DeviceUsageRecord();
|
||||||
|
deviceUsageRecord.setStartTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceUsageRecord.setDeviceId(device.getDeviceId());
|
||||||
|
deviceUsageRecord.setStartUseFlag(UniConstant.CONST_TRUE);
|
||||||
|
deviceUsageRecord.setWm(device.getWm());
|
||||||
|
deviceUsageRecord.setBelong(device.getAffiliatedWith());
|
||||||
|
deviceUsageRecord.setMuid(device.getMuid());
|
||||||
|
deviceUsageRecordMapper.insert(deviceUsageRecord);
|
||||||
|
if (device.getPaymentMethod() != null && device.getPaymentMethod() == 2 && device.getSurplus() > 0) {
|
||||||
|
int count = device.getSurplus() - 1;
|
||||||
|
device.setSurplus(count);
|
||||||
|
device.setExpireTime(String.valueOf(count));
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}
|
||||||
|
detail.setCreateTime(LocalDateTime.now());
|
||||||
|
detail.setUsageRecordId(deviceUsageRecord.getId());
|
||||||
|
/*
|
||||||
|
如果真要记录待机状态,那么把status=1的recordUse()放开,在这里加上根据deviceUsageRecord.getId()和status=1去查DeviceUsageDetail表,
|
||||||
|
如果不为空则不插入数据,即只记录一条状态为待机的数据
|
||||||
|
*/
|
||||||
|
List<DeviceUsageDetail> usageDetails = usageDetailMapper.selectList(new LambdaQueryWrapper<DeviceUsageDetail>().eq(DeviceUsageDetail::getUsageRecordId, deviceUsageRecord.getId())
|
||||||
|
.eq(DeviceUsageDetail::getStatus, "1"));
|
||||||
|
if (CollectionUtils.isEmpty(usageDetails)) {
|
||||||
|
usageDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRecord(String deviceId) {
|
||||||
|
DeviceUsageRecord deviceUsageRecord = deviceUsageRecordMapper.selectOne(new LambdaQueryWrapper<DeviceUsageRecord>()
|
||||||
|
.eq(DeviceUsageRecord::getDeviceId, deviceId)
|
||||||
|
.eq(DeviceUsageRecord::getStartUseFlag, UniConstant.CONST_TRUE));
|
||||||
|
if (Objects.isNull(deviceUsageRecord)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deviceUsageRecord.setEndTime(LocalDateTime.now(Clock.systemDefaultZone()));
|
||||||
|
deviceUsageRecord.setStartUseFlag(UniConstant.CONST_FALSE);
|
||||||
|
deviceUsageRecordMapper.updateById(deviceUsageRecord);
|
||||||
|
DeviceUsageDetail detail = new DeviceUsageDetail();
|
||||||
|
detail.setStatus("4");
|
||||||
|
detail.setCreateTime(LocalDateTime.now());
|
||||||
|
detail.setUsageRecordId(deviceUsageRecord.getId());
|
||||||
|
usageDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeDeviceOperatingStatus(String deviceId, Integer status) {
|
||||||
|
Device device = deviceMapper.selectById(deviceId);
|
||||||
|
if (Objects.isNull(device)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
device.setOperatingStatus(status);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean reply(Device device, String status) {
|
||||||
|
String muid = device.getMuid();
|
||||||
|
DeviceInfo deviceInfo = getDeviceInfo(muid);
|
||||||
|
if (deviceInfo == null) {
|
||||||
|
log.info("设备会话已过期,请设备先上报一次数据");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String message = "";
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|*{CRC}\r\n";
|
||||||
|
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
|
||||||
|
if ("1".equals(deviceInfo.getStatus())) {
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", status).replace("{2}", device.getCf());
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
message = replace.replace("{CRC}", asciiHex);
|
||||||
|
} else if ("2".equals(deviceInfo.getStatus())) {
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String replace = c02.replace("{uid}", muid)
|
||||||
|
.replace("{date}", now).replace("{1}", status).replace("{2}", "000");
|
||||||
|
String crc = replace.substring(1, replace.lastIndexOf("*"));
|
||||||
|
String asciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
message = replace.replace("{CRC}", asciiHex);
|
||||||
|
} else if ("4".equals(deviceInfo.getStatus())) {
|
||||||
|
log.info("设备为关机状态");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
log.info("最终发送的数据为:{}", message);
|
||||||
|
byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
||||||
|
InetAddress address = InetAddress.getByName(deviceInfo.getIp());
|
||||||
|
DatagramPacket packet = new DatagramPacket(data, data.length, address, deviceInfo.getPort());
|
||||||
|
serverSocket.send(packet);
|
||||||
|
System.out.printf("UDP Reply sent to %s:%d -> %s%n", deviceInfo.getIp(), deviceInfo.getPort(), message);
|
||||||
|
device.setStatus(status);
|
||||||
|
deviceMapper.updateById(device);
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.info("回复设备UDP消息发送异常");
|
||||||
|
e.printStackTrace();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据实际协议解析设备ID
|
||||||
|
* 这是一个示例,您需要根据硬件数据包的实际格式重写此方法
|
||||||
|
*
|
||||||
|
* @param message 收到的原始消息
|
||||||
|
* @return 解析出的设备ID
|
||||||
|
*/
|
||||||
|
private String parsemuid(String message) {
|
||||||
|
Pattern p = Pattern.compile("^[^|]*\\|([^|]+)\\|");
|
||||||
|
Matcher matcher = p.matcher(message);
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1).substring(2);
|
||||||
|
}
|
||||||
|
// 如果协议里没有ID,也可以用IP:端口作为唯一标识
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备信息
|
||||||
|
*
|
||||||
|
* @param muid 设备ID
|
||||||
|
* @return 设备信息,如果不存在则返回null
|
||||||
|
*/
|
||||||
|
public DeviceInfo getDeviceInfo(String muid) {
|
||||||
|
DeviceInfo deviceInfo = deviceMap.get(muid);
|
||||||
|
if (Objects.nonNull(deviceInfo) && System.currentTimeMillis() - deviceInfo.getLastActiveTime() < SESSION_TIMEOUT) {
|
||||||
|
return deviceInfo;
|
||||||
|
} else {
|
||||||
|
if (Objects.isNull(deviceInfo)) {
|
||||||
|
deviceMap.remove(muid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!deviceInfo.getStartCount()) {
|
||||||
|
deviceMap.remove(muid);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有在线设备
|
||||||
|
*/
|
||||||
|
public ConcurrentHashMap<String, DeviceInfo> getOnlineDevices() {
|
||||||
|
return new ConcurrentHashMap<>(deviceMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyUpgradeHeartbeat(DeviceInfo info, DatagramPacket packet) {
|
||||||
|
if (Objects.isNull(info)) {
|
||||||
|
log.info("method->replyHeartbeat,DeviceInfo is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|UP{3}|WM1|TC000|*{CRC}\r\n";
|
||||||
|
/*
|
||||||
|
查device_upgrade表拿到当前版本升级包名称,然后去/opt/jkadmin/upgrade下面拿到升级包
|
||||||
|
调fileService拆包,得到包数量,替换{3},然后回复
|
||||||
|
*/
|
||||||
|
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
|
||||||
|
if (Objects.isNull(deviceUpgrade)) {
|
||||||
|
replyHeartbeat(info, packet, null, null);
|
||||||
|
} else {
|
||||||
|
String fileUrl = UPGRADE_PACKAGE_ROOT_PATH + deviceUpgrade.getFileName();
|
||||||
|
List<byte[]> packages = null;
|
||||||
|
try {
|
||||||
|
packages = fileService.splitFileWithNIO(fileUrl);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("拆包发生异常-.-.-.-.-.-.-.-.-.", e);
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(packages) && packages.size() <= 32) {
|
||||||
|
String muid = info.getMuid();
|
||||||
|
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
|
||||||
|
if (Objects.isNull(device)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||||
|
String r = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", device.getStatus())
|
||||||
|
.replace("{2}", device.getCf()).replace("{3}", String.valueOf(packages.size()));
|
||||||
|
String crc = r.substring(1, r.lastIndexOf("*"));
|
||||||
|
String xorAsciiHex = XorUtil.xorAsciiHex(crc);
|
||||||
|
String msg = r.replace("{CRC}", xorAsciiHex);
|
||||||
|
log.info("回复升级心跳数据:{}", msg);
|
||||||
|
byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length, packet.getSocketAddress());
|
||||||
|
try {
|
||||||
|
serverSocket.send(sendPacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("回复升级心跳包发生异常", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("升级包为空或升级包大小超过1024*32");
|
||||||
|
replyHeartbeat(info, packet, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.properties.SysWxProperties;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author hao
|
||||||
|
* @Date 2025/9/11 10:04
|
||||||
|
* @Version 1.0
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class WxAuthLoginService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysWxProperties wxProperties;
|
||||||
|
|
||||||
|
private static String authUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=${1}&redirect_uri=${2}&response_type=code&scope=snsapi_login&state=${3}#wechat_redirect";
|
||||||
|
|
||||||
|
public void auth(HttpServletResponse response,String deviceId) throws IOException {
|
||||||
|
log.info("deviceId={}",deviceId);
|
||||||
|
String redirectUrl = URLEncoder.encode(wxProperties.getRedirectUrl(), StandardCharsets.UTF_8.name());
|
||||||
|
authUrl = authUrl.replace("${1}",wxProperties.getAppid()).replace("${2}",redirectUrl)
|
||||||
|
.replace("${3}",deviceId);
|
||||||
|
response.sendRedirect(authUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
package cn.unizk.service;
|
||||||
|
|
||||||
|
import cn.unizk.entity.po.WxUser;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
public interface WxUserService extends IService<WxUser> {
|
||||||
|
}
|
||||||
|
*/
|
||||||
Loaded 100 of 1456 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user