diff --git a/rc_autoplc_backend/.gitattributes b/rc_autoplc_backend/.gitattributes
new file mode 100644
index 0000000..3b41682
--- /dev/null
+++ b/rc_autoplc_backend/.gitattributes
@@ -0,0 +1,2 @@
+/mvnw text eol=lf
+*.cmd text eol=crlf
diff --git a/rc_autoplc_backend/.gitignore b/rc_autoplc_backend/.gitignore
new file mode 100644
index 0000000..60c0efc
--- /dev/null
+++ b/rc_autoplc_backend/.gitignore
@@ -0,0 +1,26 @@
+# Compiled class file
+*.class
+*.bak
+*.swp
+target/
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
diff --git a/rc_autoplc_backend/.idea/.gitignore b/rc_autoplc_backend/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/rc_autoplc_backend/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/rc_autoplc_backend/.idea/compiler.xml b/rc_autoplc_backend/.idea/compiler.xml
new file mode 100644
index 0000000..c858a1e
--- /dev/null
+++ b/rc_autoplc_backend/.idea/compiler.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/.idea/encodings.xml b/rc_autoplc_backend/.idea/encodings.xml
new file mode 100644
index 0000000..e768916
--- /dev/null
+++ b/rc_autoplc_backend/.idea/encodings.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/.idea/jarRepositories.xml b/rc_autoplc_backend/.idea/jarRepositories.xml
new file mode 100644
index 0000000..082f15f
--- /dev/null
+++ b/rc_autoplc_backend/.idea/jarRepositories.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/.idea/misc.xml b/rc_autoplc_backend/.idea/misc.xml
new file mode 100644
index 0000000..67e1e61
--- /dev/null
+++ b/rc_autoplc_backend/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/.idea/uiDesigner.xml b/rc_autoplc_backend/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/rc_autoplc_backend/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/.idea/vcs.xml b/rc_autoplc_backend/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/rc_autoplc_backend/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/HELP.md b/rc_autoplc_backend/HELP.md
new file mode 100644
index 0000000..5731530
--- /dev/null
+++ b/rc_autoplc_backend/HELP.md
@@ -0,0 +1,28 @@
+# Getting Started
+
+### Reference Documentation
+
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.12/maven-plugin)
+* [Create an OCI image](https://docs.spring.io/spring-boot/3.4.12/maven-plugin/build-image.html)
+* [Spring Boot DevTools](https://docs.spring.io/spring-boot/3.4.12/reference/using/devtools.html)
+* [Spring Web](https://docs.spring.io/spring-boot/3.4.12/reference/web/servlet.html)
+
+### Guides
+
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
+
+### Maven Parent overrides
+
+Due to Maven's design, elements are inherited from the parent POM to the project POM.
+While most of the inheritance is fine, it also inherits unwanted elements like `` and `` from the
+parent.
+To prevent this, the project POM contains empty overrides for these elements.
+If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides.
+
diff --git a/rc_autoplc_backend/LICENSE b/rc_autoplc_backend/LICENSE
new file mode 100644
index 0000000..e5cbdd7
--- /dev/null
+++ b/rc_autoplc_backend/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a userBusy through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive userBusy interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the userBusy that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of userBusy commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive userBusy interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular userBusy, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular userBusy or of the way in which the particular userBusy
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/rc_autoplc_backend/README.en.md b/rc_autoplc_backend/README.en.md
new file mode 100644
index 0000000..e34317d
--- /dev/null
+++ b/rc_autoplc_backend/README.en.md
@@ -0,0 +1,36 @@
+# 融创智能PLC后台系统
+
+#### Description
+智能plc管理后台系统
+
+#### 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/)
diff --git a/rc_autoplc_backend/README.md b/rc_autoplc_backend/README.md
new file mode 100644
index 0000000..252cc97
--- /dev/null
+++ b/rc_autoplc_backend/README.md
@@ -0,0 +1,42 @@
+# 融创智能PLC后台系统
+
+#### 介绍
+智能plc管理后台系统
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+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/)
+
+#### 增加日志生成:
+1. 2026-4-3:用户登录日志信息
+2. 2026-4-3:SOP用户操作日志信息
+3. 2026-4-3:基础数据(功能岛、SOP序列)用户操作(增-删-改)日志
\ No newline at end of file
diff --git a/rc_autoplc_backend/mvnw b/rc_autoplc_backend/mvnw
new file mode 100644
index 0000000..bd8896b
--- /dev/null
+++ b/rc_autoplc_backend/mvnw
@@ -0,0 +1,295 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.3.4
+#
+# Optional ENV vars
+# -----------------
+# JAVA_HOME - location of a JDK home dir, required when download maven via java source
+# MVNW_REPOURL - repo url base for downloading maven distribution
+# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
+# ----------------------------------------------------------------------------
+
+set -euf
+[ "${MVNW_VERBOSE-}" != debug ] || set -x
+
+# OS specific support.
+native_path() { printf %s\\n "$1"; }
+case "$(uname)" in
+CYGWIN* | MINGW*)
+ [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
+ native_path() { cygpath --path --windows "$1"; }
+ ;;
+esac
+
+# set JAVACMD and JAVACCMD
+set_java_home() {
+ # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+ if [ -n "${JAVA_HOME-}" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACCMD="$JAVA_HOME/jre/sh/javac"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ JAVACCMD="$JAVA_HOME/bin/javac"
+
+ if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
+ echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
+ echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
+ return 1
+ fi
+ fi
+ else
+ JAVACMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v java
+ )" || :
+ JAVACCMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v javac
+ )" || :
+
+ if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
+ echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
+ return 1
+ fi
+ fi
+}
+
+# hash string like Java String::hashCode
+hash_string() {
+ str="${1:-}" h=0
+ while [ -n "$str" ]; do
+ char="${str%"${str#?}"}"
+ h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
+ str="${str#?}"
+ done
+ printf %x\\n $h
+}
+
+verbose() { :; }
+[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
+
+die() {
+ printf %s\\n "$1" >&2
+ exit 1
+}
+
+trim() {
+ # MWRAPPER-139:
+ # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
+ # Needed for removing poorly interpreted newline sequences when running in more
+ # exotic environments such as mingw bash on Windows.
+ printf "%s" "${1}" | tr -d '[:space:]'
+}
+
+scriptDir="$(dirname "$0")"
+scriptName="$(basename "$0")"
+
+# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
+while IFS="=" read -r key value; do
+ case "${key-}" in
+ distributionUrl) distributionUrl=$(trim "${value-}") ;;
+ distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
+ esac
+done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
+[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+
+case "${distributionUrl##*/}" in
+maven-mvnd-*bin.*)
+ MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
+ case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
+ *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
+ :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
+ :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
+ :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
+ *)
+ echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
+ distributionPlatform=linux-amd64
+ ;;
+ esac
+ distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
+ ;;
+maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
+*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
+esac
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
+distributionUrlName="${distributionUrl##*/}"
+distributionUrlNameMain="${distributionUrlName%.*}"
+distributionUrlNameMain="${distributionUrlNameMain%-bin}"
+MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
+MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
+
+exec_maven() {
+ unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
+ exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
+}
+
+if [ -d "$MAVEN_HOME" ]; then
+ verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ exec_maven "$@"
+fi
+
+case "${distributionUrl-}" in
+*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
+*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
+esac
+
+# prepare tmp dir
+if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
+ clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
+ trap clean HUP INT TERM EXIT
+else
+ die "cannot create temp dir"
+fi
+
+mkdir -p -- "${MAVEN_HOME%/*}"
+
+# Download and Install Apache Maven
+verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+verbose "Downloading from: $distributionUrl"
+verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+# select .zip or .tar.gz
+if ! command -v unzip >/dev/null; then
+ distributionUrl="${distributionUrl%.zip}.tar.gz"
+ distributionUrlName="${distributionUrl##*/}"
+fi
+
+# verbose opt
+__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
+[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
+
+# normalize http auth
+case "${MVNW_PASSWORD:+has-password}" in
+'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+esac
+
+if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
+ verbose "Found wget ... using wget"
+ wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
+elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
+ verbose "Found curl ... using curl"
+ curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
+elif set_java_home; then
+ verbose "Falling back to use Java to download"
+ javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
+ targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
+ cat >"$javaSource" <<-END
+ public class Downloader extends java.net.Authenticator
+ {
+ protected java.net.PasswordAuthentication getPasswordAuthentication()
+ {
+ return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
+ }
+ public static void main( String[] args ) throws Exception
+ {
+ setDefault( new Downloader() );
+ java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
+ }
+ }
+ END
+ # For Cygwin/MinGW, switch paths to Windows format before running javac and java
+ verbose " - Compiling Downloader.java ..."
+ "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
+ verbose " - Running Downloader.java ..."
+ "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
+fi
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+if [ -n "${distributionSha256Sum-}" ]; then
+ distributionSha256Result=false
+ if [ "$MVN_CMD" = mvnd.sh ]; then
+ echo "Checksum validation is not supported for maven-mvnd." >&2
+ echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ elif command -v sha256sum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
+ distributionSha256Result=true
+ fi
+ elif command -v shasum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
+ distributionSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+ echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ fi
+ if [ $distributionSha256Result = false ]; then
+ echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
+ echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+# unzip and move
+if command -v unzip >/dev/null; then
+ unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
+else
+ tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
+fi
+
+# Find the actual extracted directory name (handles snapshots where filename != directory name)
+actualDistributionDir=""
+
+# First try the expected directory name (for regular distributions)
+if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
+ if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
+ actualDistributionDir="$distributionUrlNameMain"
+ fi
+fi
+
+# If not found, search for any directory with the Maven executable (for snapshots)
+if [ -z "$actualDistributionDir" ]; then
+ # enable globbing to iterate over items
+ set +f
+ for dir in "$TMP_DOWNLOAD_DIR"/*; do
+ if [ -d "$dir" ]; then
+ if [ -f "$dir/bin/$MVN_CMD" ]; then
+ actualDistributionDir="$(basename "$dir")"
+ break
+ fi
+ fi
+ done
+ set -f
+fi
+
+if [ -z "$actualDistributionDir" ]; then
+ verbose "Contents of $TMP_DOWNLOAD_DIR:"
+ verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
+ die "Could not find Maven distribution directory in extracted archive"
+fi
+
+verbose "Found extracted Maven distribution directory: $actualDistributionDir"
+printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
+mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
+
+clean || :
+exec_maven "$@"
diff --git a/rc_autoplc_backend/mvnw.cmd b/rc_autoplc_backend/mvnw.cmd
new file mode 100644
index 0000000..1acdbea
--- /dev/null
+++ b/rc_autoplc_backend/mvnw.cmd
@@ -0,0 +1,189 @@
+<# : batch portion
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.3.4
+@REM
+@REM Optional ENV vars
+@REM MVNW_REPOURL - repo url base for downloading maven distribution
+@REM MVNW_USERNAME/MVNW_PASSWORD - userBusy and password for downloading maven
+@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
+@REM ----------------------------------------------------------------------------
+
+@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
+@SET __MVNW_CMD__=
+@SET __MVNW_ERROR__=
+@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
+@SET PSModulePath=
+@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
+ IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
+)
+@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
+@SET __MVNW_PSMODULEP_SAVE=
+@SET __MVNW_ARG0_NAME__=
+@SET MVNW_USERNAME=
+@SET MVNW_PASSWORD=
+@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
+@echo Cannot start maven from wrapper >&2 && exit /b 1
+@GOTO :EOF
+: end batch / begin powershell #>
+
+$ErrorActionPreference = "Stop"
+if ($env:MVNW_VERBOSE -eq "true") {
+ $VerbosePreference = "Continue"
+}
+
+# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
+$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
+if (!$distributionUrl) {
+ Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+}
+
+switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
+ "maven-mvnd-*" {
+ $USE_MVND = $true
+ $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
+ $MVN_CMD = "mvnd.cmd"
+ break
+ }
+ default {
+ $USE_MVND = $false
+ $MVN_CMD = $script -replace '^mvnw','mvn'
+ break
+ }
+}
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+if ($env:MVNW_REPOURL) {
+ $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
+ $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
+}
+$distributionUrlName = $distributionUrl -replace '^.*/',''
+$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
+
+$MAVEN_M2_PATH = "$HOME/.m2"
+if ($env:MAVEN_USER_HOME) {
+ $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
+}
+
+if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
+ New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
+}
+
+$MAVEN_WRAPPER_DISTS = $null
+if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
+ $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
+} else {
+ $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
+}
+
+$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
+$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
+$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
+
+if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
+ Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
+ exit $?
+}
+
+if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
+ Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
+}
+
+# prepare tmp dir
+$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
+$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
+$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
+trap {
+ if ($TMP_DOWNLOAD_DIR.Exists) {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+ }
+}
+
+New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
+
+# Download and Install Apache Maven
+Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+Write-Verbose "Downloading from: $distributionUrl"
+Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+$webclient = New-Object System.Net.WebClient
+if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
+ $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
+}
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
+if ($distributionSha256Sum) {
+ if ($USE_MVND) {
+ Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
+ }
+ Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
+ if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
+ Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
+ }
+}
+
+# unzip and move
+Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
+
+# Find the actual extracted directory name (handles snapshots where filename != directory name)
+$actualDistributionDir = ""
+
+# First try the expected directory name (for regular distributions)
+$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
+$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
+if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
+ $actualDistributionDir = $distributionUrlNameMain
+}
+
+# If not found, search for any directory with the Maven executable (for snapshots)
+if (!$actualDistributionDir) {
+ Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
+ $testPath = Join-Path $_.FullName "bin/$MVN_CMD"
+ if (Test-Path -Path $testPath -PathType Leaf) {
+ $actualDistributionDir = $_.Name
+ }
+ }
+}
+
+if (!$actualDistributionDir) {
+ Write-Error "Could not find Maven distribution directory in extracted archive"
+}
+
+Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
+Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
+try {
+ Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
+} catch {
+ if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
+ Write-Error "fail to move MAVEN_HOME"
+ }
+} finally {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+}
+
+Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
diff --git a/rc_autoplc_backend/pom.xml b/rc_autoplc_backend/pom.xml
new file mode 100644
index 0000000..ff6d1b4
--- /dev/null
+++ b/rc_autoplc_backend/pom.xml
@@ -0,0 +1,133 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.12
+
+
+
+ com.rczn
+ Rc-autoplc-backend
+ 0.0.1-SNAPSHOT
+ Rc-autoplc-backend
+ Rc-autoplc-backend 聚合父模块
+ pom
+
+
+ rczn-common
+ rczn-autoplc
+ rczn-admin
+
+
+
+ 17
+
+ 3.0.3
+ 2.1.0
+ 4.4.0
+ 4.5.0
+ 6.0.0
+ 1.18.30
+
+
+
+
+
+
+
+ com.rczn
+ rczn-common
+ ${project.version}
+
+
+ com.rczn
+ rczn-autoplc
+ ${project.version}
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ ${mybatis.version}
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ ${pagehelper.version}
+
+
+ com.auth0
+ java-jwt
+ ${jwt.version}
+
+
+ com.github.xiaoymin
+ knife4j-openapi3-jakarta-spring-boot-starter
+ ${knife4j.version}
+
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ ${jakarta.servlet-api.version}
+ provided
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ 2.15.4
+
+
+ org.apache.commons
+ commons-lang3
+ 3.14.0
+
+
+ jakarta.validation
+ jakarta.validation-api
+ 3.0.2
+
+
+
+ com.github.s7connector
+ s7connector
+ 2.1
+
+
+
+ org.apache.commons
+ commons-pool2
+ 2.12.0
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ ${java.version}
+ ${java.version}
+ UTF-8
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/.mvn/wrapper/maven-wrapper.properties b/rc_autoplc_backend/rczn-admin/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..c0bcafe
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,3 @@
+wrapperVersion=3.3.4
+distributionType=only-script
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
diff --git a/rc_autoplc_backend/rczn-admin/pom.xml b/rc_autoplc_backend/rczn-admin/pom.xml
new file mode 100644
index 0000000..cef4882
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/pom.xml
@@ -0,0 +1,123 @@
+
+
+ 4.0.0
+
+ com.rczn
+ Rc-autoplc-backend
+ 0.0.1-SNAPSHOT
+ ../pom.xml
+
+
+ rczn-admin
+ rczn-admin
+ rczn-admin(后台管理模块)
+ jar
+
+
+
+
+ com.rczn
+ rczn-common
+
+
+
+
+ com.rczn
+ rczn-autoplc
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ provided
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+
+
+
+
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ com.auth0
+ java-jwt
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.rczn.RcznAdminApplication
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/RcznAdminApplication.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/RcznAdminApplication.java
new file mode 100644
index 0000000..088abe0
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/RcznAdminApplication.java
@@ -0,0 +1,17 @@
+package com.rczn;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@ComponentScan(value = "com.rczn.*")
+@EnableScheduling
+public class RcznAdminApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(RcznAdminApplication.class, args);
+ }
+
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/CorsConfig.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/CorsConfig.java
new file mode 100644
index 0000000..89628bc
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/CorsConfig.java
@@ -0,0 +1,45 @@
+package com.rczn.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;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**") // 所有接口允许跨域
+ // 替换allowedOrigins为allowedOriginPatterns,支持通配符*
+ .allowedOriginPatterns("*")
+ .allowedMethods("GET", "POST","PATCH", "PUT", "DELETE", "OPTIONS")
+ .allowedHeaders("*")
+ .allowCredentials(true) // 允许携带Cookie
+ .maxAge(3600); // 预检请求缓存1小时
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ CorsConfiguration config = new CorsConfiguration();
+ // 1. 允许前端源(不要用*,和withCredentials=true配合需指定具体源,或用allowedOriginPatterns)
+ config.addAllowedOriginPattern("*");
+ // 2. 允许携带凭证(和前端withCredentials=true对应)
+ config.setAllowCredentials(true);
+ // 3. 允许所有请求方法(包含OPTIONS)
+ config.addAllowedMethod("*");
+ // 4. 允许所有请求头(包含Authorization)
+ config.addAllowedHeader("*");
+ // 5. 预检请求缓存时间(减少OPTIONS请求次数)
+ config.setMaxAge(3600L);
+
+ // 配置生效路径
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/**", config);
+
+ return new CorsFilter(source);
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/Knife4jConfig.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/Knife4jConfig.java
new file mode 100644
index 0000000..052ebcc
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/Knife4jConfig.java
@@ -0,0 +1,38 @@
+package com.rczn.config;
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class Knife4jConfig {
+
+ @Bean
+ public OpenAPI customOpenAPI() {
+ // 1. 声明JWT认证规则
+ String securitySchemeName = "Authorization";
+ return new OpenAPI()
+ // 2. 文档基础信息(可选)
+ .info(new Info()
+ .title("XX自动化编程系统API")
+ .version("1.0.0")
+ .description("集成JWT认证的Knife4j接口文档"))
+ // 3. 配置全局认证规则(所有接口默认需要Token)
+ .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
+ // 4. 定义Token的传递方式(请求头+Bearer格式)
+ .components(new Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(SecurityScheme.Type.HTTP) // HTTP认证
+ .scheme("bearer") // Bearer格式
+ .bearerFormat("JWT") // Token类型为JWT
+ .in(SecurityScheme.In.HEADER) // 放在请求头
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/WebConfig.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/WebConfig.java
new file mode 100644
index 0000000..076da1a
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/config/WebConfig.java
@@ -0,0 +1,55 @@
+package com.rczn.config;
+
+import com.rczn.interceptors.LoginInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+// 必须启用@Configuration,让Spring扫描到
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+ // 必须注入拦截器(取消注释)
+ @Autowired
+ LoginInterceptor loginInterceptor;
+
+ // 注册拦截器
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(loginInterceptor)
+ // 拦截所有请求
+ .addPathPatterns("/**")
+ // 放行Swagger/Knife4j所有相关路径(关键补充/doc.html)
+ .excludePathPatterns(
+ // Knife4j自定义UI路径(核心!)
+ "/doc.html",
+ // Swagger UI页面相关
+ "/swagger-ui/**",
+ "/webjars/**",
+ // SpringDoc接口文档数据相关
+ "/v3/api-docs/**",
+ "/v3/api-docs.yaml",
+ // 旧版Swagger兼容
+ "/swagger-resources/**",
+ "/swagger-ui.html"
+ )
+ // 放行登录/注册接口
+ .excludePathPatterns("/user/login", "/user/register");
+ }
+
+ // 静态资源映射(适配Knife4j+SpringDoc)
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ // Knife4j静态资源(核心补充)
+ registry.addResourceHandler("/doc.html")
+ .addResourceLocations("classpath:/META-INF/resources/");
+ // Swagger UI静态资源
+ registry.addResourceHandler("/swagger-ui/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/springdoc-openapi-ui/");
+ // Webjars通用资源
+ registry.addResourceHandler("/webjars/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/");
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/DepartmentController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/DepartmentController.java
new file mode 100644
index 0000000..c5d16ed
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/DepartmentController.java
@@ -0,0 +1,120 @@
+package com.rczn.controller;
+
+import com.rczn.domain.PageBean;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.Department;
+import com.rczn.system.service.DepartmentService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@RestController
+@RequestMapping("/depart")
+@Tag(name = "部门管理", description = "部门增删改查+分页查询接口")
+public class DepartmentController {
+
+ @Autowired
+ private DepartmentService departmentService;
+
+ /**
+ * 分页查询部门
+ */
+ @GetMapping(value = "/listPage", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "分页查询部门", description = "支持部门名称、编码、父ID模糊/精准查询")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "deptName", description = "部门名称(可选,模糊查询)", required = false, example = "技术部", in = ParameterIn.QUERY),
+ @Parameter(name = "deptCode", description = "部门编码(可选,模糊查询)", required = false, example = "TECH", in = ParameterIn.QUERY),
+ @Parameter(name = "parentId", description = "父部门ID(可选,精准查询)", required = false, example = "1", in = ParameterIn.QUERY)
+ })
+ public Result> getDeptPage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) String deptName,
+ @RequestParam(required = false) String deptCode,
+ @RequestParam(required = false) Integer parentId) {
+ PageBean pageBean = departmentService.selectPage(pageNum, pageSize, deptName, deptCode, parentId);
+ return Result.success(pageBean);
+ }
+
+ /**
+ * 根据ID查询部门
+ */
+ @GetMapping(value = "/getById/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "查询单个部门", description = "根据部门ID查询详情")
+ public Result getDeptById(@PathVariable Long id) {
+ Department department = departmentService.selectById(id);
+ return department != null ? Result.success(department) : Result.error("部门不存在");
+ }
+
+ /**
+ * 新增部门
+ */
+ @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "新增部门", description = "部门名称和编码为必填项")
+ public Result addDept(@RequestBody Department department) {
+ try {
+ Long deptId = departmentService.insert(department);
+ return Result.success(deptId);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 修改部门
+ */
+ @PutMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "修改部门", description = "需传入部门ID,其他字段可选(非空则更新)")
+ public Result updateDept(@RequestBody Department department) {
+ try {
+ Boolean success = departmentService.update(department);
+ return success ? Result.success(true) : Result.error("修改失败(部门不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 删除部门(逻辑删除)
+ */
+ @DeleteMapping(value = "/del/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "删除部门", description = "逻辑删除(设置delSign=1,不物理删除数据)")
+ public Result deleteDept(@PathVariable Long id) {
+ try {
+ Boolean success = departmentService.deleteById(id);
+ return success ? Result.success(true) : Result.error("删除失败(部门不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 新增接口:获取完整部门树(包含所有字段)
+ */
+ @GetMapping(value = "/tree", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "获取完整部门树", description = "返回包含所有字段的部门层级结构")
+ public Result getDeptTree() {
+ List deptTree = departmentService.getDeptTree();
+ return Result.success(deptTree);
+ }
+
+ /**
+ * 新增接口:获取简化部门树(仅ID、名称、子部门,用于下拉选择)
+ */
+ @GetMapping(value = "/simple-tree", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "获取简化部门树", description = "仅返回ID、名称、子部门,适用于下拉选择框等场景")
+ public Result getSimpleDeptTree() {
+ List simpleDeptTree = departmentService.getSimpleDeptTree();
+ return Result.success(simpleDeptTree);
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/HellowAdminController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/HellowAdminController.java
new file mode 100644
index 0000000..d0cdffd
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/HellowAdminController.java
@@ -0,0 +1,19 @@
+package com.rczn.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/admin")
+@Tag(name = "用户管理", description = "用户新增、查询、修改接口")
+public class HellowAdminController {
+
+ @GetMapping("/hellow")
+ @Operation(summary = "查询用户", description = "根据ID查询用户详情") // 替代@ApiOperation
+ public String hellow(){
+ return "hellow admin!!!";
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/PositionController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/PositionController.java
new file mode 100644
index 0000000..96596a1
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/PositionController.java
@@ -0,0 +1,95 @@
+package com.rczn.controller;
+
+import com.rczn.domain.PageBean;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.Position;
+import com.rczn.system.service.PositionService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@RestController
+@RequestMapping("/position")
+@Tag(name = "职位管理", description = "职位增删改查+分页查询接口")
+public class PositionController {
+
+ @Autowired
+ private PositionService positionService;
+
+ @GetMapping(value = "/listPage", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "分页查询职位", description = "支持职位名称、编码模糊查询")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "posiName", description = "职位名称(可选,模糊查询)", required = false, example = "工程师", in = ParameterIn.QUERY),
+ @Parameter(name = "posiCode", description = "职位编码(可选,模糊查询)", required = false, example = "ENG", in = ParameterIn.QUERY)
+ })
+ public Result> getPosiPage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) String posiName,
+ @RequestParam(required = false) String posiCode) {
+ PageBean pageBean = positionService.selectPage(pageNum, pageSize, posiName, posiCode);
+ return Result.success(pageBean);
+ }
+ @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "条件查询列表", description = "支持职位名称、编码模糊查询")
+ @Parameters({
+ @Parameter(name = "posiName", description = "职位名称(可选,模糊查询)", required = false, example = "工程师", in = ParameterIn.QUERY),
+ @Parameter(name = "posiCode", description = "职位编码(可选,模糊查询)", required = false, example = "ENG", in = ParameterIn.QUERY)
+ })
+ public Result getList(
+ @RequestParam(required = false) String posiName,
+ @RequestParam(required = false) String posiCode) {
+ List list = positionService.selectList( posiName, posiCode);
+ return Result.success(list);
+ }
+
+ @GetMapping(value = "/getById/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "查询单个职位", description = "根据职位ID查询详情")
+ public Result getPosiById(@PathVariable Long id) {
+ Position position = positionService.selectById(id);
+ return position != null ? Result.success(position) : Result.error("职位不存在");
+ }
+
+ @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "新增职位", description = "职位名称和编码为必填项")
+ public Result addPosi(@RequestBody Position position) {
+ try {
+ Long posiId = positionService.insert(position);
+ return Result.success(posiId);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @PutMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "修改职位", description = "需传入职位ID,其他字段可选(非空则更新)")
+ public Result updatePosi(@RequestBody Position position) {
+ try {
+ Boolean success = positionService.update(position);
+ return success ? Result.success(true) : Result.error("修改失败(职位不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping(value = "/del/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "删除职位", description = "逻辑删除(设置delSign=1)")
+ public Result deletePosi(@PathVariable Long id) {
+ try {
+ Boolean success = positionService.deleteById(id);
+ return success ? Result.success(true) : Result.error("删除失败(职位不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/RoleController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/RoleController.java
new file mode 100644
index 0000000..21873ca
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/RoleController.java
@@ -0,0 +1,145 @@
+package com.rczn.controller;
+
+import com.rczn.domain.PageBean;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.Role;
+import com.rczn.system.service.RoleService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 角色管理 CRUD API(MyBatis+PageHelper 实现)
+ */
+@RestController
+@RequestMapping("/role") // RESTful 规范:复数形式
+@Tag(name = "角色管理", description = "角色增删改查接口(支持分页+多条件查询+编码唯一性校验)")
+public class RoleController {
+
+ @Autowired
+ RoleService roleService;
+
+ /**
+ * 1. 分页查询角色(多条件模糊查询)
+ */
+ @GetMapping("/listPage")
+ @Operation(summary = "分页查询角色", description = "支持角色名、角色编码模糊查询,页码从1开始")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填,从1开始)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "roleName", description = "角色名(模糊查询,可选)", required = false, example = "管理员", in = ParameterIn.QUERY),
+ @Parameter(name = "roleCode", description = "角色编码(模糊查询,可选)", required = false, example = "ADMIN", in = ParameterIn.QUERY)
+ })
+ public Result> getRolePage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) String roleName,
+ @RequestParam(required = false) String roleCode) {
+
+ PageBean pageBean = roleService.selectRolePage(pageNum, pageSize, roleName, roleCode);
+ return Result.success(pageBean);
+ }
+
+ /**
+ * 1. 分页查询角色(多条件模糊查询)
+ */
+ @GetMapping("/list")
+ @Operation(summary = "查询角色列表", description = "支持角色名、角色编码模糊查询")
+ @Parameters({
+ @Parameter(name = "roleName", description = "角色名(模糊查询,可选)", required = false, example = "管理员", in = ParameterIn.QUERY),
+ @Parameter(name = "roleCode", description = "角色编码(模糊查询,可选)", required = false, example = "ADMIN", in = ParameterIn.QUERY)
+ })
+ public Result getRoleList(
+ @RequestParam(required = false) String roleName,
+ @RequestParam(required = false) String roleCode) {
+
+ List list = roleService.selectRoleList( roleName, roleCode);
+ return Result.success(list);
+ }
+
+ /**
+ * 2. 根据ID查询单个角色
+ */
+ @GetMapping("/getById/{id}")
+ @Operation(summary = "查询单个角色", description = "根据角色ID查询详情")
+ public Result getRoleById(
+ @Parameter(name = "id", description = "角色ID(必填)", required = true, example = "1", in = ParameterIn.PATH)
+ @PathVariable Long id) {
+
+ Role role = roleService.selectById(id);
+ if (role == null) {
+ return Result.error("角色ID:" + id + " 不存在");
+ }
+ return Result.success(role);
+ }
+
+ /**
+ * 3. 新增角色(校验编码唯一性)
+ */
+ @PostMapping("/add")
+ @Operation(summary = "新增角色", description = "提交角色信息,角色编码不可重复(ID无需传入)")
+ public Result addRole(
+ @Parameter(name = "role", description = "角色信息(ID无需传入,roleName和roleCode必填)", required = true)
+ @RequestBody Role role) {
+
+ try {
+ // 校验必填字段(也可通过JSR-380注解+@Valid实现)
+ if (role.getRoleName() == null || role.getRoleName().trim().isEmpty()) {
+ return Result.error("角色名不能为空");
+ }
+ if (role.getRoleCode() == null || role.getRoleCode().trim().isEmpty()) {
+ return Result.error("角色编码不能为空");
+ }
+
+ Long roleId = roleService.insert(role);
+ return Result.success(roleId);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 4. 修改角色(部分字段更新+编码唯一性校验)
+ */
+ @PutMapping("/update")
+ @Operation(summary = "修改角色", description = "传入角色ID和需要修改的字段,角色编码不可重复")
+ public Result updateRole(
+ @Parameter(name = "role", description = "角色信息(ID必填,roleName/roleCode可选但至少传一个)", required = true)
+ @RequestBody Role role) {
+
+ try {
+ // 校验必填字段
+ if (role.getId() == null) {
+ return Result.error("角色ID不能为空");
+ }
+ if ((role.getRoleName() == null || role.getRoleName().trim().isEmpty())
+ && (role.getRoleCode() == null || role.getRoleCode().trim().isEmpty())) {
+ return Result.error("至少需要修改角色名或角色编码");
+ }
+
+ Boolean success = roleService.update(role);
+ return success ? Result.success("修改角色成功") : Result.error("修改失败(角色不存在)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 5. 根据ID删除角色
+ */
+ @DeleteMapping("/del/{id}")
+ @Operation(summary = "删除角色", description = "根据角色ID删除角色")
+ public Result deleteRole(
+ @Parameter(name = "id", description = "角色ID(必填)", required = true, example = "1", in = ParameterIn.PATH)
+ @PathVariable Long id) {
+
+ Boolean success = roleService.deleteById(id);
+ return success ? Result.success("删除角色成功") : Result.error("删除失败(角色不存在)");
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/RolePermissionController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/RolePermissionController.java
new file mode 100644
index 0000000..3930764
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/RolePermissionController.java
@@ -0,0 +1,65 @@
+package com.rczn.controller;
+
+import com.rczn.domain.Result;
+import com.rczn.system.domain.RolePermission;
+import com.rczn.system.domain.query.RolePermissionQuery;
+import com.rczn.system.service.RolePermissionService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/rolePermission")
+@Tag(name = "角色权限管理", description = "角色权限关联接口")
+public class RolePermissionController {
+
+ @Autowired
+ RolePermissionService rolePermissionService;
+
+ @GetMapping("/listByRoleId/{roleId}")
+ @Operation(summary = "根据角色ID查询权限ID列表")
+ public Result getListByRoleId(
+ @Parameter(name = "roleId", required = true) @PathVariable Integer roleId) {
+ List list = rolePermissionService.selectListByRoleId(roleId);
+ return Result.success(list);
+ }
+
+ @PostMapping("/add")
+ @Operation(summary = "给角色添加权限")
+ public Result add(@RequestBody RolePermissionQuery rolePermission) {
+ if (rolePermission.getRoleId() == null || rolePermission.getPermissionId() == null) {
+ return Result.error("角色ID和权限ID不能为空");
+ }
+ try {
+ RolePermission rolePermissionEntity = new RolePermission();
+ rolePermissionEntity.setRoleId(rolePermission.getRoleId());
+ rolePermissionEntity.setPermissionId(rolePermission.getPermissionId());
+ rolePermissionService.insert(rolePermissionEntity);
+ return Result.success("添加成功");
+ } catch (Exception e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping("/del")
+ @Operation(summary = "删除角色权限关联")
+ public Result delete(
+ @RequestParam Integer roleId,
+ @RequestParam(required = false) Integer permissionId) {
+ boolean success = rolePermissionService.delete(roleId, permissionId);
+ return success ? Result.success("删除成功") : Result.error("删除失败");
+ }
+
+ @DeleteMapping("/clearByRoleId/{roleId}")
+ @Operation(summary = "清空某个角色的所有权限")
+ public Result clearByRoleId(
+ @Parameter(name = "roleId", required = true) @PathVariable Integer roleId) {
+ rolePermissionService.deleteByRoleId(roleId);
+ return Result.success("清空成功");
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysDicDataController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysDicDataController.java
new file mode 100644
index 0000000..da28134
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysDicDataController.java
@@ -0,0 +1,109 @@
+package com.rczn.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.SysDicData;
+import com.rczn.system.service.SysDicDataService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+
+@RestController
+@RequestMapping("/sysDicData")
+@Tag(name = "字典数据管理", description = "字典数据增删改查+分页查询+按类型查询接口")
+public class SysDicDataController {
+
+ @Autowired
+ private SysDicDataService sysDicDataService;
+
+ @GetMapping(value = "/listPage", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "分页查询字典数据", description = "支持字典类型ID、标签、值查询")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "dicId", description = "字典类型ID(可选)", required = false, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "dicLabel", description = "数据标签(可选,模糊查询)", required = false, example = "运行", in = ParameterIn.QUERY),
+ @Parameter(name = "dicValue", description = "数据值(可选,模糊查询)", required = false, example = "1", in = ParameterIn.QUERY)
+ })
+ public Result getDicDataPage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) Integer dicId,
+ @RequestParam(required = false) String dicLabel,
+ @RequestParam(required = false) String dicValue) {
+ PageInfo pageBean = sysDicDataService.selectPage(pageNum, pageSize, dicId, dicLabel, dicValue);
+ return Result.success(pageBean);
+ }
+
+ @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "查询字典数据", description = "支持字典类型ID、标签、值查询")
+ @Parameters({
+ @Parameter(name = "dicId", description = "字典类型ID(可选)", required = false, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "dicLabel", description = "数据标签(可选,模糊查询)", required = false, example = "运行", in = ParameterIn.QUERY),
+ @Parameter(name = "dicValue", description = "数据值(可选,模糊查询)", required = false, example = "1", in = ParameterIn.QUERY)
+ })
+ public Result getList(
+ @RequestParam(required = false) Integer dicId,
+ @RequestParam(required = false) String dicLabel,
+ @RequestParam(required = false) String dicValue) {
+ List list = sysDicDataService.selectList( dicId, dicLabel, dicValue);
+ return Result.success(list);
+ }
+
+ @GetMapping(value = "/getById/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "查询单个字典数据", description = "根据字典数据ID查询详情")
+ public Result getDicDataById(@PathVariable Long id) {
+ SysDicData sysDicData = sysDicDataService.selectById(id);
+ return sysDicData != null ? Result.success(sysDicData) : Result.error("字典数据不存在");
+ }
+
+ @GetMapping(value = "/listByDicId/{dicId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "按字典类型ID查询数据列表", description = "查询指定字典类型下的所有有效数据")
+ public Result getDicDataByDicId(@PathVariable Integer dicId) {
+ try {
+ List list = sysDicDataService.selectByDicId(dicId);
+ return Result.success(list);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "新增字典数据", description = "字典类型ID、数据标签为必填项")
+ public Result addDicData(@RequestBody SysDicData sysDicData) {
+ try {
+ Long dicDataId = sysDicDataService.insert(sysDicData);
+ return Result.success(dicDataId);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @PutMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "修改字典数据", description = "需传入字典数据ID,其他字段可选(非空则更新)")
+ public Result updateDicData(@RequestBody SysDicData sysDicData) {
+ try {
+ Boolean success = sysDicDataService.update(sysDicData);
+ return success ? Result.success(true) : Result.error("修改失败(字典数据不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping(value = "/del/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "删除字典数据", description = "逻辑删除(设置delSign=1,不物理删除数据)")
+ public Result deleteDicData(@PathVariable Long id) {
+ try {
+ Boolean success = sysDicDataService.deleteById(id);
+ return success ? Result.success(true) : Result.error("删除失败(字典数据不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysDicTypeController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysDicTypeController.java
new file mode 100644
index 0000000..36a814b
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysDicTypeController.java
@@ -0,0 +1,95 @@
+package com.rczn.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.SysDicType;
+import com.rczn.system.service.SysDicTypeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/sysDicType")
+@Tag(name = "字典类型管理", description = "字典类型增删改查+分页查询接口")
+public class SysDicTypeController {
+
+ @Autowired
+ private SysDicTypeService sysDicTypeService;
+
+ @GetMapping(value = "/listPage", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "分页查询字典类型", description = "支持字典名称、编码模糊查询")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "dicName", description = "字典名称(可选,模糊查询)", required = false, example = "设备状态", in = ParameterIn.QUERY),
+ @Parameter(name = "dicCode", description = "字典编码(可选,模糊查询)", required = false, example = "DEV_STATUS", in = ParameterIn.QUERY)
+ })
+ public Result getDicTypePage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) String dicName,
+ @RequestParam(required = false) String dicCode) {
+ PageInfo pageBean = sysDicTypeService.selectPage(pageNum, pageSize, dicName, dicCode);
+ return Result.success(pageBean);
+ }
+
+ @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "查询字典类型列表", description = "支持字典名称、编码模糊查询")
+ @Parameters({
+ @Parameter(name = "dicName", description = "字典名称(可选,模糊查询)", required = false, example = "设备状态", in = ParameterIn.QUERY),
+ @Parameter(name = "dicCode", description = "字典编码(可选,模糊查询)", required = false, example = "DEV_STATUS", in = ParameterIn.QUERY)
+ })
+ public Result getList(
+ @RequestParam(required = false) String dicName,
+ @RequestParam(required = false) String dicCode) {
+ List list = sysDicTypeService.selectList( dicName, dicCode);
+ return Result.success(list);
+ }
+
+ @GetMapping(value = "/getById/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "查询单个字典类型", description = "根据字典类型ID查询详情")
+ public Result getDicTypeById(@PathVariable Long id) {
+ SysDicType sysDicType = sysDicTypeService.selectById(id);
+ return sysDicType != null ? Result.success(sysDicType) : Result.error("字典类型不存在");
+ }
+
+ @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "新增字典类型", description = "字典名称为必填项")
+ public Result addDicType(@RequestBody SysDicType sysDicType) {
+ try {
+ Long dicTypeId = sysDicTypeService.insert(sysDicType);
+ return Result.success(dicTypeId);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @PutMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "修改字典类型", description = "需传入字典类型ID,其他字段可选(非空则更新)")
+ public Result updateDicType(@RequestBody SysDicType sysDicType) {
+ try {
+ Boolean success = sysDicTypeService.update(sysDicType);
+ return success ? Result.success(true) : Result.error("修改失败(字典类型不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping(value = "/del/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "删除字典类型", description = "逻辑删除(设置delSign=1,不物理删除数据)")
+ public Result deleteDicType(@PathVariable Long id) {
+ try {
+ Boolean success = sysDicTypeService.deleteById(id);
+ return success ? Result.success(true) : Result.error("删除失败(字典类型不存在或已删除)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysPermissionController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysPermissionController.java
new file mode 100644
index 0000000..4f7f2bb
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/SysPermissionController.java
@@ -0,0 +1,128 @@
+package com.rczn.controller;
+
+import com.rczn.domain.PageBean;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.Role;
+import com.rczn.system.service.SysPermissionService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 权限管理 API(MyBatis 树形结构实现)
+ */
+@RestController
+@RequestMapping("/permission")
+@Tag(name = "权限管理", description = "权限增删改查接口(树形结构)")
+public class SysPermissionController {
+
+ @Autowired
+ private SysPermissionService sysPermissionService;
+
+ /**
+ * 1. 分页查询权限(多条件模糊查询)
+ */
+ @GetMapping("/listPage")
+ @Operation(summary = "分页查询权限", description = "支持角色名、角色编码模糊查询,页码从1开始")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填,从1开始)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "parentId", description = "父级ID(可选)", required = false, example = "0", in = ParameterIn.QUERY),
+ @Parameter(name = "permissionName", description = "权限名称(模糊查询,可选)", required = false, example = "用户添加", in = ParameterIn.QUERY)
+ })
+ public Result> getRolePage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) Integer parentId,
+ @RequestParam(required = false) String permissionName) {
+
+ PageBean pageBean = sysPermissionService.selectRolePage(pageNum, pageSize, parentId,permissionName);
+ return Result.success(pageBean);
+ }
+
+ /**
+ * 1. 查询权限树形结构列表
+ */
+ @GetMapping("/list")
+ @Operation(summary = "查询权限树形列表", description = "返回权限树形结构(parentId为0或null为顶级)")
+ public Result> getPermissionList() {
+ List treeList = sysPermissionService.getPermissionList();
+ return Result.success(treeList);
+ }
+
+ /**
+ * 1. 查询权限树形结构列表
+ */
+// @GetMapping("/listByParentId/{parentId}")
+// @Operation(summary = "查询权限树形列表", description = "返回权限树形结构(parentId为0或null为顶级)")
+// public Result> getPermissionListByParentId(@PathVariable Integer parentId) {
+// List treeList = sysPermissionService.getPermissionListByParentId(parentId);
+// return Result.success(treeList);
+// }
+
+ /**
+ * 2. 根据ID查询单个权限
+ */
+ @GetMapping("/getById/{id}")
+ @Operation(summary = "查询单个权限", description = "根据权限ID查询详情")
+ public Result getPermissionById(
+ @Parameter(name = "id", description = "权限ID", required = true, example = "1", in = ParameterIn.PATH)
+ @PathVariable Integer id) {
+
+ Permission permission = sysPermissionService.getPermissionById(id);
+ if (permission == null) {
+ return Result.error("权限ID:" + id + " 不存在");
+ }
+ return Result.success(permission);
+ }
+
+ /**
+ * 3. 新增权限
+ */
+ @PostMapping("/add")
+ @Operation(summary = "新增权限", description = "提交权限信息创建新权限")
+ public Result addPermission(
+ @Parameter(name = "permission", description = "权限信息", required = true)
+ @RequestBody Permission permission) {
+
+ boolean success = sysPermissionService.addPermission(permission);
+ return success ? Result.success("新增权限成功") : Result.error("新增失败");
+ }
+
+ /**
+ * 4. 修改权限
+ */
+ @PutMapping("/update")
+ @Operation(summary = "修改权限", description = "传入权限ID和需要修改的字段")
+ public Result updatePermission(
+ @Parameter(name = "permission", description = "权限信息(必须包含ID)", required = true)
+ @RequestBody Permission permission) {
+
+ try {
+ boolean success = sysPermissionService.updatePermission(permission);
+ return success ? Result.success("修改权限成功") : Result.error("修改失败(权限不存在)");
+ } catch (Exception e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 5. 根据ID删除权限(逻辑删除)
+ */
+ @DeleteMapping("/del/{id}")
+ @Operation(summary = "删除权限", description = "根据权限ID逻辑删除")
+ public Result deletePermission(
+ @Parameter(name = "id", description = "权限ID", required = true, example = "1", in = ParameterIn.PATH)
+ @PathVariable Integer id) {
+
+ boolean success = sysPermissionService.deletePermission(id);
+ return success ? Result.success("删除权限成功") : Result.error("删除失败(权限不存在)");
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/UserController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/UserController.java
new file mode 100644
index 0000000..126a663
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/UserController.java
@@ -0,0 +1,239 @@
+package com.rczn.controller;
+
+import com.fasterxml.jackson.databind.annotation.JsonAppend;
+import com.rczn.domain.PageBean;
+import com.rczn.domain.Result;
+import com.rczn.rcznautoplc.domain.ManageLog;
+import com.rczn.rcznautoplc.domain.RecordInfo;
+import com.rczn.rcznautoplc.service.ManageLogService;
+import com.rczn.rcznautoplc.service.RecordInfoService;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.User;
+import com.rczn.system.service.UserService;
+import com.rczn.utils.JwtUtil;
+import com.rczn.utils.Md5Util;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.constraints.Pattern;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 用户管理 CRUD API(MyBatis+PageHelper 实现)
+ */
+@RestController
+@RequestMapping("/user") // RESTful 规范:复数形式+api前缀
+@Tag(name = "用户管理", description = "用户增删改查接口(支持分页+模糊查询)")
+public class UserController {
+
+ // 注入 Service 层(构造器注入,推荐)
+ @Autowired
+ UserService userService;
+
+ /**
+ * 1. 分页查询用户(支持用户名模糊查询)
+ */
+ @GetMapping("/listPage")
+ @Operation(summary = "分页查询用户", description = "支持分页、用户名模糊查询,页码从1开始")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(从1开始)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "userName", description = "用户名(模糊查询,可选)", required = false, example = "张三", in = ParameterIn.QUERY)
+ })
+ public Result> getUserPage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) String userName) {
+
+ // 调用 Service 分页查询
+ PageBean pageBean = userService.selectUserPage(pageNum, pageSize, userName);
+ return Result.success(pageBean);
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "查询用户列表", description = "用户名模糊查询,查询全部")
+ @Parameters({
+ @Parameter(name = "userName", description = "用户名(模糊查询,可选)", required = false, example = "张三", in = ParameterIn.QUERY)
+ })
+ public Result> getUserList(
+ @RequestParam(required = false) String userName) {
+
+ // 调用 Service 查询列表
+ List userList = userService.selectUserList(userName);
+ return Result.success(userList);
+ }
+
+ /**
+ * 2. 根据ID查询单个用户
+ */
+ @GetMapping("/getById/{id}")
+ @Operation(summary = "查询单个用户", description = "根据用户ID查询详情")
+ public Result getUserById(
+ @Parameter(name = "id", description = "用户ID", required = true, example = "1", in = ParameterIn.PATH)
+ @PathVariable Long id) {
+
+ User user = userService.selectById(id);
+ if (user == null) {
+ return Result.error("用户ID:" + id + " 不存在");
+ }
+ return Result.success(user);
+ }
+
+ /**
+ * 3. 新增用户
+ */
+ @PostMapping("/add")
+ @Operation(summary = "新增用户", description = "提交用户完整信息创建新用户(ID无需传入)")
+ public Result addUser(
+ @Parameter(name = "user", description = "用户信息(ID无需传入)", required = true)
+ @RequestBody User user) {
+
+ Long userId = userService.insert(user);
+ return Result.success("新增用户成功");
+ }
+
+ /**
+ * 4. 修改用户(支持部分字段更新)
+ */
+ @PutMapping("/update")
+ @Operation(summary = "修改用户", description = "传入用户ID和需要修改的字段(非空字段才会更新)")
+ public Result updateUser(
+ @Parameter(name = "user", description = "用户信息(必须包含ID)", required = true)
+ @RequestBody User user) {
+
+ try {
+ Boolean success = userService.update(user);
+ return success ? Result.success("修改用户成功") : Result.error("修改失败(用户不存在或无字段更新)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 5. 根据ID删除用户
+ */
+ @DeleteMapping("/del/{id}")
+ @Operation(summary = "删除用户", description = "根据用户ID删除用户")
+ public Result deleteUser(
+ @Parameter(name = "id", description = "用户ID", required = true, example = "1", in = ParameterIn.PATH)
+ @PathVariable Long id) {
+
+ Boolean success = userService.deleteById(id);
+ return success ? Result.success("删除用户成功") : Result.error("删除失败(用户不存在)");
+ }
+
+
+ @PostMapping("/register")
+ @Operation(summary = "注册", description = "用户名必须是2-16位的字母、数字、下划线或减号")
+ public Result register(@Pattern(regexp = "^[a-zA-Z0-9_-]{2,16}$", message = "用户名必须是2-16位的字母、数字、下划线或减号")
+ @Parameter(
+ name = "username",
+ description = "用户名"
+ )
+ @RequestParam
+ String username,
+ @Parameter(
+ name = "password",
+ description = "密码..."
+ )
+ @RequestParam
+ String password) {
+ //查询数据库是否有该用户
+ User user = userService.findeUserByUsername(username);
+ //注册
+ if (user == null) {
+ //如果用户不存在,则注册
+ int result = userService.register(username, password);
+ return Result.success("用户注册成功");
+ } else {
+ //用户存在,返回错误信息
+ return Result.error("该用户名已存在!");
+ }
+ }
+
+ @GetMapping("/getUserByUsername")
+ public Result getUserByUsername(String username) {
+ User user = userService.findeUserByUsername(username);
+ if (user == null) {
+ return Result.error("该用户不存在!");
+ } else {
+ return Result.success(user);
+ }
+ }
+
+ @Autowired
+ ManageLogService manageLogService;
+
+ @PostMapping("/login")
+ @Operation(summary = "用户登录接口",description = "根据用户名和密码登录,返回JWT Token")
+ public Result login(
+ @Parameter(
+ name = "username",
+ description = "登录用户名(2-16位的字母、数字、下划线或减号)",
+ required = true, // 标记为必填参数
+ example = "string"
+ )
+ @RequestParam
+ String username,
+ @Parameter(
+ name = "password",
+ description = "登录密码",
+ required = true
+ )
+ @RequestParam
+ String password) {
+
+ //TODO 登录逻辑
+ //查询数据库是否有该用户
+ User user = userService.findeUserByUsername(username);
+ //登录
+ if (user == null) {
+ //如果用户不存在,返回错误信息
+ return Result.error("该用户不存在!");
+ } else {
+ //校验密码:
+ String encryptPassword = user.getPassword();
+ if (encryptPassword.equals(password)) {
+ //登录成功,增加登录日志:
+ LocalDateTime loginTime = LocalDateTime.now();
+ ManageLog info = new ManageLog();
+ info.setCreateId(user.getId());
+ info.setLogName("登录日志");
+ info.setLogType("登录日志");//1:登录日志、2:SOP操作日志、3:基础数据操作日志
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("用户名:").append(user.getUserName()).append(",登录操作时间:").append(loginTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+ info.setLogContent(stringBuilder.toString());
+ info.setCreateTime(loginTime);
+ manageLogService.insert(info);
+
+// if (Md5Util.checkPassword(password, encryptPassword)) {
+ //生产token
+ Map claims = new HashMap<>();
+ claims.put("id", user.getId());
+ claims.put("username", user.getUserName());
+ //获取权限列表:
+ List permissions = userService.findUserPermissions(user.getId());
+ List permissionList = permissions.stream().map(Permission::getPermissionCode).collect(Collectors.toList());
+ claims.put("permissions", permissionList);
+ String jwtToken = JwtUtil.genToken(claims);
+ //密码正确,返回成功信息
+ return Result.success(jwtToken);
+ } else {
+ //密码错误,返回错误信息
+ return Result.error("密码错误!");
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/UserRoleController.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/UserRoleController.java
new file mode 100644
index 0000000..dab6e94
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/controller/UserRoleController.java
@@ -0,0 +1,100 @@
+package com.rczn.controller;
+
+import com.rczn.domain.PageBean;
+import com.rczn.domain.Result;
+import com.rczn.system.domain.UserRole;
+import com.rczn.system.service.UserRoleService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/user-role")
+@Tag(name = "用户角色关联管理", description = "用户与角色的关联增删改查接口")
+public class UserRoleController {
+
+ @Autowired
+ private UserRoleService userRoleService;
+
+ @GetMapping(value = "/listPage", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "分页查询关联", description = "支持用户ID、角色ID精准查询")
+ @Parameters({
+ @Parameter(name = "pageNum", description = "页码(必填)", required = true, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "pageSize", description = "每页条数(必填)", required = true, example = "10", in = ParameterIn.QUERY),
+ @Parameter(name = "userId", description = "用户ID(可选)", required = false, example = "1", in = ParameterIn.QUERY),
+ @Parameter(name = "roleId", description = "角色ID(可选)", required = false, example = "2", in = ParameterIn.QUERY)
+ })
+ public Result> getUserRolePage(
+ @RequestParam Integer pageNum,
+ @RequestParam Integer pageSize,
+ @RequestParam(required = false) Integer userId,
+ @RequestParam(required = false) Integer roleId) {
+ PageBean pageBean = userRoleService.selectPage(pageNum, pageSize, userId, roleId);
+ return Result.success(pageBean);
+ }
+
+ @GetMapping(value = "/user/{userId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "根据用户ID查询关联角色", description = "查询指定用户的所有关联角色")
+ public Result> getByUserId(@PathVariable Integer userId) {
+ List userRoles = userRoleService.selectByUserId(userId);
+ return Result.success(userRoles);
+ }
+
+ @GetMapping(value = "/role/{roleId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "根据角色ID查询关联用户", description = "查询指定角色的所有关联用户")
+ public Result> getByRoleId(@PathVariable Integer roleId) {
+ List userRoles = userRoleService.selectByRoleId(roleId);
+ return Result.success(userRoles);
+ }
+
+ @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "新增用户角色关联", description = "用户ID和角色ID为必填项")
+ public Result addUserRole(@RequestBody UserRole userRole) {
+ try {
+ Long id = userRoleService.insert(userRole);
+ return Result.success(id);
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping(value = "/del/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "根据关联ID删除", description = "删除单个用户-角色关联")
+ public Result deleteById(@PathVariable Long id) {
+ try {
+ Boolean success = userRoleService.deleteById(id);
+ return success ? Result.success(true) : Result.error("删除失败(关联不存在)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping(value = "/user/{userId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "根据用户ID删除所有关联", description = "删除指定用户的所有角色关联")
+ public Result deleteByUserId(@PathVariable Integer userId) {
+ try {
+ Boolean success = userRoleService.deleteByUserId(userId);
+ return success ? Result.success(true) : Result.error("删除失败(无关联数据)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+
+ @DeleteMapping(value = "/role/{roleId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "根据角色ID删除所有关联", description = "删除指定角色的所有用户关联")
+ public Result deleteByRoleId(@PathVariable Integer roleId) {
+ try {
+ Boolean success = userRoleService.deleteByRoleId(roleId);
+ return success ? Result.success(true) : Result.error("删除失败(无关联数据)");
+ } catch (IllegalArgumentException e) {
+ return Result.error(e.getMessage());
+ }
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Department.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Department.java
new file mode 100644
index 0000000..342af1d
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Department.java
@@ -0,0 +1,88 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+
+public class Department extends BaseBean {
+ private String deptName;
+
+ private String deptCode;
+
+ private Integer parentId;
+
+ private Integer leaderId;
+
+ private User leader;
+ // 新增:子部门列表(核心字段,用于存储树形结构)
+ private List children;
+
+ public Department() {
+ }
+
+ public Department(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ }
+
+ public String getDeptName() {
+ return deptName;
+ }
+
+ public void setDeptName(String deptName) {
+ this.deptName = deptName;
+ }
+
+ public String getDeptCode() {
+ return deptCode;
+ }
+
+ public void setDeptCode(String deptCode) {
+ this.deptCode = deptCode;
+ }
+
+ public Integer getParentId() {
+ return parentId;
+ }
+
+ public void setParentId(Integer parentId) {
+ this.parentId = parentId;
+ }
+
+ public Integer getLeaderId() {
+ return leaderId;
+ }
+
+ public void setLeaderId(Integer leaderId) {
+ this.leaderId = leaderId;
+ }
+
+ public User getLeader() {
+ return leader;
+ }
+
+ public void setLeader(User leader) {
+ this.leader = leader;
+ }
+
+ public List getChildren() {
+ return children;
+ }
+
+ public void setChildren(List children) {
+ this.children = children;
+ }
+
+ @Override
+ public String toString() {
+ return "Department{" +
+ "deptName='" + deptName + '\'' +
+ ", deptCode='" + deptCode + '\'' +
+ ", parentId=" + parentId +
+ ", leaderId=" + leaderId +
+ ", leader=" + leader +
+ ", children=" + children +
+ '}';
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Permission.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Permission.java
new file mode 100644
index 0000000..dfc2554
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Permission.java
@@ -0,0 +1,31 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+
+import java.util.List;
+
+public class Permission extends BaseBean{
+
+ private Integer parentId;
+ private String permissionName;
+ private String permissionCode;
+
+ // 树形结构子节点 ✅
+ private List children;
+
+ // getter & setter
+ public Integer getParentId() { return parentId; }
+ public void setParentId(Integer parentId) { this.parentId = parentId; }
+ public String getPermissionName() { return permissionName; }
+ public void setPermissionName(String permissionName) { this.permissionName = permissionName; }
+ public String getPermissionCode() { return permissionCode; }
+ public void setPermissionCode(String permissionCode) { this.permissionCode = permissionCode; }
+
+ // children
+ public List getChildren() {
+ return children;
+ }
+ public void setChildren(List children) {
+ this.children = children;
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Position.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Position.java
new file mode 100644
index 0000000..50fd71d
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Position.java
@@ -0,0 +1,42 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+
+import java.time.LocalDateTime;
+
+public class Position extends BaseBean {
+ private String posiName;
+
+ private String posiCode;
+
+ public Position() {
+ }
+
+ public Position(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ }
+
+ @Override
+ public String toString() {
+ return "Position{" +
+ "posiName='" + posiName + '\'' +
+ ", posiCode='" + posiCode + '\'' +
+ '}';
+ }
+
+ public String getPosiName() {
+ return posiName;
+ }
+
+ public void setPosiName(String posiName) {
+ this.posiName = posiName;
+ }
+
+ public String getPosiCode() {
+ return posiCode;
+ }
+
+ public void setPosiCode(String posiCode) {
+ this.posiCode = posiCode;
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Role.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Role.java
new file mode 100644
index 0000000..ced36aa
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/Role.java
@@ -0,0 +1,27 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+import java.time.LocalDateTime;
+
+public class Role extends BaseBean {
+ private String roleName;
+ private String roleCode;
+
+ // 全参构造器同步修改 delSign 类型(Boolean → boolean)
+ public Role(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark, String roleName, String roleCode) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark); // 父类参数类型同步
+ this.roleName = roleName;
+ this.roleCode = roleCode;
+ }
+
+ // 其他构造器、getter/setter 保持不变
+ public Role() { }
+ public Role(String roleName, String roleCode) {
+ this.roleName = roleName;
+ this.roleCode = roleCode;
+ }
+ public String getRoleName() { return roleName; }
+ public void setRoleName(String roleName) { this.roleName = roleName; }
+ public String getRoleCode() { return roleCode; }
+ public void setRoleCode(String roleCode) { this.roleCode = roleCode; }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/RolePermission.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/RolePermission.java
new file mode 100644
index 0000000..7e55f16
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/RolePermission.java
@@ -0,0 +1,56 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+
+import java.time.LocalDateTime;
+
+public class RolePermission extends BaseBean {
+
+ private Integer roleId;
+
+ private Integer permissionId;
+
+ private Role role;
+
+ private Permission permission;
+
+ public RolePermission() {
+ }
+
+ public RolePermission(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ }
+
+
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+
+ public Integer getPermissionId() {
+ return permissionId;
+ }
+
+ public void setPermissionId(Integer permissionId) {
+ this.permissionId = permissionId;
+ }
+
+ public Role getRole() {
+ return role;
+ }
+
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
+ public Permission getPermission() {
+ return permission;
+ }
+
+ public void setPermission(Permission permission) {
+ this.permission = permission;
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/SysDicData.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/SysDicData.java
new file mode 100644
index 0000000..a64751c
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/SysDicData.java
@@ -0,0 +1,52 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+import java.time.LocalDateTime;
+
+/**
+ * 字典数据实体类
+ * 对应表:sys_dic_data
+ */
+public class SysDicData extends BaseBean {
+
+ // 字典类型id(外键)
+ private Integer dicId;
+
+ // 数据标签
+ private String dicLabel;
+
+ // 数据字典值
+ private String dicValue;
+
+ public SysDicData() {
+ }
+
+ public SysDicData(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ }
+
+ // getter/setter
+ public Integer getDicId() {
+ return dicId;
+ }
+
+ public void setDicId(Integer dicId) {
+ this.dicId = dicId;
+ }
+
+ public String getDicLabel() {
+ return dicLabel;
+ }
+
+ public void setDicLabel(String dicLabel) {
+ this.dicLabel = dicLabel;
+ }
+
+ public String getDicValue() {
+ return dicValue;
+ }
+
+ public void setDicValue(String dicValue) {
+ this.dicValue = dicValue;
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/SysDicType.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/SysDicType.java
new file mode 100644
index 0000000..827bdce
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/SysDicType.java
@@ -0,0 +1,41 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+import java.time.LocalDateTime;
+
+/**
+ * 字典类型实体类
+ * 对应表:sys_dic_type
+ */
+public class SysDicType extends BaseBean {
+
+ // 字典名称(必填)
+ private String dicName;
+
+ // 字典编码
+ private String dicCode;
+
+ public SysDicType() {
+ }
+
+ public SysDicType(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ }
+
+ // getter/setter
+ public String getDicName() {
+ return dicName;
+ }
+
+ public void setDicName(String dicName) {
+ this.dicName = dicName;
+ }
+
+ public String getDicCode() {
+ return dicCode;
+ }
+
+ public void setDicCode(String dicCode) {
+ this.dicCode = dicCode;
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/User.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/User.java
new file mode 100644
index 0000000..2af76cf
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/User.java
@@ -0,0 +1,152 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+
+import java.time.LocalDateTime;
+
+public class User extends BaseBean {
+ private String userName;
+
+ private String password;
+
+ private String salt;
+
+ private String nicke;
+
+ private Boolean sex; // 0-女, 1-男
+
+ private String emailAddr;
+
+ private String address;
+
+ private String telephone;
+
+ private Integer depId;
+
+ private Integer posId;
+
+ private Department department;
+
+ private Position position;
+
+ public User() {
+ }
+
+ public User(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "userName='" + userName + '\'' +
+ ", password='" + password + '\'' +
+ ", salt='" + salt + '\'' +
+ ", nicke='" + nicke + '\'' +
+ ", sex=" + sex +
+ ", emailAddr='" + emailAddr + '\'' +
+ ", address='" + address + '\'' +
+ ", telephone='" + telephone + '\'' +
+ ", depId=" + depId +
+ ", posId=" + posId +
+ ", department=" + department +
+ ", position=" + position +
+ '}';
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getSalt() {
+ return salt;
+ }
+
+ public void setSalt(String salt) {
+ this.salt = salt;
+ }
+
+ public String getNicke() {
+ return nicke;
+ }
+
+ public void setNicke(String nicke) {
+ this.nicke = nicke;
+ }
+
+ public Boolean getSex() {
+ return sex;
+ }
+
+ public void setSex(Boolean sex) {
+ this.sex = sex;
+ }
+
+ public String getEmailAddr() {
+ return emailAddr;
+ }
+
+ public void setEmailAddr(String emailAddr) {
+ this.emailAddr = emailAddr;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getTelephone() {
+ return telephone;
+ }
+
+ public void setTelephone(String telephone) {
+ this.telephone = telephone;
+ }
+
+ public Integer getDepId() {
+ return depId;
+ }
+
+ public void setDepId(Integer depId) {
+ this.depId = depId;
+ }
+
+ public Integer getPosId() {
+ return posId;
+ }
+
+ public void setPosId(Integer posId) {
+ this.posId = posId;
+ }
+
+ public Department getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(Department department) {
+ this.department = department;
+ }
+
+ public Position getPosition() {
+ return position;
+ }
+
+ public void setPosition(Position position) {
+ this.position = position;
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/UserRole.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/UserRole.java
new file mode 100644
index 0000000..4163de1
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/UserRole.java
@@ -0,0 +1,89 @@
+package com.rczn.system.domain;
+
+import com.rczn.domain.BaseBean;
+
+import java.time.LocalDateTime;
+
+public class UserRole extends BaseBean {
+ private Long id;
+
+ private Integer userId;
+
+ private Integer roleId;
+
+ private User user;
+
+ private Role role;
+
+ @Override
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Integer getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Integer userId) {
+ this.userId = userId;
+ }
+
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ public Role getRole() {
+ return role;
+ }
+
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
+ public UserRole() {
+ }
+
+ public UserRole(Long id, Integer userId, Integer roleId, User user, Role role) {
+ this.id = id;
+ this.userId = userId;
+ this.roleId = roleId;
+ this.user = user;
+ this.role = role;
+ }
+
+ public UserRole(Long id, Long createId, LocalDateTime createTime, Long updateId, LocalDateTime updateTime, boolean delSign, String remark, Long id1, Integer userId, Integer roleId, User user, Role role) {
+ super(id, createId, createTime, updateId, updateTime, delSign, remark);
+ this.id = id1;
+ this.userId = userId;
+ this.roleId = roleId;
+ this.user = user;
+ this.role = role;
+ }
+
+ @Override
+ public String toString() {
+ return "UserRole{" +
+ "id=" + id +
+ ", userId=" + userId +
+ ", roleId=" + roleId +
+ ", user=" + user +
+ ", role=" + role +
+ '}';
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/UserTest.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/UserTest.java
new file mode 100644
index 0000000..55a85f3
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/UserTest.java
@@ -0,0 +1,27 @@
+package com.rczn.system.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+/**
+ * 用户实体类
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+@Schema(description = "用户实体类") // 替代@ApiModel
+public class UserTest {
+
+ @Schema(description = "用户ID", example = "1001") // 替代@ApiModelProperty
+ private Long id;
+
+ @Schema(description = "用户名", required = true, example = "张三")
+ private String name;
+
+ @Schema(description = "年龄", example = "25")
+ private Integer age;
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/query/RolePermissionQuery.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/query/RolePermissionQuery.java
new file mode 100644
index 0000000..f17fa3a
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/domain/query/RolePermissionQuery.java
@@ -0,0 +1,34 @@
+package com.rczn.system.domain.query;
+
+public class RolePermissionQuery {
+
+ //角色id
+ private Integer roleId;
+
+ //权限id
+ private Integer permissionId;
+
+ public RolePermissionQuery(Integer roleId, Integer permissionId) {
+ this.roleId = roleId;
+ this.permissionId = permissionId;
+ }
+
+ public RolePermissionQuery() {
+ }
+
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+
+ public Integer getPermissionId() {
+ return permissionId;
+ }
+
+ public void setPermissionId(Integer permissionId) {
+ this.permissionId = permissionId;
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/DepartmentMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/DepartmentMapper.java
new file mode 100644
index 0000000..23cbd68
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/DepartmentMapper.java
@@ -0,0 +1,44 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.Department;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+@Mapper
+public interface DepartmentMapper {
+ // 新增部门
+ int insert(Department department);
+
+ // 根据ID删除部门(逻辑删除:更新delSign=1)
+ int deleteById(Long id);
+
+ // 根据ID更新部门
+ int updateById(Department department);
+
+ // 根据ID查询部门
+ Department selectById(Long id);
+
+ // 分页查询部门(支持模糊查询)
+ List selectPage(
+ @Param("deptName") String deptName,
+ @Param("deptCode") String deptCode,
+ @Param("parentId") Integer parentId
+ );
+
+ // 查询分页总数(配合分页查询)
+ int selectTotal(
+ @Param("deptName") String deptName,
+ @Param("deptCode") String deptCode,
+ @Param("parentId") Integer parentId
+ );
+
+ // 新增:查询所有未删除的部门(用于递归组装树)
+ List selectAllDept();
+
+ // 新增:按父部门ID查询子部门(用于递归查询)
+ List selectChildrenByParentId(@Param("parentId") Integer parentId);
+
+ // 新增:查询顶级部门(parent_id IS NULL)
+ List selectTopDept();
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/PositionMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/PositionMapper.java
new file mode 100644
index 0000000..43b33e2
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/PositionMapper.java
@@ -0,0 +1,26 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.Position;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+@Mapper
+public interface PositionMapper {
+ int insert(Position position);
+ int deleteById(Long id);
+ int updateById(Position position);
+ Position selectById(Long id);
+ List selectPage(
+ @Param("posiName") String posiName,
+ @Param("posiCode") String posiCode
+ );
+ int selectTotal(
+ @Param("posiName") String posiName,
+ @Param("posiCode") String posiCode
+ );
+ List selectList(
+ @Param("posiName") String posiName,
+ @Param("posiCode") String posiCode
+ );
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/RoleMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/RoleMapper.java
new file mode 100644
index 0000000..eac1efd
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/RoleMapper.java
@@ -0,0 +1,55 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.Role;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Role MyBatis Mapper 接口
+ */
+@Mapper
+public interface RoleMapper {
+
+ /**
+ * 分页查询角色(支持角色名/角色编码模糊查询)
+ */
+ List selectRolePage(
+ @Param("roleName") String roleName,
+ @Param("roleCode") String roleCode);
+
+ /**
+ * 根据ID查询单个角色
+ */
+ Role selectById(@Param("id") Long id);
+
+ /**
+ * 新增角色
+ */
+ int insert(Role role);
+
+ /**
+ * 修改角色(部分字段更新)
+ */
+ int update(Role role);
+
+ /**
+ * 根据ID删除角色
+ */
+ int deleteById(@Param("id") Long id);
+
+ /**
+ * 查询总条数(支持模糊查询条件)
+ */
+ Long selectTotal(
+ @Param("roleName") String roleName,
+ @Param("roleCode") String roleCode);
+
+ /**
+ * 校验角色编码唯一性(新增/修改时使用)
+ */
+ Integer checkRoleCodeUnique(
+ @Param("roleCode") String roleCode,
+ @Param("id") Long id);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/RolePermissionMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/RolePermissionMapper.java
new file mode 100644
index 0000000..93f27f9
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/RolePermissionMapper.java
@@ -0,0 +1,18 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.RolePermission;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+@Mapper
+public interface RolePermissionMapper {
+
+ List selectListByRoleId(@Param("roleId") Integer roleId);
+
+ int insert(RolePermission rolePermission);
+
+ int delete(@Param("roleId") Integer roleId, @Param("permissionId") Integer permissionId);
+
+ int deleteByRoleId(@Param("roleId") Integer roleId);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysDicDataMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysDicDataMapper.java
new file mode 100644
index 0000000..52cea18
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysDicDataMapper.java
@@ -0,0 +1,39 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.SysDicData;
+import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
+@Mapper
+public interface SysDicDataMapper {
+
+ /**
+ * 新增字典数据
+ */
+ int insert(SysDicData sysDicData);
+
+ /**
+ * 修改字典数据
+ */
+ int update(SysDicData sysDicData);
+
+ /**
+ * 逻辑删除字典数据
+ */
+ int deleteById(Long id);
+
+ /**
+ * 根据ID查询字典数据
+ */
+ SysDicData selectById(Long id);
+
+ /**
+ * 分页查询字典数据(参数可选)
+ */
+ List selectPage(SysDicData sysDicData);
+
+ /**
+ * 根据字典类型ID查询字典数据列表
+ */
+ List selectByDicId(Integer dicId);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysDicTypeMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysDicTypeMapper.java
new file mode 100644
index 0000000..ec25b7a
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysDicTypeMapper.java
@@ -0,0 +1,34 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.SysDicType;
+import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
+@Mapper
+public interface SysDicTypeMapper {
+
+ /**
+ * 新增字典类型
+ */
+ int insert(SysDicType sysDicType);
+
+ /**
+ * 修改字典类型
+ */
+ int update(SysDicType sysDicType);
+
+ /**
+ * 逻辑删除字典类型
+ */
+ int deleteById(Long id);
+
+ /**
+ * 根据ID查询字典类型
+ */
+ SysDicType selectById(Long id);
+
+ /**
+ * 分页查询字典类型(参数可选)
+ */
+ List selectPage(SysDicType sysDicType);
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysPermissionMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysPermissionMapper.java
new file mode 100644
index 0000000..4b67f65
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/SysPermissionMapper.java
@@ -0,0 +1,52 @@
+package com.rczn.system.mapper;
+
+
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.Role;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface SysPermissionMapper {
+
+ /**
+ * 分页查询角色(支持角色名/角色编码模糊查询)
+ */
+ List selectPermissionPage(
+ @Param("parentId") Integer parentId,
+ @Param("permissionName") String permissionName);
+
+ /**
+ * 查询总条数(支持模糊查询条件)
+ */
+ Long selectTotal(
+ @Param("parentId") Integer parentId,
+ @Param("permissionName") String permissionName);
+
+ /**
+ * 查询所有权限(未删除)
+ */
+ List selectPermissionList();
+
+ /**
+ * 根据ID查询
+ */
+ Permission selectPermissionById(Integer id);
+
+ /**
+ * 新增
+ */
+ int insertPermission(Permission permission);
+
+ /**
+ * 修改
+ */
+ int updatePermission(Permission permission);
+
+ /**
+ * 逻辑删除
+ */
+ int deletePermissionById(Integer id);
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/UserMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/UserMapper.java
new file mode 100644
index 0000000..bd19442
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/UserMapper.java
@@ -0,0 +1,43 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.User;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+@Mapper
+public interface UserMapper {
+ // 分页查询(参数支持空值,为空时忽略该条件)
+ List selectUserPage(User user);
+
+ // 根据ID查询(支持传delSign筛选状态)
+ User selectById(@Param("id") Long id, @Param("delSign") Boolean delSign);
+
+ // 新增用户(空参数会插入默认值或null)
+ int insert(User user);
+
+ // 修改用户(仅更新非空字段)
+ int update(User user);
+
+ // 逻辑删除用户
+ int deleteById(@Param("id") Long id, @Param("updateId") Long updateId);
+
+ // 查询总条数(与分页查询参数一致)
+ Long selectTotal(
+ @Param("userName") String userName,
+ @Param("depId") Integer depId,
+ @Param("posId") Integer posId,
+ @Param("createId") Long createId,
+ @Param("sex") Integer sex,
+ @Param("delSign") Boolean delSign
+ );
+
+ @Select("SELECT * FROM sys_user WHERE user_name = #{userName}")
+ User selectByUsername(String userName);
+
+ //根据用户id,查询出对应的权限列表
+ List findUserPermissions(Long userId);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/UserRoleMapper.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/UserRoleMapper.java
new file mode 100644
index 0000000..5d3ae10
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/mapper/UserRoleMapper.java
@@ -0,0 +1,42 @@
+package com.rczn.system.mapper;
+
+import com.rczn.system.domain.UserRole;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+@Mapper
+public interface UserRoleMapper {
+ // 新增用户-角色关联
+ int insert(UserRole userRole);
+
+ // 根据ID删除关联
+ int deleteById(Long id);
+
+ // 根据用户ID删除所有关联
+ int deleteByUserId(Integer userId);
+
+ // 根据角色ID删除所有关联
+ int deleteByRoleId(Integer roleId);
+
+ // 根据ID查询关联
+ UserRole selectById(Long id);
+
+ // 根据用户ID查询关联的角色列表
+ List selectByUserId(Integer userId);
+
+ // 根据角色ID查询关联的用户列表
+ List selectByRoleId(Integer roleId);
+
+ // 分页查询所有关联
+ List selectPage(
+ @Param("userId") Integer userId,
+ @Param("roleId") Integer roleId
+ );
+
+ // 查询分页总数
+ int selectTotal(
+ @Param("userId") Integer userId,
+ @Param("roleId") Integer roleId
+ );
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/DepartmentService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/DepartmentService.java
new file mode 100644
index 0000000..a39f648
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/DepartmentService.java
@@ -0,0 +1,35 @@
+package com.rczn.system.service;
+
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Department;
+
+import java.util.List;
+
+public interface DepartmentService {
+ // 新增部门
+ Long insert(Department department);
+
+ // 根据ID删除部门
+ Boolean deleteById(Long id);
+
+ // 根据ID更新部门
+ Boolean update(Department department);
+
+ // 根据ID查询部门
+ Department selectById(Long id);
+
+ // 分页查询部门
+ PageBean selectPage(
+ Integer pageNum,
+ Integer pageSize,
+ String deptName,
+ String deptCode,
+ Integer parentId
+ );
+
+ // 新增:获取完整部门树(递归组装)
+ List getDeptTree();
+
+ // 新增:获取简化版部门树(仅包含ID、名称、子部门,用于下拉选择)
+ List getSimpleDeptTree();
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/PositionService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/PositionService.java
new file mode 100644
index 0000000..5c8af40
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/PositionService.java
@@ -0,0 +1,15 @@
+package com.rczn.system.service;
+
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Position;
+
+import java.util.List;
+
+public interface PositionService {
+ Long insert(Position position);
+ Boolean deleteById(Long id);
+ Boolean update(Position position);
+ Position selectById(Long id);
+ PageBean selectPage(Integer pageNum, Integer pageSize, String posiName, String posiCode);
+ List selectList(String posiName, String posiCode);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/RolePermissionService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/RolePermissionService.java
new file mode 100644
index 0000000..6c175d6
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/RolePermissionService.java
@@ -0,0 +1,15 @@
+package com.rczn.system.service;
+
+import com.rczn.system.domain.RolePermission;
+import java.util.List;
+
+public interface RolePermissionService {
+
+ List selectListByRoleId(Integer roleId);
+
+ void insert(RolePermission rolePermission);
+
+ boolean delete(Integer roleId, Integer permissionId);
+
+ void deleteByRoleId(Integer roleId);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/RoleService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/RoleService.java
new file mode 100644
index 0000000..6e6fa29
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/RoleService.java
@@ -0,0 +1,60 @@
+package com.rczn.system.service;
+
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Role;
+
+import java.util.List;
+
+/**
+ * Role 业务逻辑层接口
+ */
+public interface RoleService {
+
+ /**
+ * 分页查询角色(支持多条件模糊查询)
+ * @param pageNum 页码(从1开始)
+ * @param pageSize 每页条数
+ * @param roleName 角色名(可选)
+ * @param roleCode 角色编码(可选)
+ * @return 分页结果
+ */
+ PageBean selectRolePage(Integer pageNum, Integer pageSize, String roleName, String roleCode);
+
+ /**
+ * 根据ID查询单个角色
+ * @param id 角色ID
+ * @return 角色实体
+ */
+ Role selectById(Long id);
+
+ /**
+ * 新增角色(校验角色编码唯一性)
+ * @param role 角色实体
+ * @return 新增成功的角色ID
+ * @throws IllegalArgumentException 角色编码已存在时抛出
+ */
+ Long insert(Role role);
+
+ /**
+ * 修改角色(校验角色编码唯一性+部分字段更新)
+ * @param role 角色实体(需包含ID)
+ * @return 是否修改成功
+ * @throws IllegalArgumentException 角色编码已存在或未传ID时抛出
+ */
+ Boolean update(Role role);
+
+ /**
+ * 根据ID删除角色
+ * @param id 角色ID
+ * @return 是否删除成功
+ */
+ Boolean deleteById(Long id);
+
+ /**
+ * 根据角色名或角色编码模糊查询角色列表
+ * @param roleName 角色名(可选)
+ * @param roleCode 角色编码(可选)
+ * @return 角色列表
+ */
+ List selectRoleList(String roleName, String roleCode);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysDicDataService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysDicDataService.java
new file mode 100644
index 0000000..a590771
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysDicDataService.java
@@ -0,0 +1,44 @@
+package com.rczn.system.service;
+
+import com.github.pagehelper.PageInfo;
+import com.rczn.system.domain.SysDicData;
+
+import java.util.List;
+
+public interface SysDicDataService {
+
+ /**
+ * 分页查询字典数据
+ */
+ PageInfo selectPage(Integer pageNum, Integer pageSize, Integer dicId, String dicLabel, String dicValue);
+
+ /**
+ * 查询字典数据列表
+ */
+ List selectList(Integer dicId, String dicLabel, String dicValue);
+
+ /**
+ * 根据ID查询字典数据
+ */
+ SysDicData selectById(Long id);
+
+ /**
+ * 根据字典类型ID查询字典数据列表
+ */
+ List selectByDicId(Integer dicId);
+
+ /**
+ * 新增字典数据
+ */
+ Long insert(SysDicData sysDicData);
+
+ /**
+ * 修改字典数据
+ */
+ Boolean update(SysDicData sysDicData);
+
+ /**
+ * 逻辑删除字典数据
+ */
+ Boolean deleteById(Long id);
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysDicTypeService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysDicTypeService.java
new file mode 100644
index 0000000..c04b731
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysDicTypeService.java
@@ -0,0 +1,40 @@
+package com.rczn.system.service;
+
+
+import com.github.pagehelper.PageInfo;
+import com.rczn.system.domain.SysDicType;
+
+import java.util.List;
+
+public interface SysDicTypeService {
+
+ /**
+ * 分页查询字典类型
+ */
+ PageInfo selectPage(Integer pageNum, Integer pageSize, String dicName, String dicCode);
+
+ /**
+ * 查询字典类型列表
+ */
+ List selectList( String dicName, String dicCode);
+
+ /**
+ * 根据ID查询字典类型
+ */
+ SysDicType selectById(Long id);
+
+ /**
+ * 新增字典类型
+ */
+ Long insert(SysDicType sysDicType);
+
+ /**
+ * 修改字典类型
+ */
+ Boolean update(SysDicType sysDicType);
+
+ /**
+ * 逻辑删除字典类型
+ */
+ Boolean deleteById(Long id);
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysPermissionService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysPermissionService.java
new file mode 100644
index 0000000..8e5ee0a
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/SysPermissionService.java
@@ -0,0 +1,26 @@
+package com.rczn.system.service;
+
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.Role;
+
+import java.util.List;
+
+public interface SysPermissionService {
+ List getPermissionList();
+ //根据父ID查询权限列表:
+ List getPermissionListByParentId(Integer parentId);
+ Permission getPermissionById(Integer id);
+ boolean addPermission(Permission permission);
+ boolean updatePermission(Permission permission);
+ boolean deletePermission(Integer id);
+
+ /**
+ * 1. 分页查询角色(多条件模糊查询)
+ * @param pageNum
+ * @param pageSize
+ * @param permissionName
+ * @return
+ */
+ PageBean selectRolePage(Integer pageNum, Integer pageSize,Integer parentId, String permissionName);
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/UserRoleService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/UserRoleService.java
new file mode 100644
index 0000000..f3897ad
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/UserRoleService.java
@@ -0,0 +1,23 @@
+package com.rczn.system.service;
+
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.UserRole;
+import java.util.List;
+
+public interface UserRoleService {
+ Long insert(UserRole userRole);
+ Boolean deleteById(Long id);
+ Boolean deleteByUserId(Integer userId);
+ Boolean deleteByRoleId(Integer roleId);
+ UserRole selectById(Long id);
+ List selectByUserId(Integer userId);
+
+/**
+ * Selects user roles by the given role ID
+ *
+ * @param roleId The ID of the role to search for
+ * @return List of UserRole objects associated with the given role ID
+ */
+ List selectByRoleId(Integer roleId);
+ PageBean selectPage(Integer pageNum, Integer pageSize, Integer userId, Integer roleId);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/UserService.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/UserService.java
new file mode 100644
index 0000000..8a73a04
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/UserService.java
@@ -0,0 +1,78 @@
+package com.rczn.system.service;
+
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.User;
+
+import java.util.List;
+
+/**
+ * User 业务逻辑层接口
+ */
+public interface UserService {
+
+ /**
+ * 1. 分页查询用户(支持用户名模糊查询)
+ * @param pageNum 页码(从1开始)
+ * @param pageSize 每页条数
+ * @param userName 用户名(模糊查询,可选)
+ * @return 分页结果(PageBean)
+ */
+ PageBean selectUserPage(Integer pageNum, Integer pageSize, String userName);
+
+ /**
+ * 1. 查询用户列表(支持用户名模糊查询)
+ * @param userName 用户名(模糊查询,可选)
+ * @return 结果(listUser)
+ */
+ List selectUserList(String userName);
+
+ /**
+ * 2. 根据ID查询单个用户
+ * @param id 用户ID
+ * @return 单个用户实体
+ */
+ User selectById(Long id);
+
+ /**
+ * 3. 新增用户
+ * @param user 用户实体
+ * @return 新增成功的用户ID
+ */
+ Long insert(User user);
+
+ /**
+ * 4. 修改用户(部分字段更新)
+ * @param user 用户实体(需包含ID,仅更新非空字段)
+ * @return 是否修改成功(true/false)
+ */
+ Boolean update(User user);
+
+ /**
+ * 5. 根据ID删除用户
+ * @param id 用户ID
+ * @return 是否删除成功(true/false)
+ */
+ Boolean deleteById(Long id);
+
+ /**
+ * 6. 根据用户名查询用户
+ * @param username 用户名
+ * @return 用户实体
+ */
+ User findeUserByUsername(String username);
+
+ /**
+ * 7. 注册用户
+ * @param username 用户名
+ * @param password 密码
+ */
+ int register(String username, String password);
+
+ /**
+ * 根据用户id查询出关联的用户权限对象列表,
+ * 表直接的关系是:
+ * 用户表(user)--用户权限表(user_role)--权限表(role)-- 权限资源表(role_resource)--资源表(resource)
+ */
+ List findUserPermissions(Long userId);
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/DepartmentServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/DepartmentServiceImpl.java
new file mode 100644
index 0000000..e1bd1fa
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/DepartmentServiceImpl.java
@@ -0,0 +1,186 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Department;
+import com.rczn.system.mapper.DepartmentMapper;
+import com.rczn.system.service.DepartmentService;
+import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class DepartmentServiceImpl implements DepartmentService {
+
+ @Autowired
+ private DepartmentMapper departmentMapper;
+
+ @Override
+ public Long insert(Department department) {
+ // 校验必填字段
+ Assert.notNull(department.getDeptName(), "部门名称不能为空");
+ Assert.notNull(department.getDeptCode(), "部门编码不能为空");
+
+ // 补充创建时间字段
+// department.setCreateId(getCurrentUserId());
+ if (department.getCreateTime() == null) {
+ department.setCreateTime(LocalDateTime.now());
+ }
+ int rows = departmentMapper.insert(department);
+ return rows > 0 ? department.getId() : null;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ Assert.notNull(id, "部门ID不能为空");
+ int rows = departmentMapper.deleteById(id);
+ return rows > 0;
+ }
+
+ @Override
+ public Boolean update(Department department) {
+ Assert.notNull(department.getId(), "部门ID不能为空");
+
+// department.setUpdateId(null);
+ if (department.getUpdateTime() == null) {
+ department.setUpdateTime(LocalDateTime.now());
+ }
+ int rows = departmentMapper.updateById(department);
+ return rows > 0;
+ }
+
+ @Override
+ public Department selectById(Long id) {
+ Assert.notNull(id, "部门ID不能为空");
+ return departmentMapper.selectById(id);
+ }
+
+ @Override
+ public PageBean selectPage(Integer pageNum, Integer pageSize, String deptName, String deptCode, Integer parentId) {
+ // 校验分页参数
+ Assert.notNull(pageNum, "页码不能为空");
+ Assert.notNull(pageSize, "每页条数不能为空");
+ Assert.isTrue(pageNum > 0, "页码必须大于0");
+ Assert.isTrue(pageSize > 0 && pageSize <= 100000, "每页条数必须在1-10000之间");
+ // 1. 设置分页参数(PageHelper 自动拦截后续的 SQL 进行分页)
+ PageHelper.startPage(pageNum, pageSize);
+
+ // 查询分页数据和总数
+ List items = departmentMapper.selectPage(deptName, deptCode, parentId);
+ Page page = (Page) items;
+
+ PageBean pageBean = new PageBean<>();
+ pageBean.setTotal(page.getTotal());
+ pageBean.setItems(page.getResult());
+
+ // 封装PageBean返回
+ return pageBean;
+ }
+
+ /**
+ * 核心:获取完整部门树(包含所有字段和层级关系)
+ */
+ @Override
+ public List getDeptTree() {
+ // 1. 查询所有未删除的部门(一次性查询,减少数据库交互)
+ List allDept = departmentMapper.selectAllDept();
+
+ // 2. 递归组装树形结构(从顶级部门开始)
+ return buildDeptTree(allDept, null);
+ }
+
+ /**
+ * 核心:获取简化版部门树(仅ID、名称、子部门,用于下拉选择框等场景)
+ */
+ @Override
+ public List getSimpleDeptTree() {
+ List allDept = departmentMapper.selectAllDept();
+ List deptTree = buildDeptTree(allDept, null);
+
+ // 简化部门树字段(仅保留必要字段,减少返回数据量)
+ return simplifyDeptTree(deptTree);
+ }
+
+ /**
+ * 递归组装部门树
+ * @param allDept 所有部门列表
+ * @param parentId 父部门ID(null 表示查询顶级部门)
+ * @return 组装后的子部门列表
+ */
+ private List buildDeptTree(List allDept, Integer parentId) {
+ // 筛选当前父部门的所有子部门
+ List childrenDept = allDept.stream()
+ .filter(dept -> {
+ // 父部门ID为null时,筛选parent_id IS NULL的顶级部门;否则筛选parent_id等于当前parentId的部门
+ if (parentId == null) {
+ return dept.getParentId() == null;
+ } else {
+ return parentId.equals(dept.getParentId());
+ }
+ })
+ .collect(Collectors.toList());
+
+ // 递归为每个子部门设置下属子部门
+ for (Department dept : childrenDept) {
+ List children = buildDeptTree(allDept, dept.getId().intValue()); // dept.id是Long,转Integer匹配parentId类型
+ dept.setLeader(null); // 简化场景可清空负责人,如需保留可删除此句
+ dept.setChildren(children); // 给当前部门设置子部门
+ }
+
+ return childrenDept;
+ }
+
+ /**
+ * 简化部门树字段(仅保留ID、名称、子部门)
+ * @param deptTree 完整部门树
+ * @return 简化后的部门树
+ */
+ private List simplifyDeptTree(List deptTree) {
+ List simpleTree = new ArrayList<>();
+
+ for (Department dept : deptTree) {
+ Department simpleDept = new Department();
+ simpleDept.setId(dept.getId());
+ simpleDept.setDeptName(dept.getDeptName());
+ simpleDept.setDeptCode(dept.getDeptCode());
+
+ // 递归简化子部门
+ if (dept.getChildren() != null && !dept.getChildren().isEmpty()) {
+ simpleDept.setChildren(simplifyDeptTree(dept.getChildren()));
+ }
+
+ simpleTree.add(simpleDept);
+ }
+
+ return simpleTree;
+ }
+
+ /**
+ * 辅助方法:获取当前登录用户ID(需替换为你的实际获取逻辑,如从Token中解析)
+ */
+ private Long getCurrentUserId() {
+ // 示例:临时返回1,实际项目中需替换为真实的用户ID获取逻辑(如SecurityContext、ThreadLocal等)
+ return 1L;
+ }
+
+ // 为Department实体类添加children字段的setter(因为原实体类没有,需动态设置子部门)
+ // 注意:这里是通过反射或直接在实体类中添加children字段,推荐在实体类中显式添加!
+ // 下面是临时解决方案,实际需修改Department实体类(见步骤六)
+ private void setChildren(Department dept, List children) {
+ try {
+ // 通过反射给Department设置children字段(若实体类已添加,可直接调用setChildren)
+ java.lang.reflect.Field field = Department.class.getDeclaredField("children");
+ field.setAccessible(true);
+ field.set(dept, children);
+ } catch (Exception e) {
+ throw new RuntimeException("设置部门子节点失败", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/PositionServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/PositionServiceImpl.java
new file mode 100644
index 0000000..73e70ce
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/PositionServiceImpl.java
@@ -0,0 +1,83 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Department;
+import com.rczn.system.domain.Position;
+import com.rczn.system.mapper.PositionMapper;
+import com.rczn.system.service.PositionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import java.util.List;
+
+@Service
+public class PositionServiceImpl implements PositionService {
+
+ @Autowired
+ private PositionMapper positionMapper;
+
+ @Override
+ public Long insert(Position position) {
+ Assert.notNull(position.getPosiName(), "职位名称不能为空");
+ Assert.notNull(position.getPosiCode(), "职位编码不能为空");
+ int rows = positionMapper.insert(position);
+ return rows > 0 ? position.getId() : null;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ Assert.notNull(id, "职位ID不能为空");
+ int rows = positionMapper.deleteById(id);
+ return rows > 0;
+ }
+
+ @Override
+ public Boolean update(Position position) {
+ Assert.notNull(position.getId(), "职位ID不能为空");
+ int rows = positionMapper.updateById(position);
+ return rows > 0;
+ }
+
+ @Override
+ public Position selectById(Long id) {
+ Assert.notNull(id, "职位ID不能为空");
+ return positionMapper.selectById(id);
+ }
+
+ @Override
+ public PageBean selectPage(Integer pageNum, Integer pageSize, String posiName, String posiCode) {
+ Assert.notNull(pageNum, "页码不能为空");
+ Assert.notNull(pageSize, "每页条数不能为空");
+ Assert.isTrue(pageNum > 0, "页码必须大于0");
+ Assert.isTrue(pageSize > 0 && pageSize <= 100000, "每页条数必须在1-10000之间");
+
+ // 1. 设置分页参数(PageHelper 自动拦截后续的 SQL 进行分页)
+ PageHelper.startPage(pageNum, pageSize);
+
+ // 查询分页数据和总数
+
+ List items = positionMapper.selectPage(posiName, posiCode);
+ Page page = (Page) items;
+
+ PageBean pageBean = new PageBean<>();
+ pageBean.setTotal(page.getTotal());
+ pageBean.setItems(page.getResult());
+
+ // 封装PageBean返回
+ return pageBean;
+ }
+
+ /**
+ * 条件查询职位列表
+ * @param posiName 职位名称
+ * @param posiCode 职位编码
+ * @return 职位列表
+ */
+ @Override
+ public List selectList(String posiName, String posiCode) {
+ return positionMapper.selectList(posiName, posiCode);
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/RolePermissionServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/RolePermissionServiceImpl.java
new file mode 100644
index 0000000..5a1fb45
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/RolePermissionServiceImpl.java
@@ -0,0 +1,42 @@
+package com.rczn.system.service.impl;
+
+import com.rczn.system.domain.RolePermission;
+import com.rczn.system.mapper.RolePermissionMapper;
+import com.rczn.system.service.RolePermissionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Service
+public class RolePermissionServiceImpl implements RolePermissionService {
+
+ @Autowired
+ RolePermissionMapper rolePermissionMapper;
+
+ @Override
+ public List selectListByRoleId(Integer roleId) {
+ return rolePermissionMapper.selectListByRoleId(roleId);
+ }
+
+ @Override
+ @Transactional
+ public void insert(RolePermission rolePermission) {
+ rolePermission.setCreateTime(LocalDateTime.now());
+ rolePermissionMapper.insert(rolePermission);
+ }
+
+ @Override
+ @Transactional
+ public boolean delete(Integer roleId, Integer permissionId) {
+ return rolePermissionMapper.delete(roleId, permissionId) > 0;
+ }
+
+ @Override
+ @Transactional
+ public void deleteByRoleId(Integer roleId) {
+ rolePermissionMapper.deleteByRoleId(roleId);
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/RoleServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/RoleServiceImpl.java
new file mode 100644
index 0000000..c3f47c9
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/RoleServiceImpl.java
@@ -0,0 +1,110 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Role;
+import com.rczn.system.mapper.RoleMapper;
+import com.rczn.system.service.RoleService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * Role 业务逻辑层实现
+ */
+@Service
+@Transactional
+public class RoleServiceImpl implements RoleService {
+
+ @Autowired
+ RoleMapper roleMapper;
+
+ @Override
+ public PageBean selectRolePage(Integer pageNum, Integer pageSize, String roleName, String roleCode) {
+ // 1. PageHelper 设置分页参数
+ PageHelper.startPage(pageNum, pageSize);
+ // 2. 执行查询
+ List roleList = roleMapper.selectRolePage(roleName, roleCode);
+ // 3. 查询总条数
+ Long total = roleMapper.selectTotal(roleName, roleCode);
+ // 4. 封装分页结果
+ return new PageBean() {{
+ setTotal(total);
+ setItems(roleList);
+ }};
+ }
+
+ @Override
+ public Role selectById(Long id) {
+ return roleMapper.selectById(id);
+ }
+
+ @Override
+ public Long insert(Role role) {
+ // 校验角色编码唯一性
+ Integer count = roleMapper.checkRoleCodeUnique(role.getRoleCode(), null);
+ if (count != null && count > 0) {
+ throw new IllegalArgumentException("角色编码:" + role.getRoleCode() + " 已存在");
+ }
+ // 更新创建时间、创建者
+// TODO 待实现
+// role.setCreateId(1L);
+
+ if (role.getCreateTime() == null) {
+ role.setCreateTime(LocalDateTime.now());
+ }
+ // 执行新增(自动回填ID)
+ roleMapper.insert(role);
+ return role.getId();
+ }
+
+ @Override
+ public Boolean update(Role role) {
+ // 校验ID是否存在
+ if (role.getId() == null) {
+ throw new IllegalArgumentException("修改角色必须传入ID");
+ }
+ // 校验角色编码唯一性(排除自身)
+ Integer count = roleMapper.checkRoleCodeUnique(role.getRoleCode(), role.getId());
+ if (count != null && count > 0) {
+ throw new IllegalArgumentException("角色编码:" + role.getRoleCode() + " 已存在");
+ }
+ // 更新更新时间、更新者
+ // TODO 待实现
+// role.setUpdateId(1L);
+ if (role.getUpdateTime() == null) {
+ role.setUpdateTime(LocalDateTime.now());
+ }
+ // 执行修改
+ int rows = roleMapper.update(role);
+ return rows > 0;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ // 先校验角色是否存在
+ Role role = roleMapper.selectById(id);
+ if (role == null) {
+ return false;
+ }
+ // 执行删除
+ int rows = roleMapper.deleteById(id);
+ return rows > 0;
+ }
+
+ /**
+ * 根据角色名或角色编码模糊查询角色列表
+ *
+ * @param roleName 角色名(可选)
+ * @param roleCode 角色编码(可选)
+ * @return 角色列表
+ */
+ @Override
+ public List selectRoleList(String roleName, String roleCode) {
+ return roleMapper.selectRolePage(roleName, roleCode);
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysDicDataServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysDicDataServiceImpl.java
new file mode 100644
index 0000000..ff69849
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysDicDataServiceImpl.java
@@ -0,0 +1,97 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.rczn.system.domain.SysDicData;
+import com.rczn.system.mapper.SysDicDataMapper;
+import com.rczn.system.service.SysDicDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import java.util.List;
+
+@Service
+public class SysDicDataServiceImpl implements SysDicDataService {
+
+ @Autowired
+ private SysDicDataMapper sysDicDataMapper;
+
+ @Override
+ public PageInfo selectPage(Integer pageNum, Integer pageSize, Integer dicId, String dicLabel, String dicValue) {
+ PageHelper.startPage(pageNum, pageSize);
+ SysDicData query = new SysDicData();
+ query.setDicId(dicId);
+ query.setDicLabel(dicLabel);
+ query.setDicValue(dicValue);
+ return new PageInfo<>(sysDicDataMapper.selectPage(query));
+ }
+
+ /**
+ * 查询字典数据列表
+ *
+ * @param dicId
+ * @param dicLabel
+ * @param dicValue
+ */
+ @Override
+ public List selectList(Integer dicId, String dicLabel, String dicValue) {
+ SysDicData query = new SysDicData();
+ query.setDicId(dicId);
+ query.setDicLabel(dicLabel);
+ query.setDicValue(dicValue);
+ return sysDicDataMapper.selectPage(query);
+ }
+
+ @Override
+ public SysDicData selectById(Long id) {
+ return sysDicDataMapper.selectById(id);
+ }
+
+ @Override
+ public List selectByDicId(Integer dicId) {
+ if (dicId == null) {
+ throw new IllegalArgumentException("字典类型ID不能为空");
+ }
+ return sysDicDataMapper.selectByDicId(dicId);
+ }
+
+ @Override
+ public Long insert(SysDicData sysDicData) {
+ // 校验必填项
+ if (sysDicData.getDicId() == null) {
+ throw new IllegalArgumentException("字典类型ID不能为空");
+ }
+ if (sysDicData.getDicLabel() == null || sysDicData.getDicLabel().trim().isEmpty()) {
+ throw new IllegalArgumentException("数据标签不能为空");
+ }
+ int count = sysDicDataMapper.insert(sysDicData);
+ return count > 0 ? sysDicData.getId() : null;
+ }
+
+ @Override
+ public Boolean update(SysDicData sysDicData) {
+ if (sysDicData.getId() == null) {
+ throw new IllegalArgumentException("字典数据ID不能为空");
+ }
+ // 校验是否存在
+ SysDicData exist = sysDicDataMapper.selectById(sysDicData.getId());
+ if (exist == null) {
+ return false;
+ }
+ int count = sysDicDataMapper.update(sysDicData);
+ return count > 0;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ if (id == null) {
+ throw new IllegalArgumentException("字典数据ID不能为空");
+ }
+ // 校验是否存在
+ SysDicData exist = sysDicDataMapper.selectById(id);
+ if (exist == null) {
+ return false;
+ }
+ int count = sysDicDataMapper.deleteById(id);
+ return count > 0;
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysDicTypeServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysDicTypeServiceImpl.java
new file mode 100644
index 0000000..f9b6625
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysDicTypeServiceImpl.java
@@ -0,0 +1,84 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.rczn.system.domain.SysDicType;
+import com.rczn.system.mapper.SysDicTypeMapper;
+import com.rczn.system.service.SysDicTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class SysDicTypeServiceImpl implements SysDicTypeService {
+
+ @Autowired
+ private SysDicTypeMapper sysDicTypeMapper;
+
+ @Override
+ public PageInfo selectPage(Integer pageNum, Integer pageSize, String dicName, String dicCode) {
+ PageHelper.startPage(pageNum, pageSize);
+ SysDicType query = new SysDicType();
+ query.setDicName(dicName);
+ query.setDicCode(dicCode);
+ return new PageInfo<>(sysDicTypeMapper.selectPage(query));
+ }
+
+ /**
+ * 查询字典类型列表
+ *
+ * @param dicName
+ * @param dicCode
+ */
+ @Override
+ public List selectList(String dicName, String dicCode) {
+ SysDicType query = new SysDicType();
+ query.setDicName(dicName);
+ query.setDicCode(dicCode);
+ return sysDicTypeMapper.selectPage(query);
+ }
+
+ @Override
+ public SysDicType selectById(Long id) {
+ return sysDicTypeMapper.selectById(id);
+ }
+
+ @Override
+ public Long insert(SysDicType sysDicType) {
+ // 校验必填项
+ if (sysDicType.getDicName() == null || sysDicType.getDicName().trim().isEmpty()) {
+ throw new IllegalArgumentException("字典名称不能为空");
+ }
+ int count = sysDicTypeMapper.insert(sysDicType);
+ return count > 0 ? sysDicType.getId() : null;
+ }
+
+ @Override
+ public Boolean update(SysDicType sysDicType) {
+ if (sysDicType.getId() == null) {
+ throw new IllegalArgumentException("字典类型ID不能为空");
+ }
+ // 校验是否存在
+ SysDicType exist = sysDicTypeMapper.selectById(sysDicType.getId());
+ if (exist == null) {
+ return false;
+ }
+ int count = sysDicTypeMapper.update(sysDicType);
+ return count > 0;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ if (id == null) {
+ throw new IllegalArgumentException("字典类型ID不能为空");
+ }
+ // 校验是否存在
+ SysDicType exist = sysDicTypeMapper.selectById(id);
+ if (exist == null) {
+ return false;
+ }
+ int count = sysDicTypeMapper.deleteById(id);
+ return count > 0;
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysPermissionServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysPermissionServiceImpl.java
new file mode 100644
index 0000000..22fa1a3
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/SysPermissionServiceImpl.java
@@ -0,0 +1,140 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.Role;
+import com.rczn.system.mapper.SysPermissionMapper;
+import com.rczn.system.service.SysPermissionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class SysPermissionServiceImpl implements SysPermissionService {
+
+ @Autowired
+ private SysPermissionMapper sysPermissionMapper;
+
+ @Override
+ public Permission getPermissionById(Integer id) {
+ return sysPermissionMapper.selectPermissionById(id);
+ }
+
+ @Override
+ public boolean addPermission(Permission permission) {
+ return sysPermissionMapper.insertPermission(permission) > 0;
+ }
+
+ @Override
+ public boolean updatePermission(Permission permission) {
+ return sysPermissionMapper.updatePermission(permission) > 0;
+ }
+
+ @Override
+ public boolean deletePermission(Integer id) {
+ return sysPermissionMapper.deletePermissionById(id) > 0;
+ }
+
+ /**
+ * 1. 分页查询角色(多条件模糊查询)
+ *
+ * @param pageNum
+ * @param pageSize
+ * @param permissionName
+ * @return
+ */
+ @Override
+ public PageBean selectRolePage(Integer pageNum, Integer pageSize,Integer parentId, String permissionName) {
+ // 1. PageHelper 设置分页参数
+ PageHelper.startPage(pageNum, pageSize);
+ //加一层过滤:
+ if(parentId == 0){
+ parentId = null;
+ }
+ // 2. 执行查询
+ List permissionList = sysPermissionMapper.selectPermissionPage(parentId,permissionName);
+ // 3. 查询总条数
+ Long total = sysPermissionMapper.selectTotal(parentId,permissionName);
+ // 4. 封装分页结果
+ return new PageBean() {{
+ setTotal(total);
+ setItems(permissionList);
+ }};
+ }
+
+ @Override
+ public List getPermissionList() {
+ // 1. 查询所有平级权限
+ List allPermissions = sysPermissionMapper.selectPermissionList();
+
+ // 2. 找到顶层节点(parentId = null 或 0)
+ List topNodes = new ArrayList<>();
+ for (Permission p : allPermissions) {
+ if (p.getParentId() == null || p.getParentId() == 0) {
+ topNodes.add(p);
+ }
+ }
+
+ // 3. 循环给每个顶层节点设置子节点(递归)
+ for (Permission node : topNodes) {
+ node.setChildren(findChildren(node, allPermissions));
+ }
+
+ return topNodes;
+ }
+
+ /***
+ * 根据父ID查询权限列表
+ * @param parentId
+ * @return
+ */
+ @Override
+ public List getPermissionListByParentId(Integer parentId) {
+ // 1. 查询所有平级权限
+ List allPermissions = sysPermissionMapper.selectPermissionList();
+
+ // 2. 找到顶层节点(parentId = null 或 0)
+ List topNodes = new ArrayList<>();
+ for (Permission p : allPermissions) {
+ if(parentId == null || parentId == 0){
+ if (p.getParentId() == null || p.getParentId() == 0) {
+ topNodes.add(p);
+ }
+ }else {
+ if (p.getParentId() == parentId) {
+ topNodes.add(p);
+ }
+ }
+
+ }
+
+ // 3. 循环给每个顶层节点设置子节点(递归)
+ for (Permission node : topNodes) {
+ node.setChildren(findChildren(node, allPermissions));
+ }
+
+ return topNodes;
+ }
+
+ /**
+ * 递归查找子节点(最稳妥、最清晰、不会漏)
+ */
+ private List findChildren(Permission parent, List allList) {
+ List children = new ArrayList<>();
+
+ for (Permission p : allList) {
+ // 子节点的 parentId == 父节点 id
+ if (parent.getId().equals(p.getParentId()==null?0:p.getParentId().longValue())) {
+ children.add(p);
+ // 递归给子节点设置孙子节点
+ p.setChildren(findChildren(p, allList));
+ }
+ }
+
+ return children;
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/UserRoleServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/UserRoleServiceImpl.java
new file mode 100644
index 0000000..a56a513
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/UserRoleServiceImpl.java
@@ -0,0 +1,88 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.Position;
+import com.rczn.system.domain.UserRole;
+import com.rczn.system.mapper.UserRoleMapper;
+import com.rczn.system.service.UserRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import java.util.List;
+
+@Service
+public class UserRoleServiceImpl implements UserRoleService {
+
+ @Autowired
+ private UserRoleMapper userRoleMapper;
+
+ @Override
+ public Long insert(UserRole userRole) {
+ Assert.notNull(userRole.getUserId(), "用户ID不能为空");
+ Assert.notNull(userRole.getRoleId(), "角色ID不能为空");
+ int rows = userRoleMapper.insert(userRole);
+ return rows > 0 ? userRole.getId() : null;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ Assert.notNull(id, "关联ID不能为空");
+ int rows = userRoleMapper.deleteById(id);
+ return rows > 0;
+ }
+
+ @Override
+ public Boolean deleteByUserId(Integer userId) {
+ Assert.notNull(userId, "用户ID不能为空");
+ int rows = userRoleMapper.deleteByUserId(userId);
+ return rows > 0;
+ }
+
+ @Override
+ public Boolean deleteByRoleId(Integer roleId) {
+ Assert.notNull(roleId, "角色ID不能为空");
+ int rows = userRoleMapper.deleteByRoleId(roleId);
+ return rows > 0;
+ }
+
+ @Override
+ public UserRole selectById(Long id) {
+ Assert.notNull(id, "关联ID不能为空");
+ return userRoleMapper.selectById(id);
+ }
+
+ @Override
+ public List selectByUserId(Integer userId) {
+ Assert.notNull(userId, "用户ID不能为空");
+ return userRoleMapper.selectByUserId(userId);
+ }
+
+ @Override
+ public List selectByRoleId(Integer roleId) {
+ Assert.notNull(roleId, "角色ID不能为空");
+ return userRoleMapper.selectByRoleId(roleId);
+ }
+
+ @Override
+ public PageBean selectPage(Integer pageNum, Integer pageSize, Integer userId, Integer roleId) {
+ Assert.notNull(pageNum, "页码不能为空");
+ Assert.notNull(pageSize, "每页条数不能为空");
+ Assert.isTrue(pageNum > 0, "页码必须大于0");
+ Assert.isTrue(pageSize > 0 && pageSize <= 100000, "每页条数必须在1-10000之间");
+
+ PageHelper.startPage(pageNum,pageSize);
+ List items = userRoleMapper.selectPage(userId, roleId);
+ Page page = (Page) items;
+
+ PageBean pageBean = new PageBean<>();
+ pageBean.setTotal(page.getTotal());
+ pageBean.setItems(page.getResult());
+
+ // 封装PageBean返回
+ return pageBean;
+ }
+}
diff --git a/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/UserServiceImpl.java b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..701d98a
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/java/com/rczn/system/service/impl/UserServiceImpl.java
@@ -0,0 +1,131 @@
+package com.rczn.system.service.impl;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.rczn.domain.PageBean;
+import com.rczn.system.domain.Permission;
+import com.rczn.system.domain.User;
+import com.rczn.system.mapper.UserMapper;
+import com.rczn.system.service.UserService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * User 业务逻辑层实现
+ */
+@Service
+@Transactional // 事务管理(增删改操作需事务)
+public class UserServiceImpl implements UserService {
+
+ // 注入 Mapper(Lombok @RequiredArgsConstructor 自动生成构造器)
+
+ @Autowired
+ UserMapper userMapper;
+
+ @Override
+ public PageBean selectUserPage(Integer pageNum, Integer pageSize, String userName) {
+ // 1. 设置分页参数(PageHelper 自动拦截后续的 SQL 进行分页)
+ PageHelper.startPage(pageNum, pageSize);
+
+ // 2. 执行查询(MyBatis 会自动添加 LIMIT 分页)
+ User user = new User();
+ user.setUserName(userName);
+ List userList = userMapper.selectUserPage(user);
+ Page userPage = (Page) userList;
+
+ // 3. 查询总条数(支持模糊查询条件)
+ PageBean pageBean = new PageBean<>();
+ pageBean.setTotal(userPage.getTotal());
+ pageBean.setItems(userPage);
+
+ // 4. 封装分页结果(使用你的自定义 PageBean)
+ return pageBean;
+ }
+
+ /**
+ * 1. 查询用户列表(支持用户名模糊查询)
+ *
+ * @param userName 用户名(模糊查询,可选)
+ * @return 结果(listUser)
+ */
+ @Override
+ public List selectUserList(String userName) {
+ // 2. 执行查询(MyBatis 会自动添加 LIMIT 分页)
+ User user = new User();
+ user.setUserName(userName);
+ List userList = userMapper.selectUserPage(user);
+
+ return userList;
+ }
+
+ @Override
+ public User selectById(Long id) {
+ // 查询不到返回 null(后续 Controller 处理)
+ return userMapper.selectById(id, false);
+ }
+
+ @Override
+ public Long insert(User user) {
+ // 执行新增(XML 中已配置 useGeneratedKeys,会自动回填 ID 到 user 对象)
+ userMapper.insert(user);
+ return user.getId(); // 返回新增用户的 ID
+ }
+
+ @Override
+ public Boolean update(User user) {
+ if (user.getId() == null) {
+ throw new IllegalArgumentException("修改用户必须传入 ID");
+ }
+ // 执行修改(返回影响行数,>0 表示修改成功)
+ int rows = userMapper.update(user);
+ return rows > 0;
+ }
+
+ @Override
+ public Boolean deleteById(Long id) {
+ // 执行删除(返回影响行数,>0 表示删除成功)
+ int rows = userMapper.deleteById(id,null);
+ return rows > 0;
+ }
+
+ /**
+ * 6. 根据用户名查询用户
+ *
+ * @param username 用户名
+ * @return 用户实体
+ */
+ @Override
+ public User findeUserByUsername(String username) {
+ return userMapper.selectByUsername(username);
+ }
+
+ /**
+ * 7. 注册用户
+ *
+ * @param username 用户名
+ * @param password 密码
+ */
+ @Override
+ public int register(String username, String password) {
+ User user = new User();
+ user.setUserName(username);
+ user.setPassword(password);
+ return userMapper.insert(user);
+ }
+
+ /**
+ * 根据用户id查询出关联的用户权限对象列表,
+ * 表直接的关系是:
+ * 用户表(user)--用户权限表(user_role)--权限表(role)-- 权限资源表(role_resource)--资源表(resource)
+ *
+ * @param userId
+ */
+ @Override
+ public List findUserPermissions(Long userId) {
+ return userMapper.findUserPermissions(userId);
+ }
+}
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/application.yml b/rc_autoplc_backend/rczn-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..720422e
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/application.yml
@@ -0,0 +1,163 @@
+# 服务器配置
+server:
+ port: 9090 # 项目端口
+ servlet:
+ encoding:
+ charset: UTF-8 # 解决中文乱码(含接口文档/响应)
+ enabled: true
+ force: true
+
+# Spring核心配置
+spring:
+ application:
+ name: rczn-admin # 应用名称
+ # 数据源配置(MySQL 8.x)
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://47.116.126.33:3306/rc_autoplc_program?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&allowMultiQueries=true
+ username: nianke
+ password: Jy@.niankeCrm2025
+ # 解决跨域(可选,配合之前的CorsConfig)
+ web:
+ cors:
+ allowed-origins: false # 禁用默认CORS,使用自定义CorsConfig
+ # 关键:Jackson 序列化配置(替代 JacksonConfig)
+ jackson:
+ # 允许空对象序列化(解决 HttpMediaTypeNotAcceptableException 核心)
+ serialization:
+ fail-on-empty-beans: false
+ # 格式化 JSON 输出(可选,便于调试)
+ indent-output: true
+ # 忽略未知字段(避免前端传多余字段报错)
+ deserialization:
+ fail-on-unknown-properties: false
+ # 支持 Java 8 日期类型(LocalDateTime)
+ modules:
+ - com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
+ # 日期格式化(可选,统一日期返回格式)
+ date-format: yyyy-MM-dd HH:mm:ss
+ time-zone: GMT+8
+
+# MyBatis配置
+mybatis:
+ configuration:
+ map-underscore-to-camel-case: true # 下划线转驼峰
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 关键:SQL 打印到控制台
+ log-prefix: "[MyBatis] " # 可选:日志前缀,便于区分 SQL 日志
+ default-statement-timeout: 30 # 可选:SQL 执行超时时间(秒)
+ mapper-locations: classpath:mapper/**/*.xml # 补充:指定Mapper.xml文件路径(必加)
+ type-aliases-package: com.rczn.**.domain # 补充:实体类别名包(可选)
+
+
+ # HikariCP 连接池配置(关键)
+ hikari:
+ max-lifetime: 1800000 # 连接最大生命周期(30 分钟,必须小于 MySQL wait_timeout,默认 8 小时)
+ idle-timeout: 600000 # 连接空闲超时时间(10 分钟)
+ connection-timeout: 30000 # 连接超时时间(30 秒)
+ minimum-idle: 5 # 最小空闲连接数
+ maximum-pool-size: 10 # 最大连接池大小
+ test-while-idle: true # 空闲时检测连接有效性
+ validation-timeout: 5000 # 连接校验超时时间(5 秒)
+ connection-test-query: SELECT 1 # 连接校验 SQL(MySQL 可用此简单查询)
+
+# PageHelper 分页插件配置
+pagehelper:
+ helper-dialect: mysql # 数据库方言(适配 MySQL)
+ reasonable: true # 合理化分页(页码≤0时查第1页,页码超出总页数时查最后1页)
+ support-methods-arguments: true # 支持通过 Mapper 接口参数传递分页参数
+ params: count=countSql # 分页参数名映射
+
+#
+## SpringDoc OpenAPI 3 核心配置(适配Spring Boot 3.x)
+#springdoc:
+# packages-to-scan: com.rczn # 扫描的基础包(Controller所在包)
+# api-docs:
+# enabled: true # 启用/v3/api-docs接口
+# path: /v3/api-docs # OpenAPI JSON数据路径(默认)
+# swagger-ui:
+# path: /swagger-ui.html # 自定义Swagger UI访问路径(兼容Spring Boot 2.x习惯)
+# tags-sorter: alpha # 标签字母排序
+# operations-sorter: alpha # 接口字母排序
+# disable-swagger-default-url: true # 禁用默认PetStore示例
+# default-flat-param-object: false # 禁用扁平参数对象
+# paths-to-exclude: /error, /actuator/** # 排除错误接口/监控接口(可选)
+#
+## OpenAPI文档基础信息(中文正常显示)
+openapi:
+ info:
+ title: XX自动化编程系统API文档
+ description: SpringBoot 3.x + SpringDoc OpenAPI 3 接口文档
+ version: 1.0.0
+ contact:
+ name: 研发组
+ email: xxx@xxx.com
+ servers:
+ - url: http://localhost:9090 # 开发环境地址
+ description: 本地开发环境
+ - url: http://47.116.126.33:9090 # 测试环境地址
+ description: 测试环境
+
+
+# SpringDoc + Knife4j 核心配置
+springdoc:
+ packages-to-scan: com.rczn # 扫描Controller所在包
+ api-docs:
+ enabled: true
+ path: /v3/api-docs
+ swagger-ui:
+ tags-sorter: alpha
+ operations-sorter: alpha
+ paths-to-exclude: /error, /actuator/**
+
+# Knife4j增强配置(可选,开启中文UI)
+knife4j:
+ enable: true
+ setting:
+ language: zh_cn # 中文界面
+ enable-swagger-models: true # 显示模型
+ enable-document-manage: false # 关闭文档管理(开发环境)
+
+# OpenAPI文档信息
+#openapi:
+# info:
+# title: XX自动化编程系统API文档
+# description: SpringBoot 3.x + Knife4j + OpenAPI 3 接口文档
+# version: 1.0.0
+# contact:
+# name: 研发组
+# email: xxx@xxx.com
+# servers:
+# - url: http://localhost:9090
+# description: 本地开发环境
+# - url: http://47.116.126.33:9090
+# description: 测试环境
+# Spring Boot 日志核心配置
+logging:
+ # 1. 全局日志级别(可细化到包/类)
+ level:
+ root: INFO # 根日志级别(默认)
+ com.rczn.rcznautoplc: DEBUG # 自定义包级别(调试业务代码)
+ org.springframework: INFO # Spring 框架日志级别(减少冗余)
+ com.zaxxer.hikari: ERROR # 数据库连接池日志级别(仅输出错误)
+ mybatis: DEBUG # MyBatis SQL 日志级别(输出执行的 SQL)
+
+ # 2. 日志输出配置(控制台 + 文件)
+ pattern:
+# console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" # 控制台格式
+ file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" # 文件格式
+
+ # 3. 文件输出配置
+ file:
+ name: ./logs/rczn-autoplc.log # 日志文件路径(相对路径/绝对路径)
+ max-size: 10MB # 单个日志文件大小上限(超过则分割)
+ max-history: 30 # 日志文件保留天数
+ total-size-cap: 1GB # 日志文件总大小上限
+ clean-history-on-start: false # 启动时是否清理历史日志
+
+ # 4. 日志分割(按大小/时间,Logback 原生支持)
+ logback:
+ rollingpolicy:
+ file-name-pattern: ./logs/rczn-autoplc-%d{yyyy-MM-dd}.%i.log # 分割后的文件名(%i 是序号,处理同天多文件)
+ max-file-size: 100MB # 单个文件大小(覆盖上面的 max-size)
+ max-history: 30 # 保留天数
+ total-size-cap: 1GB # 总大小
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/DepartmentMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/DepartmentMapper.xml
new file mode 100644
index 0000000..e83d1cb
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/DepartmentMapper.xml
@@ -0,0 +1,179 @@
+
+
+
+
+
+ id, create_id, create_time, update_id, update_time, del_sign, remark
+
+
+
+
+ dept_name, dept_code, parent_id, leader_id
+
+
+
+
+ INSERT INTO sys_department (
+
+
+
+ create_id,
+ create_time,
+ remark,
+
+ dept_name,
+ dept_code,
+ parent_id,
+ leader_id,
+
+ ) VALUES (
+
+
+
+ #{createId},
+ #{createTime},
+ #{remark},
+
+ #{deptName},
+ #{deptCode},
+ #{parentId},
+ #{leaderId},
+
+ )
+
+
+
+
+ UPDATE sys_department
+ SET del_sign = 1, update_time = NOW()
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+ UPDATE sys_department
+
+ dept_name = #{deptName},
+ dept_code = #{deptCode},
+ parent_id = #{parentId},
+ leader_id = #{leaderId},
+ update_id = #{updateId},
+ remark = #{remark},
+ update_time = NOW()
+
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/PositionMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/PositionMapper.xml
new file mode 100644
index 0000000..e3a475f
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/PositionMapper.xml
@@ -0,0 +1,82 @@
+
+
+
+
+ id, create_id, create_time, update_id, update_time, del_sign, remark
+
+
+ posi_name, posi_code
+
+
+
+ INSERT INTO sys_position (
+ , create_time, update_time, del_sign
+ ) VALUES (
+ #{posiName}, #{posiCode}, NOW(), NOW(), 0
+ )
+
+
+
+ UPDATE sys_position
+ SET del_sign = 1, update_time = NOW()
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+ UPDATE sys_position
+
+ posi_name = #{posiName},
+ posi_code = #{posiCode},
+ update_id = #{updateId},
+ remark = #{remark},
+ update_time = NOW()
+
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/RoleMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/RoleMapper.xml
new file mode 100644
index 0000000..e1e7648
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/RoleMapper.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ id, create_id, create_time, update_id, update_time, del_sign, remark
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO sys_role (
+
+ role_name,
+ role_code,
+ create_id,
+ create_time,
+ update_id,
+ update_time,
+ del_sign,
+ remark,
+
+ )
+ VALUES (
+
+ #{roleName},
+ #{roleCode},
+ #{createId},
+ #{createTime},
+ #{updateId},
+ #{updateTime},
+ #{delSign},
+ #{remark},
+
+ )
+
+
+
+
+ UPDATE sys_role
+
+ role_name = #{roleName},
+ role_code = #{roleCode},
+ update_id = #{updateId},
+ update_time = now(),
+ remark = #{remark},
+
+ WHERE id = #{id}
+
+
+
+
+ DELETE FROM sys_role WHERE id = #{id}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/RolePermissionMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/RolePermissionMapper.xml
new file mode 100644
index 0000000..ba72578
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/RolePermissionMapper.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ id, role_id, permission_id
+
+
+
+
+
+ INSERT INTO sys_role_permission (role_id, permission_id)
+ VALUES (#{roleId}, #{permissionId})
+
+
+
+ DELETE FROM sys_role_permission
+
+
+ role_id = #{roleId}
+
+
+ AND permission_id = #{permissionId}
+
+
+
+
+
+ DELETE FROM sys_role_permission
+ WHERE role_id = #{roleId}
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysDicDataMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysDicDataMapper.xml
new file mode 100644
index 0000000..2ab76dc
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysDicDataMapper.xml
@@ -0,0 +1,74 @@
+
+
+
+
+ id, create_by, create_time, update_by, update_time, del_sign, remark
+
+
+
+ dic_id, dic_label, dic_value
+
+
+
+
+ INSERT INTO sys_dic_data (
+ ,
+ create_by, create_time, update_by, update_time, del_sign
+ ) VALUES (
+ #{dicId}, #{dicLabel}, #{dicValue},
+ #{createId}, NOW(), #{updateId}, NOW(), 0
+ )
+
+
+
+
+ UPDATE sys_dic_data
+
+ dic_id = #{dicId},
+ dic_label = #{dicLabel},
+ dic_value = #{dicValue},
+ update_by = #{updateId},
+ update_time = NOW()
+
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+ UPDATE sys_dic_data
+ SET del_sign = 1, update_time = NOW()
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysDicTypeMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysDicTypeMapper.xml
new file mode 100644
index 0000000..29f9613
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysDicTypeMapper.xml
@@ -0,0 +1,62 @@
+
+
+
+
+ id, create_by, create_time, update_by, update_time, del_sign, remark
+
+
+
+ dic_name, dic_code
+
+
+
+
+ INSERT INTO sys_dic_type (
+ ,
+ create_by, create_time, update_by, update_time, del_sign
+ ) VALUES (
+ #{dicName}, #{dicCode},
+ #{createId}, NOW(), #{updateId}, NOW(), 0
+ )
+
+
+
+
+ UPDATE sys_dic_type
+
+ dic_name = #{dicName},
+ dic_code = #{dicCode},
+ update_by = #{updateId},
+ update_time = NOW()
+
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+ UPDATE sys_dic_type
+ SET del_sign = 1, update_time = NOW()
+ WHERE id = #{id} AND del_sign = 0
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysPermissionMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysPermissionMapper.xml
new file mode 100644
index 0000000..dfba1f9
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/SysPermissionMapper.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO sys_permission
+ (parent_id, permission_name, permission_code, create_id, remark, del_sign)
+ VALUES
+ (#{parentId}, #{permissionName}, #{permissionCode}, #{createId}, #{remark}, 0)
+
+
+
+
+ UPDATE sys_permission
+ SET
+ parent_id = #{parentId},
+ permission_name = #{permissionName},
+ permission_code = #{permissionCode},
+ update_id = #{updateId},
+ remark = #{remark}
+ WHERE id = #{id}
+
+
+
+
+ UPDATE sys_permission SET del_sign = 1 WHERE id = #{id}
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/UserMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/UserMapper.xml
new file mode 100644
index 0000000..27907f9
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/UserMapper.xml
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, create_id, create_time, update_id, update_time, del_sign, remark
+
+
+
+
+ user_name, password, salt, nicke, sex, email_addr, address, telephone, dep_id, pos_id
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO sys_user (
+
+ user_name,
+ password,
+ salt,
+ nicke,
+ sex,
+ email_addr,
+ address,
+ telephone,
+ dep_id,
+ pos_id,
+
+ create_id,
+ create_time,
+ update_id,
+ update_time,
+
+ del_sign,
+ remark,
+
+ ) VALUES (
+
+ #{userName},
+ #{password},
+ #{salt},
+ #{nicke},
+ #{sex},
+ #{emailAddr},
+ #{address},
+ #{telephone},
+ #{depId},
+ #{posId},
+
+ #{createId},
+ #{createTime},
+ #{updateId},
+ #{updateTime},
+
+ #{delSign},
+ #{remark},
+
+ )
+
+
+
+
+ UPDATE sys_user
+
+
+ user_name = #{userName},
+ password = #{password},
+ salt = #{salt},
+ nicke = #{nicke},
+ sex = #{sex},
+ email_addr = #{emailAddr},
+ address = #{address},
+ telephone = #{telephone},
+ dep_id = #{depId},
+ pos_id = #{posId},
+
+ update_id = #{updateId},
+ remark = #{remark},
+ del_sign = #{delSign},
+
+ update_time = NOW()
+
+ WHERE id = #{id}
+
+
+
+
+ UPDATE sys_user
+ SET
+ del_sign = 1,
+ update_time = NOW()
+ , update_id = #{updateId}
+ WHERE id = #{id}
+ AND del_sign = 0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/UserRoleMapper.xml b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/UserRoleMapper.xml
new file mode 100644
index 0000000..b53de42
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/main/resources/mapper/UserRoleMapper.xml
@@ -0,0 +1,69 @@
+
+
+
+
+ id, create_id, create_time, update_id, update_time, del_sign, remark
+
+
+ user_id, role_id
+
+
+
+ INSERT INTO sys_user_role (
+ ,remark, create_time, del_sign
+ ) VALUES (
+ #{userId}, #{roleId}, #{remark},NOW(), 0
+ )
+
+
+
+ DELETE FROM sys_user_role WHERE id = #{id}
+
+
+
+ DELETE FROM sys_user_role WHERE user_id = #{userId}
+
+
+
+ DELETE FROM sys_user_role WHERE role_id = #{roleId}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-admin/src/test/java/com/rczn/RcznAdminApplicationTests.java b/rc_autoplc_backend/rczn-admin/src/test/java/com/rczn/RcznAdminApplicationTests.java
new file mode 100644
index 0000000..aadd54c
--- /dev/null
+++ b/rc_autoplc_backend/rczn-admin/src/test/java/com/rczn/RcznAdminApplicationTests.java
@@ -0,0 +1,13 @@
+package com.rczn;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class RcznAdminApplicationTests {
+
+// @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/rc_autoplc_backend/rczn-autoplc/.mvn/wrapper/maven-wrapper.properties b/rc_autoplc_backend/rczn-autoplc/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..c0bcafe
--- /dev/null
+++ b/rc_autoplc_backend/rczn-autoplc/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,3 @@
+wrapperVersion=3.3.4
+distributionType=only-script
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
diff --git a/rc_autoplc_backend/rczn-autoplc/pom.xml b/rc_autoplc_backend/rczn-autoplc/pom.xml
new file mode 100644
index 0000000..8eb981a
--- /dev/null
+++ b/rc_autoplc_backend/rczn-autoplc/pom.xml
@@ -0,0 +1,100 @@
+
+
+ 4.0.0
+
+ com.rczn
+ Rc-autoplc-backend
+ 0.0.1-SNAPSHOT
+ ../pom.xml
+
+
+ rczn-autoplc
+ rczn-autoplc
+ rczn-autoplc(PLC业务模块)
+ jar
+
+
+
+
+ com.rczn
+ rczn-common
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ true
+
+
+ com.github.pagehelper
+ pagehelper
+ 5.3.3
+ compile
+
+
+
+ org.mybatis
+ mybatis
+ 3.5.14
+ compile
+
+
+ org.springframework.boot
+ spring-boot-test
+ test
+
+
+ org.testng
+ testng
+ 7.11.0
+ test
+
+
+ io.swagger.core.v3
+ swagger-models-jakarta
+ 2.2.19
+ compile
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/IsLandActionParamToPlc.java b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/IsLandActionParamToPlc.java
new file mode 100644
index 0000000..cea8853
--- /dev/null
+++ b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/IsLandActionParamToPlc.java
@@ -0,0 +1,28 @@
+package com.rczn.rcznautoplc.cache;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 1-功能岛>plc地址
+ * 2-动作单元>plc地址
+ * 3-参数名字>plc地址
+ * 三个映射关系Map表
+ */
+public class IsLandActionParamToPlc {
+ // 1-功能岛>plc地址:key-功能岛id,value-功能岛plc地址
+ public static final Map islandToPlc = new HashMap<>();
+
+ // 2-动作单元>plc地址:key-动作单元id,value-动作单元plc地址
+ public static final Map actionToPlc = new HashMap<>();
+
+ // 3-参数名字>plc地址:key-参数名字,value-参数plc地址
+ public static final Map paramToPlc = new HashMap<>();
+
+ //4-参数id>plc地址:key-参数id,value-参数plc地址
+ public static final Map paramIdToPlc = new HashMap<>();
+ //更新三种数据的方法
+ //获取spring里面bean
+ //1-功能岛>plc地址
+
+}
diff --git a/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/PlcRunStatus.java b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/PlcRunStatus.java
new file mode 100644
index 0000000..8478c95
--- /dev/null
+++ b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/PlcRunStatus.java
@@ -0,0 +1,110 @@
+package com.rczn.rcznautoplc.cache;
+
+//样品准备状态
+public class PlcRunStatus {
+ //定容岛:状态属性:
+ public static int goodsScanStatus = 0; //货物扫描:0-准备,1-扫描完毕
+
+ //plc系统运行状态:
+ public static int systemPlcRunStatus = 0; //系统准备:0-未准备,1-空闲,2-忙,4异常
+
+ public static int goodsCount = 0;//样品处理数量
+
+ public static int goodsCurrentIndex = 0;//当前样品处理索引
+
+ //404内照射项目默认样品:尿液,液体:
+ public static String defaultGoodsName = "尿液";
+
+ public static String defaultGoodsType = "液体";
+
+ //目标监测物
+ public static String defaultGoalDetect = "总氮";
+
+ public static class PlcRunStatusResponse{
+ private int goodsScanStatus = 0; //货物扫描:0-准备,1-扫描完毕
+
+ private int systemPlcRunStatus = 0; //系统准备:0-未准备,1-空闲,2-忙,4异常
+
+ private int goodsCount = 0;//样品处理数量
+
+ private int goodsCurrentIndex = 0;//当前样品处理索引
+
+ private String defaultGoodsName = "尿液";//默认样品名称
+
+ private String defaultGoodsType = "液体";//默认样品类型
+
+ private String defaultGoalDetect = "总氮";//默认目标监测物
+
+ public PlcRunStatusResponse() {
+
+ }
+
+ public PlcRunStatusResponse(int goodsScanStatus, int systemPlcRunStatus, int goodsCount, int goodsCurrentIndex, String defaultGoodsName, String defaultGoodsType, String defaultGoalDetect) {
+ this.goodsScanStatus = goodsScanStatus;
+ this.systemPlcRunStatus = systemPlcRunStatus;
+ this.goodsCount = goodsCount;
+ this.goodsCurrentIndex = goodsCurrentIndex;
+ this.defaultGoodsName = defaultGoodsName;
+ this.defaultGoodsType = defaultGoodsType;
+ this.defaultGoalDetect = defaultGoalDetect;
+ }
+
+ public int getGoodsScanStatus() {
+ return goodsScanStatus;
+ }
+
+ public void setGoodsScanStatus(int goodsScanStatus) {
+ this.goodsScanStatus = goodsScanStatus;
+ }
+
+ public int getSystemPlcRunStatus() {
+ return systemPlcRunStatus;
+ }
+
+ public void setSystemPlcRunStatus(int systemPlcRunStatus) {
+ this.systemPlcRunStatus = systemPlcRunStatus;
+ }
+
+ public int getGoodsCount() {
+ return goodsCount;
+ }
+
+ public void setGoodsCount(int goodsCount) {
+ this.goodsCount = goodsCount;
+ }
+
+ public int getGoodsCurrentIndex() {
+ return goodsCurrentIndex;
+ }
+
+ public void setGoodsCurrentIndex(int goodsCurrentIndex) {
+ this.goodsCurrentIndex = goodsCurrentIndex;
+ }
+
+ public String getDefaultGoodsName() {
+ return defaultGoodsName;
+ }
+
+ public void setDefaultGoodsName(String defaultGoodsName) {
+ this.defaultGoodsName = defaultGoodsName;
+ }
+
+ public String getDefaultGoodsType() {
+ return defaultGoodsType;
+ }
+
+ public void setDefaultGoodsType(String defaultGoodsType) {
+ this.defaultGoodsType = defaultGoodsType;
+ }
+
+ public String getDefaultGoalDetect() {
+ return defaultGoalDetect;
+ }
+
+ public void setDefaultGoalDetect(String defaultGoalDetect) {
+ this.defaultGoalDetect = defaultGoalDetect;
+ }
+ }
+}
+
+
diff --git a/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/RegisterAddrDic.java b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/RegisterAddrDic.java
new file mode 100644
index 0000000..d2425b5
--- /dev/null
+++ b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/cache/RegisterAddrDic.java
@@ -0,0 +1,17 @@
+package com.rczn.rcznautoplc.cache;
+
+public class RegisterAddrDic {
+
+ //主PLC:寄存器地址:
+ public final static int goodsScanRegisterArr = 5000;//样品扫描状态寄存器地址:
+
+ //整体运转状态:
+ public final static int wholeRunStatusRegisterArr = 1100;//整体运转状态寄存器地址:
+
+ //协议存储地址:
+ //1-下发plc:样品sop指令协议寄存器地址:
+ public final static int downProtcolRegisterArr = 2000;//协议存储寄存器地址:
+ //2-接收plc:处理样品状态数据协议寄存器地址
+ public final static int upProtcolRegisterArr = 3000;//协议存储寄存器地址:
+
+}
diff --git a/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/controller/DevInfoController.java b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/controller/DevInfoController.java
new file mode 100644
index 0000000..b2bcb38
--- /dev/null
+++ b/rc_autoplc_backend/rczn-autoplc/src/main/java/com/rczn/rcznautoplc/controller/DevInfoController.java
@@ -0,0 +1,185 @@
+package com.rczn.rcznautoplc.controller;
+
+import com.rczn.domain.Result;
+import com.rczn.rcznautoplc.domain.DevInfo;
+import com.rczn.rcznautoplc.service.DevInfoService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springdoc.core.annotations.ParameterObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 设备信息 Controller(RESTful API)
+ */
+@RestController
+@RequestMapping("/devInfo")
+@Tag(name = "动作单元管理", description = "设备增删改查+分页查询+全量查询接口")
+public class DevInfoController {
+
+ @Autowired
+ private DevInfoService devInfoService;
+
+ /**
+ * 新增设备
+ */
+ @PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
+ @Operation(summary = "新增动作单元", description = "动作单元名称为必填项,其他字段可选(非空则入库)")
+ public ResponseEntity