# Conflicts:
#	crmeb/app/services/order/StoreOrderRefundServices.php
#	crmeb/app/services/user/UserBillServices.php
This commit is contained in:
From-wh 2025-09-28 09:30:26 +08:00
commit 7e64ff5fc1
6760 changed files with 380591 additions and 176758 deletions

5
.gitignore vendored
View File

@ -19,3 +19,8 @@
/template/uni-app/node_modules/
/template/uni-app/unpackage/
/template/uni-app/.hbuilderx/
/crmeb/.idea/
/docker-compose/MacArm/mysql/data/
/docker-compose/MacArm/mysql/log/
/docker-compose/linux/mysql/data/
/docker-compose/linux/mysql/log/

876
LICENSE
View File

@ -1,674 +1,202 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is 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. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
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.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
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 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 user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user 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 user 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 user 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 user 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 user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
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. Use with the GNU Affero General Public License.
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 Affero 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 special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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 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 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 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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <2017> <西安众邦网络科技有限公司>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
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 GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2014-2024] [Xi'an Zhongbang Network Technology Co., Ltd]
Licensed 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.

369
README.md
View File

@ -1,178 +1,295 @@
![输入图片说明](readme/pic/gitee.jpg)
<div align="center" >
<img src="https://images.gitee.com/uploads/images/2021/1109/164354_0aafe3d2_892944.gif" />
</div>
<div align="center">
支持免费商用的PHP **多语言** 商城系统
<div align="center" >
<img src="https://www.crmeb.com/static/images/dark_logo.png" />
</div>
<div align="center" style="font-size: 15px;">
CRMEB开源商城系统(PHP版)
</div>
<div align="center" >
<a href="http://www.crmeb.com">
<img src="https://img.shields.io/badge/Licence-GPL3.0-green.svg?style=flat" />
</a>
<a href="http://www.crmeb.com">
<img src="https://img.shields.io/badge/Edition-4.5-blue.svg" />
</a>
<a href="https://gitee.com/ZhongBangKeJi/CRMEB/repository/archive/master.zip">
<img src="https://img.shields.io/badge/Download-150m-red.svg" />
</a>
<a href='https://gitee.com/ZhongBangKeJi/CRMEB/stargazers'>
<img src='https://gitee.com/ZhongBangKeJi/CRMEB/badge/star.svg?theme=gvp' alt='star'></img>
</a>
<a href="http://www.crmeb.com">
<img src="https://img.shields.io/badge/Licence-apache2.0-green.svg?style=flat" />
</a>
<a href="http://www.crmeb.com">
<img src="https://img.shields.io/badge/Edition-5.6.1-blue.svg" />
</a>
<a href="https://gitee.com/ZhongBangKeJi/CRMEB/repository/archive/master.zip">
<img src="https://img.shields.io/badge/Download-240m-red.svg" />
</a>
</div>
####
<div align="center" style="font-size: 15px;">
用心做开源,我们也很需要你的鼓励!右上角Star🌟,等你点亮
</div>
####
<div align="center">
[官网](https://www.crmeb.com/) |
[在线体验](http://v4.crmeb.net/admin/) |
[帮助文档](https://doc.crmeb.com/single/crmeb_v4) |
[技术社区](https://www.crmeb.com/ask/)
[帮助文档](https://doc.crmeb.com/single_open) |
[应用市场](https://www.crmeb.com/market/) |
[技术社区](https://www.crmeb.com/ask/thread/list/147) |
[宽屏预览](https://gitee.com/ZhongBangKeJi/CRMEB/blob/master/README.md)
[comment]: <> ([宽屏预览]&#40;https://gitee.com/ZhongBangKeJi/CRMEB/blob/master/README.md&#41;)
</div>
<div align="center" >
<a href="https://gitee.com/ZhongBangKeJi/CRMEB/blob/master/README.md">宽 屏 预 览</a>
</div>
### 介绍
CRMEB打通版是历经6年时间匠心之作!系统全开源可商用,包含小程序商城、H5商城、公众号商城、PC商城、App,多种分销模式、拼团、砍价、秒杀、优惠券、抽奖、积分、会员等级、小程序直播、页面DIY,前后端分离全部100%开源。方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程。为开发者赋能,助力企业发展、国家富强,致力于打造最受欢迎的商城项目
CRMEB开源商城Java版:https://gitee.com/ZhongBangKeJi/crmeb_java
### 系统亮点
---
### 📝 **项目介绍**
**开源自由**
CRMEB开源商城系统代码100%开源,基于 **Apache-2.0协议** 免费商用,无任何隐藏费用或功能限制,真正实现“零成本”部署与二次开发自由!
**技术架构**
采用 **ThinkPHP 6 + ElementUI + UniApp** 技术栈,前后端分离设计,支持模块化开发与高效维护。前端适配微信小程序、H5、APP、PC等多端,后端统一管理全平台数据,保障流畅体验与高并发性能。
**全场景覆盖**
无缝对接公众号、小程序、H5、APP、PC端,数据实时互通,助力商家一站式运营多渠道业务,满足全场景电商需求。
**原生营销引擎**
内置 **20+核心营销模块**(拼团、砍价、秒杀、优惠券、积分体系、直播带货、付费会员、等级会员、用户充值、分销裂变、渠道码、新人礼等),支持零插件自定义活动规则。通过 **首页DIY功能** ,商家可拖拽式设计商城首页,无需技术背景即可快速搭建高转化场景,实现「所见即所得」的运营效率。
**社区共建计划**
我们致力于打造开发者友好生态,开放源码、持续更新功能模块,并欢迎开发者提交优化建议或贡献代码。通过共享技术成果,降低行业重复造轮子成本,推动开源电商系统的可持续发展。
🔗 <a href="https://doc.crmeb.com/single_open/open_v54/19855" target="_blank">功能列表</a> | 📩 <a href="https://gitee.com/ZhongBangKeJi/CRMEB/issues" target="_blank">提交反馈</a> | 📩 <a href="https://gitee.com/ZhongBangKeJi/CRMEB/pulls" target="_blank">提交代码</a>
---
### 🫧 技术特点
~~~
多 语 言:后台随时配置语言包,移动端支持多语言切换;
高 性 能:redis缓存、队列、长连接、多种云储存、支持集群部署;
个 性 UI:多种风格切换、支持DIY各种首页/专题页面
前后端分离:后端TP6,管理端iviewui,移动端uniapp;
代码规范:遵循PSR-2命名规范、Restful标准接口、代码严格分层、注释齐全、统一错误码;
权限管理:内置强大灵活的权限管理,可以控制到每一个菜单;
开发配置:低代码增加配置、系统组合数据模块;
二开效率:PHP快速生成表单、内置所有事件、后台在线编辑器、代码注释齐全、完整接口文档;
快速上手:详细帮助文档、接口文档、数据库字典、代码注释、一键安装;
系统安全:系统操作日志、系统生产日志、文件校验、数据备份;
系统功能:请看帮助文档 https://doc.crmeb.com/single/crmeb_v4/1758
用户体验:等您来评!
关于二开:
1.代码规范:遵循PSR-2命名规范、Restful标准接口、代码严格分层、注释齐全、统一错误码;
2.权限管理:内置强大灵活的权限管理,可以控制到每一个菜单;
3.开发配置:低代码增加配置、系统组合数据模块;
4.代码生成:快速生成后台菜单、页面,快速实现增删改查;
5.定时任务:系统内置10中定时任务,还有自定义任务,可以自行设置执行周期,执行代码,完美兼容;
6.系统事件:埋入30+系统事件锚点,可在后台页面进行事件添加;
7.在线编辑:可以在后台对系统的代码进行编辑修改操作,不用登录服务器去修改代码文件,方便快捷;
8.接口管理:后台页面可以看到系统中所有的接口数据,并且可以在线调试接口;
9.二开效率:应用form-builder PHP可以快速生成表单;
10.快速上手:后台接口管理、后台数据库字典、系统文件管理备注、代码注释、一键安装;
~~~
~~~
性能与拓展:
1.系统安全:系统操作日志、系统生产日志、文件校验、数据备份;
2.高性能:支持Redis缓存、队列、长连接、多种云储存、支持集群部署;
3.多语言:支持自动识别浏览器多语言展示;
4.驱动扩展:支持多种支付方式、多种短信、多种云储存等;
5.云存储:云存储支持图片和视频的远程云存储,支持阿里云,腾讯云,七牛云,京东云,天翼云,华为云
6.一号通:通用的第三方扩展,支持短信,物流查询,电子面单,电子发票,商品采集,商家寄件
~~~
---
### 运行环境
### 📖 系统功能
```
Nignx/Apache/IIS
PHP 7.1 ~ 7.4
MySQL 5.7
Redis
```
![输入图片说明](readme/pic/核心功能.jpg)
---
### 📖 UI界面展示
![输入图片说明](readme/pic/PHP_06.jpg)
> 温馨提示:虚拟空间不支持,推荐使用bt宝塔面板,服务器推荐阿里云ecs或腾讯云cvm 云服务器:<a href="https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=dligum2z" target="_blank"> 查看 </a>
---
### 📖 后台界面展示
![输入图片说明](readme/pic/PHP_05.jpg)
### 系统演示
---
![输入图片说明](readme/pic/20公众号.jpg)
管理后台: http://v4.crmeb.net/admin 账号:demo 密码:crmeb.com
### 📱 系统演示
H5端:http://v4.crmeb.net/(移动端打开)
![输入图片说明](readme/pic/contact2.jpg)
PC端:http://v4.crmeb.net/(电脑端打开)
管理后台: http://v5.crmeb.net/admin
账号:demo 密码:crmeb.com
H5端:http://v5.crmeb.net/ (移动端打开)
PC端:http://v5.crmeb.net/ (电脑端打开)
APP下载:http://app.crmeb.cn/bzv (苹果手机直接在APP Store里搜索CRMEB下载)
---
> 听说,大神你想看看CRMEB开源项目的完整框架?<a href="https://doc.crmeb.com/single/v5/7712" target="_blank">戳这儿,轻松获取!</a>
#### 体验云部署
不懂服务器?不懂技术?无法解决高并发?想数据私有化?还想后期定制开发?
推荐云部署版一键超低价格低至 :collision: 9.9元/年,解决以上所有问题<a href='https://saas.crmeb.com/saas-home-software-detail-50043-s-y.html' target='_blank'>点击了解 </a>
---
### 官方论坛
产品BUG、优化建议,欢迎社区反馈:https://www.crmeb.com/ask/thread/list?id=147
### 页面展示
(页面仅展示部分UI)
![输入图片说明](readme/pic/gitee开源版详情_01.jpg)
![输入图片说明](readme/pic/gitee开源版详情_02.jpg)
![输入图片说明](readme/pic/gitee开源版详情_03.jpg)
![输入图片说明](readme/pic/gitee开源版详情_04.jpg)
![输入图片说明](readme/pic/gitee开源版详情_05.jpg)
<div align="center">
<a href='http://s.crmeb.com/goods_detail/739' target='_blank'>点击查看高清版全套UI设计图</a>
</div>
### 🔐 **运行环境**
### 推荐项目(欢迎合作,QQ:763569752 )
| 项目名称 | 关注量 | 项目介绍 |
| ------------ | ------------ | ------------ |
| [![](https://img.shields.io/badge/CRMEB-CRMChat-blue.svg)](https://gitee.com/ZhongBangKeJi/CRMChat) | [![](https://gitee.com/ZhongBangKeJi/CRMChat/badge/star.svg)](https://gitee.com/ZhongBangKeJi/CRMChat/stargazers) | CRMChat客服系统,支持接入各种渠道. |
| [![](https://img.shields.io/badge/CRMEB-crmeb_java-blue.svg)](https://gitee.com/ZhongBangKeJi/crmeb_java) | [![](https://gitee.com/ZhongBangKeJi/crmeb_java/badge/star.svg)](https://gitee.com/ZhongBangKeJi/crmeb_java/stargazers) | JAVA版开源商城. |
| [![](https://img.shields.io/badge/xaboy-formbuilder-blue.svg)](https://gitee.com/xaboy/form-builder) | [![](https://gitee.com/xaboy/form-builder/badge/star.svg)](https://gitee.com/xaboy/form-builder/stargazers) | PHP表单生成器,快速生成现代化的form表单。 |
| [![](https://img.shields.io/badge/就眠儀式-LayuiVue-blue.svg)](https://gitee.com/layui/layui-vue) | [![](https://gitee.com/layui/layui-vue/badge/star.svg)](https://gitee.com/layui/layui-vue/stargazers) | layui-vue(谐音:类UI)是一套Vue3.0 的桌面端组件库. |
| [![](https://img.shields.io/badge/逆天的蝈蝈-TpFlow-blue.svg)](https://gitee.com/ntdgg/tpflow) | [![](https://gitee.com/ntdgg/tpflow/badge/star.svg?theme=gvp)](https://gitee.com/ntdgg/tpflow/stargazers) | TpFlow工作流引擎是一套规范化的流程管理系统,基于业务而驱动系统生命力的一套引擎. |
### 商业版购买
开源不易,以下如果有需要,请支持一下,感谢您的支持,让我们更多动力!
[![](readme/pic/gitee2.png)](https://www.crmeb.com/index/criteria)
### 🔥🔥庆祝:CRMEB开源商城系统Gitee star突破10000+ 专属活动福利 [点击了解](https://www.crmeb.com/ask/thread/20738)
### 感谢参与开发者
感谢大神们提交代码(排名不分先后)
@yizhisamoye,@bys1123,@xaboy,@youngxj0,@jacklincheung,@392256866,@sxsea
欢迎反馈问题 [反馈问题](https://gitee.com/ZhongBangKeJi/CRMEB/issues)。
欢迎提交代码 [提交代码](https://gitee.com/ZhongBangKeJi/CRMEB/pulls)。
### 特别鸣谢
排名不分先后,感谢这些软件的开发者:thinkphp、iview、vue、mysql、redis、uniapp、echarts、tree-table-vue、swiper、form-create等,如有遗漏请联系我!
### 核心开发团队
产品:木子刀客
技术:聆听、等风来、xaboy、吴汐、最后一片叶、旺仔、小小、娜娜、归来仍是少年
UI:xy-yyds、LXT
测试:夏天、绵绵羊、。ws
### 使用须知
1.允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;
2.如果商用必须保留版权信息,请自觉遵守;
3.禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负。
### 版权信息
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2017-2023 by CRMEB (https://www.crmeb.com)
All rights reserved。
CRMEB® 商标和著作权所有者为西安众邦网络科技有限公司。
| **运行环境** | **要求** |
|------------------|------------------------------------------------------------------------|
| **操作系统** | Linux / Windows |
| **WEB 服务** | Nginx / Apache / IIS |
| **PHP 版本** | PHP 7.1 ~ 7.4 |
| **数据库** | MySQL 5.7 ~ 8.0(引擎:InnoDB) |
| **缓存** | Redis(可选,不安装则使用文件缓存) |
| **管理器** | Supervisor(用于管理消息队列) |
| **推荐工具** | 宝塔面板(简单易用) |
| **云服务器** | 阿里云 ECS / 腾讯云 CVM / 京东云ECS |
| **开放端口** | 80, 21, 8888, 888, 443, 3306, 6379(授权对象:`0.0.0.0/0`) |
| **PHP 扩展** | fileinfo(可选)、redis(可选) |
| **禁用函数** | `proc_open`, `pcntl_signal`, `pcntl_signal_dispatch`, `pcntl_fork`, `pcntl_wait`, `pcntl_alarm` |
| **消息队列** | 运行命令:`php think queue:listen --queue` (使用Supervisor) |
| **长连接** | 运行命令:`sudo -u www php think workerman start --d` (命令行执行) |
| **定时任务** | 运行命令:`php think timer start --d` (命令行执行) |
> 温馨提示:虚拟空间不支持,推荐使用bt宝塔面板,服务器推荐京东云服务器:<a href="https://partner.jdcloud.com/partner/notice/b06c3232b6394fdfa496923b8e00b286" target="_blank">注册即享6.5折专属优惠,点我领取!</a>
---
### 📺 **开发环境及使用技术**
### **开发环境:**
| 工具 | 版本 | 下载链接 |
|--------------|--------------------|-------------------------------------------------------------------------|
| **PHP** | 7.1-7.4 | [PHP 官方下载](https://www.php.net/downloads.php) |
| **MySQL** | 5.7 | [MySQL 官网](https://www.mysql.com/) |
| **Redis** | 7.0 | [Redis 官网](https://redis.io/download) |
| **Nginx** | 1.22 | [Nginx 官网](http://nginx.org/en/download.html) |
| **Apache** | 2.4 | [Apache HTTP Server](https://httpd.apache.org/download.cgi) |
| **Node.js** | 14/18 | [Node.js LTS 版本](https://nodejs.org/en/download/releases/) |
### 后端技术栈
| **技术** | **名称** | **网址** |
|---------------------|-----------------------------------------------------------------------------|-------------------------------------------------------------------------|
| php扩展库 | PHP 基础运行环境,JSON 数据处理,高精度数学计算等 | https://www.php.net/ |
| topthink | ThinkPHP 视图模板引擎,验证码生成组件,队列任务支持,数据库迁移工具 | https://www.thinkphp.cn/ |
| overtrue | 微信生态开发(公众号/小程序/支付) | https://github.com/w7corp/easywechat |
| php-jwt | JWT 令牌生成与验证 | https://github.com/firebase/php-jwt |
| var-dumper | 调试输出工具(格式化变量) | https://symfony.com/doc/current/components/var_dumper.html |
| phpoffice | 文件处理 | https://github.com/PHPOffice/PhpSpreadsheet |
| guzzlehttp|psr7 | HTTP 客户端库,PSR-7 HTTP 消息接口实现 | https://guzzle-cn.readthedocs.io/zh-cn/latest |
| form-builder | 快速构建表单的 UI 工具 | https://form-create.com |
| workerman | 高性能 Socket 服务器框架,定时任务调度 | https://www.workerman.net |
### 移动端技术栈
| **技术** | **名称** | **官网** |
| --- | --- | --- |
| uniapp | 跨端框架 | https://uniapp.dcloud.net.cn/ |
| vuex | 状态管理库 | https://vuex.vuejs.org/ |
| socket | WebSocket通信 | https://socket.io/ |
| dayjs | 时间处理库 | https://day.js.org/ |
| animate | CSS动画库 | https://animate.style/ |
| easy-loadimage | 图片懒加载 | https://github.com/TSjianjiao/easy-loadimage |
### Admin端技术栈
| **技术** | **名称** | **官网** |
| --- | --- | --- |
| vue2 | Vue框架 | https://v2.vuejs.org/ |
| vuex | 状态管理库 | https://vuex.vuejs.org/ |
| element-ui | UI框架 | https://element.eleme.io/ |
| axios | HTTP客户端 | https://axios-http.com/ |
| vxe-table | 高级表格组件 | https://vxetable.cn/ |
| wangeditor | 富文本编辑器 | https://www.wangeditor.com/ |
| qs | 查询字符串解析 | https://github.com/ljharb/qs |
| xlsx | Excel处理库 | https://sheetjs.com/ |
| sass | CSS预处理器 | https://sass-lang.com/ |
| prettier | 代码格式化 | https://prettier.io/ |
| v-viewer | 图片查看器 | https://github.com/mirari/v-viewer |
### PC端技术栈
| **技术** | **名称** | **官网** |
| --- | --- | --- |
| nuxt | Vue服务端渲染框架 | https://nuxtjs.org/ |
| element | UI框架 | https://element.eleme.io/ |
| axios | HTTP客户端 | https://axios-http.com/ |
| sass | CSS预处理器 | https://sass-lang.com/ |
| cookie-universal-nuxt | Nuxt Cookie处理 | https://github.com/microcipcip/cookie-universal |
| postcss | CSS转换工具 | https://postcss.org/ |
| qs | 查询字符串解析 | https://github.com/ljharb/qs |
### 想要快速安装,教程来助攻!
快速一键安装部署:https://doc.crmeb.com/single_open/open_v54/20366
手动配置安装:https://doc.crmeb.com/single_open/open_v54/20389
docker-compose一键部署:https://doc.crmeb.com/single_open/open_v54/20145
宝塔环境一键安装:https://doc.crmeb.com/single_open/open_v54/19892
### 二开支持:
使用文档:https://doc.crmeb.com/single_open/open_v54/19849
接口文档:https://doc.crmeb.com/single_open/open_v54/21040
数据字典:https://doc.crmeb.com/single_open/open_v54/20136
代码生成:https://doc.crmeb.com/single_open/open_v54/20135
二开文档:https://doc.crmeb.com/single_open/open_v54/19851
视频教程:https://www.bilibili.com/video/BV1kh4y1872K/
技术社区:https://www.crmeb.com/ask/thread/list/147
---
### 📞 CRMEB互动
#### CRMEB开源技术交流群(扫码进群可领取开源版接口文档、产品功能清单、高清UI设计图、思维脑图!)
![输入图片说明](readme/pic/开源群.jpg)
#### 技术社区!找方法、提bug、看官方消息、拿活跃大奖!都在 <a href="https://www.crmeb.com/ask" target="_blank">CRMEB 技术社区</a> 应有尽有
---
### 📕 CRMEB PRO版
[![输入图片说明](readme/pic/PRO版2.jpg)](https://www.crmeb.com/index/pro)
### 📕 CRMEB 多商户版
[![输入图片说明](readme/pic/duoshanghu2.jpg)](https://www.crmeb.com/index/merchant)
---
[返回顶部 :fa-arrow-circle-up: ](https://gitee.com/ZhongBangKeJi/CRMEB#%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D)

View File

@ -1,5 +1,5 @@
version=CRMEB-KY v4.7.0
version_code=470
version=CRMEB-KY v5.6.3
version_code=563
platform=gitee
app_id=ze7x9rxsv09l6pvsyo
app_key=fuF7U9zaybLa5gageVQzxtxQMFnvU2OI

View File

@ -1,4 +1,4 @@
CRMEB v4.5 后端程序目录
CRMEB v5 后端程序目录
===============
> 运行环境要求PHP7.1-7.4。
@ -8,12 +8,10 @@ CRMEB v4.5 后端程序目录
## 一键安装
上传你的代码,站点入口目录设置/public
在浏览器中输入你的域名或IP(例如:www.yourdomain.com),
安装程序会自动执行安装。期间系统会提醒你输入数据库信息以完成安装,安装完成后建议删除install目录下index.php文件或将其改名。
安装程序会自动执行安装。期间系统会提醒你输入数据库信息以完成安装,安装完成后建议删除install目录。
后台访问地址:
1.域名/admin
2.域名/index.php/admin
3.域名/index.php?s=/admin
公众号和H5首页访问地址:
1.域名/
@ -37,32 +35,39 @@ DEFAULT_TIMEZONE = Asia/Shanghai
[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1 #数据库连接地址
HOSTPORT = 3306 #数据库端口
DATABASE = test #数据库名称
USERNAME = username #数据库登录账号
PASSWORD = password #数据库登录密码
HOSTPORT = 3306 #数据库端口
CHARSET = utf8
PREFIX = eb_
CHARSET = utf8mb4
DEBUG = true
[LANG]
default_lang = zh-cn
[CACHE]
DRIVER = file #缓存类型,redis/file
CACHE_PREFIX = cache_xxxx: #缓存前缀
CACHE_TAG_PREFIX = cache_tag_xxxx: #缓存类型前缀
[REDIS]
REDIS_HOSTNAME = 127.0.0.1 # redis链接地址
REDIS_HOSTNAME = 127.0.0.1 #redis链接地址
PORT = 6379 #端口号
REDIS_PASSWORD = 123456 #密码
SELECT = 0 #数据库
[QUEUE]
QUEUE_NAME = xxxx #队列前缀
~~~
3.修改目录权限(linux系统)777
/public
/runtime
/crmeb
/template
4.后台登录:
http://域名/admin
默认账号:admin 密码:crmeb.com
## 消息队列
```sh
php think queue:listen --queue
```
## 消息队列
```sh
@ -98,6 +103,165 @@ php think workerman start --d
- restart: 重启
- --d : 后台执行
## 开发规范
#### 命名规范
ThinkPHP6.0遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:
1. 目录和文件
2. 目录使用小写+下划线;
3. 类库、函数文件统一以.php为后缀;
4. 类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致;
5. 类(包含接口和Trait)文件采用驼峰法命名(首字母大写),其它文件采用小写+下划线命名;
6. 类名(包括接口和Trait)和文件名保持一致,统一采用驼峰法命名(首字母大写);
#### 函数和类、属性命名
1. 类的命名采用驼峰法(首字母大写),例如 User、UserType;
2. common函数的命名使用小写字母和下划线(小写字母开头)的方式,例如 get_client_ip;
3. 控制器里面的方法使用小写字母和下划线(小写字母开头)的方式,例如 get_client_ip
4. 方法的命名使用驼峰法(首字母小写),例如 getUserName;
5. 属性的命名使用驼峰法(首字母小写),例如 tableName、instance;
6. 特例:以双下划线__打头的函数或方法作为魔术方法,例如 __call 和 __autoload;
#### 常量和配置
1. 常量以大写字母和下划线命名,例如 APP_PATH;
2. 配置参数以小写字母和下划线命名,例如 url_route_on 和url_convert;
3. 环境变量定义使用大写字母和下划线命名,例如APP_DEBUG;
#### 数据表和字段
1. 数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如 think_user 表和 user_name字段,不建议使用驼峰和中文作为数据表及字段命名
注意:请理解并尽量遵循以上命名规范,可以减少在开发过程中出现不必要的错误
#### 语法规范
1. 尽量使用php7新语法
2. 每个 namespace 命名空间声明语句和 use 声明语句块后面,必须 插入一个空白行
3. 类的开始花括号({) 必须 写在类声明后自成一行,结束花括号(})也 必须 写在类主体后自成一行
4. 方法的开始花括号({) 必须 写在函数声明后自成一行,结束花括号(})也 必须 写在函数主体后自成一行。
5. 类的属性和方法 必须 添加访问修饰符(private、protected 以及 public),abstract 以及 final 必须 声明在访问修饰符之前,而 static 必须 声明在访问修饰符之后
6. 控制结构的关键字后 必须 要有一个空格符,而调用方法或函数时则 一定不可 有
7. 控制结构的开始花括号({) 必须 写在声明的同一行,而结束花括号(}) 必须 写在主体后自成一行
8. 纯 PHP 代码文件 必须 省略最后的 ?> 结束标签
9. 所有方法,类,控制器类,都 必须 添加访问修饰符
~~~
/**
* 中文注释
* @param string $str 声明类型
* @param array $arr
* @return bool
*/
public function action(string $str, array $arr)
{
return true;
}
~~~
10. 参数列表中,每个逗号后面 必须 要有一个空格,而逗号前面 一定不可 有空格
~~~
function foo($arg1, &$arg2, $arg3 = [])
{
// method body
}
~~~
11. 参数 可以 分列成多行,此时包括第一个参数在内的每个参数都 尽量 单独成行。
~~~
<?php
$foo->bar(
$longArgument,
$longerArgument,
$muchLongerArgument
);
~~~
12. 标准的 if 结构如下代码所示,请留意「括号」、「空格」以及「花括号」的位置,
注意 else 和 elseif 都与前面的结束花括号在同一行
~~~
<?php
if ($expr1) {
// if body
} elseif ($expr2) {
// elseif body
} else {
// else body;
}
~~~
13. 赋值等号前后必须加空格符
~~~
<?php
$arr = [];
~~~
#### PHP 7.1+ 常用新语法
1. 三元运算符
~~~
<?php
$arr = ['crmeb'=>true];
之前
echo isset($arr['crmeb']) ? $arr['crmeb'] : '';
之后
echo $arr['crmeb'] ?? '';
~~~
2. define() 定义常量数组
~~~
<?php
define('ARR',['a','b']);
~~~
3. 命名空间优化
~~~
<?php
//PHP7之前语法
use FooLibrary\Bar\Baz\ClassA;
use FooLibrary\Bar\Baz\ClassB;
// PHP7新语法写法
use FooLibrary\Bar\Baz\{ ClassA, ClassB};
~~~
#### CRMEB PRO规范
1. 所有数据验证放在模块下的 validates 目录下
2. JSON返回使用父级 AuthController类中的success 和 fail
3. 错误判断抛出异常,由一个错误类统一控制输出
~~~
<?php
throw new AuthException('错误信息',400);
~~~
4. 错误码和错误提示语应该统一管理,方便切换多语言
5. 数据库操作使用模型类,不能使用Db::table()
6. 获取表单数据使用 app\Request
~~~
<?php
use app\Request;
public function index(Request $request) {
//获取提交的数据,并以二维数组形式返回
$arr = $request->getMore([
'name',
'nickname'
]);
//获取提交的数据,并以二维数组形式返回并附加默认值
$arr = $request->getMore([
['name','123'],
['nickname','0']
]);
//获取提交的数据,并以一维数组形式返回并附加默认值
[$name, $nickname] = $request->getMore([
['name','123'],
['nickname','0']
],true);
}
~~~
7. 所有控制器类命令和表名对应,按照大驼峰命名规范
8. 所有文件夹命名按照小写字母加下划线定义
9. 所有属性名,变量名尽量遵守小驼峰命名规范
10. 复杂逻辑,多状态应适当添加行内注释
11. 模型里只能写关于搜索条件语句,查出数据得组合书写在services层进行处理,services创建命令:php make:services api@user/User
## 文档
[使用手册](https://doc.crmeb.com)

70
crmeb/app/README.md Normal file
View File

@ -0,0 +1,70 @@
### 系统目录介绍优化方案
#### 1. 引言
在优化系统目录介绍时,我们的目标是使目录结构更加清晰、易于理解,并突出每个目录的核心功能和作用。
#### 2. 目录结构优化概述
我们将通过以下几个步骤来优化目录介绍:
- **明确目录层级**:清晰展示主目录与子目录的关系。
- **突出核心功能**:简要概括每个目录的主要作用和包含的文件类型。
- **增加示例或用途说明**:对于关键目录,提供简短的示例或用途描述,帮助开发者快速理解。
#### 3. 优化后的目录介绍
##### app/
- **核心目录**:存放应用程序的核心代码和资源。
- **包含内容**:业务逻辑、控制器、模型、视图等。
###### app/adminapi/
- **功能**:管理端应用控制器。
- **用途**:处理管理端用户请求、业务逻辑和数据交互。
- **示例**:管理员登录、权限管理等。
###### app/api/
- **功能**:用户端应用控制器。
- **用途**:处理用户端请求、业务逻辑和数据交互。
- **示例**:用户注册、商品浏览等。
###### app/dao/
- **功能**:数据访问对象(DAO)。
- **用途**:封装数据访问操作,提供统一接口。
- **文件类型**:类文件。
###### app/http/
- **功能**:HTTP请求和响应跨域中间键。
- **用途**:处理跨域请求,确保前后端通信顺畅。
###### app/jobs/
- **功能**:消息队列任务。
- **用途**:处理异步任务,如邮件发送、数据同步等。
###### app/kefuapi/
- **功能**:客服端应用控制器。
- **用途**:处理客服端请求、业务逻辑和数据交互。
- **示例**:客服聊天、工单处理等。
###### app/lang/
- **功能**:语言包。
- **用途**:支持多语言功能,提供不同语言的文本资源。
###### app/listener/
- **功能**:事件监听器。
- **用途**:监听和处理系统事件,如用户登录、订单生成等。
###### app/model/
- **功能**:模型类。
- **用途**:封装数据访问操作,提供统一接口。
- **与dao区别**:模型类更侧重于业务逻辑层面的数据操作。
###### app/outapi/
- **功能**:对外接口应用控制器。
- **用途**:处理外部系统请求、业务逻辑和数据交互。
- **示例**:第三方支付回调、API对接等。
###### app/service/
- **功能**:服务类。
- **用途**:封装业务逻辑和数据交互操作,提供统一服务接口。
- **示例**:用户服务、订单服务等。
#### 4. 结语
通过上述优化,我们使`app`目录及其子目录的介绍更加清晰、条理分明。每个目录的核心功能和用途都得到了突出展示,有助于开发者快速理解和定位代码。同时,增加的示例和用途说明也进一步降低了理解门槛,提升了开发效率。

View File

@ -33,7 +33,8 @@ class Request extends \think\Request
* 不过滤变量名
* @var array
*/
protected $except = ['menu_path', 'api_url', 'unique_auth', 'description', 'custom_form', 'content'];
protected $except = ['menu_path', 'api_url', 'unique_auth',
'description', 'custom_form', 'params_list', 'content', 'tableField', 'url', 'customCode', 'value', 'refund_reason_wap_img'];
/**
* 获取请求的数据
@ -48,7 +49,7 @@ class Request extends \think\Request
$i = 0;
foreach ($params as $param) {
if (!is_array($param)) {
$p[$suffix == true ? $i++ : $param] = $this->filterWord(is_string($this->param($param)) ? trim($this->param($param)) : $this->param($param), $filter && !in_array($param, $this->except));
$p[$suffix == true ? $i++ : $param] = $this->param($param);
} else {
if (!isset($param[1])) $param[1] = null;
if (!isset($param[2])) $param[2] = '';
@ -59,41 +60,42 @@ class Request extends \think\Request
$name = is_array($param[1]) ? $param[0] . '/a' : $param[0];
$keyName = $param[0];
}
$p[$suffix == true ? $i++ : ($param[3] ?? $keyName)] = $this->filterWord(is_string($this->param($name, $param[1], $param[2])) ? trim($this->param($name, $param[1], $param[2])) : $this->param($name, $param[1], $param[2]), $filter && !in_array($keyName, $this->except));
$p[$suffix == true ? $i++ : ($param[3] ?? $keyName)] = $this->param($name, $param[1], $param[2]);
}
}
if ($filter && $p) {
$p = $this->filterArrayValues($p);
}
return $p;
}
/**
* 过滤接受的参数
* 过滤接数组中的字符串
* @param $str
* @param bool $filter
* @return array|mixed|string|string[]
*/
public function filterWord($str, bool $filter = true)
public function filterArrayValues($array)
{
if (!$str || !$filter) return $str;
// 把数据过滤
$farr = [
"/<(\\/?)(script|i?frame|style|html|body|title|link|meta|object|\\?|\\%)([^>]*?)>/isU",
"/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
"/select|join|where|drop|like|modify|rename|insert|update|table|database|alter|truncate|\'|\/\*|\.\.\/|\.\/|union|into|load_file|outfile/is"
];
if (is_array($str)) {
foreach ($str as &$v) {
if (is_array($v)) {
foreach ($v as &$vv) {
if (!is_array($vv)) $vv = preg_replace($farr, '', $vv);
}
$result = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
// 如果值是数组,并且不在不过滤变量名里面,递归调用 filterArrayValues,否则直接赋值
$result[$key] = in_array($key, $this->except) ? $value : $this->filterArrayValues($value);
} else {
if (in_array($key, $this->except) || is_int($value) || is_null($value)) {
$result[$key] = $value;
} else {
$v = preg_replace($farr, '', $v);
// 如果值是字符串,过滤特殊字符
$result[$key] = filter_str($value);
}
}
} else {
$str = preg_replace($farr, '', $str);
}
return $str;
return $result;
}
/**
@ -176,7 +178,7 @@ class Request extends \think\Request
}
/**
* 是否是app端
* 是否是pc端
* @return bool
*/
public function isPc()

View File

@ -17,6 +17,7 @@ use crmeb\exceptions\ApiException;
use crmeb\exceptions\AuthException;
use think\db\exception\DbException;
use think\exception\Handle;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\facade\Env;
use think\facade\Log;
@ -45,26 +46,30 @@ class AdminApiExceptionHandle extends Handle
public function report(Throwable $exception): void
{
if (!$this->isIgnoreReport($exception)) {
$data = [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $this->getMessage($exception),
'code' => $this->getCode($exception),
];
try {
$data = [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $this->getMessage($exception),
'code' => $this->getCode($exception),
];
//日志内容
$log = [
request()->adminId(), //管理员ID
request()->ip(), //客户ip
ceil(msectime() - (request()->time(true) * 1000)), //耗时(毫秒)
request()->rule()->getMethod(), //请求类型
str_replace("/", "", request()->rootUrl()), //应用
request()->baseUrl(), //路由
json_encode(request()->param(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),//请求参数
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), //报错数据
//日志内容
$log = [
request()->adminId(), //管理员ID
request()->ip(), //客户ip
ceil(msectime() - (request()->time(true) * 1000)), //耗时(毫秒)
request()->rule()->getMethod(), //请求类型
str_replace("/", "", request()->rootUrl()), //应用
request()->baseUrl(), //路由
json_encode(request()->param(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),//请求参数
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), //报错数据
];
Log::write(implode("|", $log), "error");
];
Log::write(implode("|", $log), "error");
} catch (\Throwable $e) {
Log::write($e->getMessage(), "error");
}
}
}
@ -77,6 +82,9 @@ class AdminApiExceptionHandle extends Handle
*/
public function render($request, Throwable $e): Response
{
if ($e instanceof HttpResponseException) {
return parent::render($request, $e);
}
$massageData = Env::get('app_debug', false) ? [
'message' => $e->getMessage(),
'file' => $e->getFile(),
@ -84,7 +92,7 @@ class AdminApiExceptionHandle extends Handle
'trace' => $e->getTrace(),
'previous' => $e->getPrevious(),
] : [];
$message = Env::get('app_debug', false) ? $e->getMessage() : '很抱歉,系统开小差了';
$message = $e->getMessage();
// 添加自定义异常处理机制
if ($e instanceof AuthException || $e instanceof AdminException || $e instanceof ApiException || $e instanceof ValidateException) {
return app('json')->make($e->getCode() ?: 400, $message, $massageData);

View File

@ -0,0 +1,17 @@
crmeb/app/adminapi这个目录主要是后台管理系统的API接口文件。
具体来说:
- adminapi目录下的文件都是后台管理系统的控制器(Controller)文件,这些控制器被用来处理后台系统的各种请求。
- 每一个控制器文件对应后台管理系统某个功能模块,比如AuthController处理认证模块请求,StoreProduct处理商品模块请求等。
- 控制器内有各种方法,这些方法就相当于API接口,可以处理GET、POST请求,返回JSON数据。
- 浏览器或APP在调用这些API接口时,会发送请求到相应的控制器方法,例如登录接口请求到Login文件的login方法。
- 控制器处理完请求后,通过返回Response对象返回处理结果给浏览器或APP。
所以简单来说,adminapi目录负责后台管理系统的所有API接口,这些接口被APP或前端调用来完成各种管理操作,如查询数据、添加修改删除等。开发者在新增后台功能时,也需要在此目录增加对应的控制器和接口。
它实际上负责后台系统的通信交互层,解耦了后端逻辑和前端展示,采用 RESTful规范设计。

View File

@ -126,13 +126,21 @@ if (!function_exists('attr_format')) {
$result = [];
foreach ($temp as $item) {
foreach ($arr[$i + 1]['detail'] as $datum) {
$result[] = trim($item) . ',' . trim($datum);
if (is_array($item)) {
$result[] = trim($item['value']) . ',' . trim($datum['value']);
} else {
$result[] = trim($item) . ',' . trim($datum);
}
}
}
}
} else {
foreach ($arr[0]['detail'] as $item) {
$result[] = trim($item);
if (is_array($item)) {
$result[] = trim($item['value']);
} else {
$result[] = trim($item);
}
}
}
}

View File

@ -11,6 +11,7 @@
namespace app\adminapi\controller;
use app\services\system\config\SystemConfigServices;
use app\services\system\config\SystemConfigTabServices;
use app\services\system\SystemAuthServices;
use app\services\order\StoreOrderServices;
use app\services\product\product\StoreProductServices;
@ -20,8 +21,9 @@ use app\services\user\UserExtractServices;
use app\services\product\sku\StoreProductAttrValueServices;
use app\services\system\SystemMenusServices;
use app\services\user\UserServices;
use crmeb\services\CacheService;
use crmeb\services\HttpService;
use think\facade\Cache;
use think\facade\Config;
/**
* 公共接口基类 主要存放公共接口
@ -58,34 +60,6 @@ class Common extends AuthController
'version' => $version
]);
$res = $res ? json_decode($res, true) : [];
//兼容test.
if ($res['data']['status'] !== 1) {
$host = str_replace('test.', '', $host);
$res = HttpService::request('http://authorize.crmeb.net/api/auth_cert_query', 'post', [
'domain_name' => $host,
'label' => 34,
'version' => $version
]);
$res = $res ? json_decode($res, true) : [];
}
//如果是主域名兼容www.
if ($res['data']['status'] !== 1) {
$host = str_replace('www.', '', $host);
$res = HttpService::request('http://authorize.crmeb.net/api/auth_cert_query', 'post', [
'domain_name' => $host,
'label' => 34,
'version' => $version
]);
$res = $res ? json_decode($res, true) : [];
}
//升级状态
/** @var UpgradeServices $upgradeServices */
$upgradeServices = app()->make(UpgradeServices::class);
$upgradeStatus = $upgradeServices->getUpgradeStatus();
$status = $res['data']['status'] ?? -9;
switch ((int)$status) {
case 1:
@ -164,15 +138,26 @@ class Common extends AuthController
return app('json')->success(compact('info'));
}
//增长率
/**
* 计算增长率
* 特殊情况:
* 1. 当前值和上期值均为0时,返回0;
* 2. 上期值为0时,返回当前值;
* 3. 当前值为0时,返回上期值的负数。
*
* @param float $nowValue 当前值
* @param float $lastValue 上期值
* @return float 增长率
*/
public function growth($nowValue, $lastValue)
{
if ($lastValue == 0 && $nowValue == 0) return 0;
if ($lastValue == 0) return round($nowValue, 2);
if ($nowValue == 0) return -round($lastValue, 2);
return bcmul(bcdiv((bcsub($nowValue, $lastValue, 2)), $lastValue, 2), 100, 2);
if ($lastValue == 0 && $nowValue == 0) return 0;
if ($lastValue == 0) return round($nowValue, 2);
if ($nowValue == 0) return -round($lastValue, 2);
return bcmul(bcdiv((bcsub($nowValue, $lastValue, 2)), $lastValue, 2), 100, 2);
}
/**
* 订单图表
*/
@ -235,29 +220,29 @@ class Common extends AuthController
if ($data['ordernum'] != 0) {
$value[] = [
'title' => "您有$data[ordernum]个待发货的订单",
'type' => 'bulb',
'url' => '/admin/order/list?status=1'
'type' => 1,
'url' => '/' . Config::get('app.admin_prefix', 'admin') . '/order/list?status=1'
];
}
if ($data['inventory'] != 0) {
$value[] = [
'title' => "您有$data[inventory]个商品库存预警",
'type' => 'information',
'url' => '/admin/product/product_list?type=5',
'type' => 2,
'url' => '/' . Config::get('app.admin_prefix', 'admin') . '/product/product_list?type=5',
];
}
if ($data['commentnum'] != 0) {
$value[] = [
'title' => "您有$data[commentnum]条评论待回复",
'type' => 'bulb',
'url' => '/admin/product/product_reply?is_reply=0'
'type' => 3,
'url' => '/' . Config::get('app.admin_prefix', 'admin') . '/product/product_reply?is_reply=0'
];
}
if ($data['reflectnum'] != 0) {
$value[] = [
'title' => "您有$data[reflectnum]个提现申请待审核",
'type' => 'bulb',
'url' => '/admin/finance/user_extract/index?status=0',
'type' => 4,
'url' => '/' . Config::get('app.admin_prefix', 'admin') . '/finance/user_extract/index?status=0',
];
}
return app('json')->success($this->noticeData($value));
@ -346,6 +331,7 @@ class Common extends AuthController
$pid = $item->getData('pid');
$data[$key] = json_decode($item, true);
$data[$key]['pid'] = $pid;
$data[$key]['menu_path'] = '/' . config('app.admin_prefix', 'admin') . $item['menu_path'];
if (in_array($item->id, $counts)) {
$data[$key]['type'] = 1;
} else {
@ -401,8 +387,76 @@ class Common extends AuthController
'info' => ''
]);
}
CacheService::clear();
return app('json')->success(100000);
}
/**
* 系统搜索菜单
* @return \think\Response
* @author 吴汐
* @email 442384644@qq.com
* @date 2024/2/1
*/
public function menusSearch()
{
// 从请求中获取关键字
[$keyword] = $this->request->postMore([
['keyword', ''],
], true);
if (empty($keyword)) {
return app('json')->fail(400239, '关键字不能为空');
}
// 获取系统菜单服务实例
$menusServices = app()->make(SystemMenusServices::class);
// 查询菜单列表
$menusList = $menusServices->selectList([['menu_name', 'like', '%' . $keyword . '%'], ['auth_type', '=', 1]], 'menu_name as title,menu_path as path,id')->toArray();
// 获取系统配置服务实例
$configServices = app()->make(SystemConfigServices::class);
// 获取系统配置标签服务实例
$configTabServices = app()->make(SystemConfigTabServices::class);
// 查询配置项列表
$configList = $configServices->selectList([['info', 'like', '%' . $keyword . '%']], 'info as title,config_tab_id')->toArray();
// 查询配置项标签列表
$configTabList = $configTabServices->selectList([['title', 'like', '%' . $keyword . '%']], 'title,id as config_tab_id')->toArray();
// 合并配置项列表和配置项标签列表
$configAllList = array_merge($configList, $configTabList);
// 获取配置项对应的标签ID
$tabIds = array_unique(array_column($configAllList, 'config_tab_id'));
// 查询配置项标签列表
$tabList = $configTabServices->getColumn([['id', 'in', $tabIds]], 'menus_id', 'id');
// 将配置项标签列表中的菜单ID与配置项列表中的菜单ID对应起来
foreach ($configAllList as &$item1) {
$item1['menus_id'] = $tabList[$item1['config_tab_id']] ?? 0;
}
// 获取配置项标签对应的菜单ID
$configTabIds = array_values($tabList);
// 查询配置项标签对应的菜单列表
$configMenusList = $menusServices->getColumn([['id', 'in', $configTabIds]], 'menu_name as title,menu_path as path,id', 'id');
// 将配置项列表中的菜单ID与配置项标签对应的菜单ID对应起来
foreach ($configAllList as $item2) {
if ($item2['menus_id'] == 0) {
continue;
}
$menusList[] = [
'title' => $configMenusList[$item2['menus_id']]['title'] . '-' . $item2['title'],
'path' => $configMenusList[$item2['menus_id']]['path'] . '?tab_id=' . $item2['config_tab_id'],
'id' => $configMenusList[$item2['menus_id']]['id']
];
}
// 将菜单列表中的路径前缀添加到每个菜单项的 path 属性上
$adminPrefix = '/' . Config::get('app.admin_prefix', 'admin');
foreach ($menusList as &$item) {
if (strpos($item['path'], '/') !== 0) {
$item['path'] = $adminPrefix . '/' . ltrim($item['path'], '/');
} else {
$item['path'] = $adminPrefix . $item['path'];
}
}
// 返回 JSON 格式的菜单列表
return app('json')->success($menusList);
}
}

View File

@ -101,10 +101,14 @@ class Login extends AuthController
}
}
if (strlen(trim($password)) < 6 || strlen(trim($password)) > 32) {
return app('json')->fail(400762);
}
$this->validate(['account' => $account, 'pwd' => $password], \app\adminapi\validate\setting\SystemAdminValidata::class, 'get');
$result = $this->services->login($account, $password, 'admin', $key);
if (!$result) {
$num = CacheService::get('login_captcha',1);
$num = CacheService::get('login_captcha', 1);
if ($num > 1) {
return app('json')->fail(400140, ['login_captcha' => 1]);
}

View File

@ -12,8 +12,13 @@
namespace app\adminapi\controller;
use app\Request;
use app\services\system\attachment\SystemAttachmentServices;
use app\services\system\SystemRouteServices;
use crmeb\services\CacheService;
use think\facade\Env;
use think\Response;
use think\facade\Db;
class PublicController
{
@ -23,8 +28,13 @@ class PublicController
* @param string $key
* @return Response|\think\response\File
*/
public function download(string $key = '')
public function download(Request $request, string $key = '')
{
if ($key == '') {
$key = $request->getMore([
['key', ''],
], true);
}
if (!$key) {
return Response::create()->code(500);
}
@ -44,4 +54,99 @@ class PublicController
{
return app('json')->success(getWorkerManUrl());
}
/**
* 扫码上传
* @param Request $request
* @param int $upload_type
* @param int $type
* @return Response
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/06/13
*/
public function scanUpload(Request $request, $upload_type = 0, $type = 0)
{
[$file, $uploadToken, $pid] = $request->postMore([
['file', 'file'],
['uploadToken', ''],
['pid', 0]
], true);
$service = app()->make(SystemAttachmentServices::class);
if (CacheService::get('scan_upload') != $uploadToken) {
return app('json')->fail(410086);
}
$service->upload((int)$pid, $file, $upload_type, $type, '', $uploadToken);
return app('json')->success(100032);
}
public function import(Request $request)
{
$filePath = $request->param('file_path', '');
if (empty($filePath)) {
return app('json')->fail(12894);
}
app()->make(SystemRouteServices::class)->import($filePath);
return app('json')->success(100010);
}
/**
* 服务器信息
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/9/24
*/
public function getSystemInfo()
{
$info['server'] = [
['name' => '服务器系统', 'require' => '类UNIX', 'value' => PHP_OS],
['name' => 'WEB环境', 'require' => 'Apache/Nginx/IIS', 'value' => $_SERVER['SERVER_SOFTWARE']],
];
$gd_info = function_exists('gd_info') ? gd_info() : array();
$info['environment'] = [
['name' => 'PHP版本', 'require' => '7.1-7.4', 'value' => phpversion()],
['name' => 'MySql版本', 'require' => '5.6-8.0', 'value' => Db::query("SELECT VERSION()")[0]['VERSION()']],
['name' => 'MySqli', 'require' => '开启', 'value' => function_exists('mysqli_connect')],
['name' => 'Openssl', 'require' => '开启', 'value' => function_exists('openssl_encrypt')],
['name' => 'Session', 'require' => '开启', 'value' => function_exists('session_start')],
['name' => 'Safe_Mode', 'require' => '开启', 'value' => !ini_get('safe_mode')],
['name' => 'GD', 'require' => '开启', 'value' => !empty($gd_info['GD Version'])],
['name' => 'Curl', 'require' => '开启', 'value' => function_exists('curl_init')],
['name' => 'Bcmath', 'require' => '开启', 'value' => function_exists('bcadd')],
['name' => 'Upload', 'require' => '开启', 'value' => (bool)ini_get('file_uploads')],
];
$info['permissions'] = [
['name' => 'backup', 'require' => '读写', 'value' => is_readable(root_path('backup')) && is_writable(root_path('backup'))],
['name' => 'public', 'require' => '读写', 'value' => is_readable(root_path('public')) && is_writable(root_path('public'))],
['name' => 'runtime', 'require' => '读写', 'value' => is_readable(root_path('runtime')) && is_writable(root_path('runtime'))],
['name' => '.env', 'require' => '读写', 'value' => is_readable(root_path() . '.env') && is_writable(root_path() . '.env')],
['name' => '.version', 'require' => '读写', 'value' => is_readable(root_path() . '.version') && is_writable(root_path() . '.version')],
['name' => '.constant', 'require' => '读写', 'value' => is_readable(root_path() . '.constant') && is_writable(root_path() . '.constant')],
];
if (function_exists('exec')) {
$workermanOutput = $timerOutput = $queueOutput = [];
exec("ps aux | grep 'php think workerman' | grep -v grep", $workermanOutput);
exec("ps aux | grep 'php think timer' | grep -v grep", $timerOutput);
exec("ps aux | grep 'php think queue' | grep -v grep", $queueOutput);
$info['process'] = [
['name' => '长链接', 'require' => '开启', 'value' => count($workermanOutput) > 0],
['name' => '定时任务', 'require' => '开启', 'value' => count($timerOutput) > 0],
['name' => '消息队列', 'require' => '开启', 'value' => count($queueOutput) > 0],
];
} else {
$info['process'] = [
['name' => '长链接', 'require' => '开启', 'value' => file_exists(root_path('runtime') . 'workerman.pid')],
['name' => '定时任务', 'require' => '开启', 'value' => file_exists(root_path('runtime') . '.timer')],
['name' => '消息队列', 'require' => '开启', 'value' => file_exists(root_path('runtime') . '.queue')],
];
}
return app('json')->success($info);
}
public function customAdminJs()
{
return sys_config('custom_admin_js', '');
}
}

File diff suppressed because it is too large Load Diff

View File

@ -69,13 +69,13 @@ class AgentLevel extends AuthController
['name', ''],
['grade', 0],
['image', ''],
['one_brokerage', 0],
['two_brokerage', 0],
['one_brokerage_percent', 0],
['two_brokerage_percent', 0],
['status', 0]]);
if (!$data['name']) return app('json')->fail(400200);
if (!$data['grade']) return app('json')->fail(400201);
if (!$data['image']) return app('json')->fail(400202);
if ($data['two_brokerage'] > $data['one_brokerage']) {
if ($data['two_brokerage_percent'] > $data['one_brokerage_percent']) {
return app('json')->fail(400203);
}
$grade = $this->services->get(['grade' => $data['grade'], 'is_del' => 0]);
@ -121,13 +121,13 @@ class AgentLevel extends AuthController
['name', ''],
['grade', 0],
['image', ''],
['one_brokerage', 0],
['two_brokerage', 0],
['one_brokerage_percent', 0],
['two_brokerage_percent', 0],
['status', 0]]);
if (!$data['name']) return app('json')->fail(400200);
if (!$data['grade']) return app('json')->fail(400201);
if (!$data['image']) return app('json')->fail(400202);
if ($data['two_brokerage'] > $data['one_brokerage']) {
if ($data['two_brokerage_percent'] > $data['one_brokerage_percent']) {
return app('json')->fail(400203);
}
if (!$levelInfo = $this->services->getLevelInfo((int)$id)) return app('json')->fail(400206);
@ -139,8 +139,8 @@ class AgentLevel extends AuthController
$levelInfo->name = $data['name'];
$levelInfo->grade = $data['grade'];
$levelInfo->image = $data['image'];
$levelInfo->one_brokerage = $data['one_brokerage'];
$levelInfo->two_brokerage = $data['two_brokerage'];
$levelInfo->one_brokerage_percent = $data['one_brokerage_percent'];
$levelInfo->two_brokerage_percent = $data['two_brokerage_percent'];
$levelInfo->status = $data['status'];
$levelInfo->save();
return app('json')->success(100001);
@ -184,4 +184,35 @@ class AgentLevel extends AuthController
$this->services->update($id, ['status' => $status]);
return app('json')->success(100014);
}
/**
* 获取任务表单数量
* @param int $id 任务ID
* @return \think\response\Json
*/
public function getTaskNumForm($id)
{
// 判断任务ID是否为0,若为0则返回错误信息
if ($id == 0) return app('json')->fail(100100);
// 调用服务层获取任务表单数量
$result = $this->services->getTaskNumForm($id);
// 返回成功信息和任务表单数量
return app('json')->success($result);
}
/**
* 设置任务数量
* @param int $id 任务ID
* @return \think\response\Json
*/
public function setTaskNum($id)
{
// 从请求中获取任务数量
$data = $this->request->postMore([
['task_num', 0]
]);
// 调用服务层设置任务数量
$res = $this->services->setTaskNum($id, $data);
return app('json')->success(100014);
}
}

View File

@ -11,6 +11,7 @@
namespace app\adminapi\controller\v1\agent;
use app\adminapi\controller\AuthController;
use app\services\agent\AgentLevelServices;
use app\services\agent\AgentLevelTaskServices;
use think\facade\App;
@ -93,6 +94,10 @@ class AgentLevelTask extends AuthController
$this->services->checkTypeTask(0, $data);
$data['add_time'] = time();
$this->services->save($data);
$levelInfo = app()->make(AgentLevelServices::class)->get((int)$data['level_id']);
$levelInfo->task_num = $levelInfo->task_num + 1;
$levelInfo->task_total_num = $levelInfo->task_total_num + 1;
$levelInfo->save();
return app('json')->success(400210);
}
@ -162,8 +167,15 @@ class AgentLevelTask extends AuthController
$levelTaskInfo = $this->services->getLevelTaskInfo((int)$id);
if ($levelTaskInfo) {
$res = $this->services->update($id, ['is_del' => 1]);
if (!$res)
if ($res) {
$levelInfo = app()->make(AgentLevelServices::class)->get((int)$levelTaskInfo['level_id']);
$levelInfo->task_num = $levelInfo->task_num - 1;
$levelInfo->task_total_num = $levelInfo->task_total_num - 1;
if ($levelInfo->task_num <= 0) $levelInfo->task_num = $levelInfo->task_total_num;
$levelInfo->save();
} else {
return app('json')->fail(100008);
}
}
return app('json')->success(100002);
}

View File

@ -60,7 +60,7 @@ class AgentManage extends AuthController
public function get_badge()
{
$where = $this->request->getMore([
['data', ''],
['data', '', '', 'time'],
['nickname', ''],
]);
return app('json')->success(['res' => $this->services->getSpreadBadge($where)]);
@ -228,7 +228,7 @@ class AgentManage extends AuthController
$userInfo->spread_time = time();
$userInfo->division_id = $spreadInfo->division_id;
$userInfo->agent_id = $spreadInfo->agent_id;
$userInfo->is_staff = $spreadInfo->is_staff;
$userInfo->staff_id = $spreadInfo->staff_id;
$userInfo->save();
return app('json')->success(100001);
}

View File

@ -99,8 +99,9 @@ class Division extends AuthController
['account', ''],
['pwd', ''],
['conf_pwd', ''],
['real_name', ''],
['roles', []]
['division_name', ''],
['roles', []],
['image', []]
]);
$this->services->divisionSave($data);
return app('json')->success(100000);
@ -121,19 +122,32 @@ class Division extends AuthController
* 保存代理商
* @param UserServices $userServices
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function divisionAgentSave(UserServices $userServices)
{
$data = $this->request->postMore([
['division_id', 0],
['uid', 0],
['division_percent', 0],
['division_end_time', ''],
['division_status', 1],
['division_name', ''],
['edit', 0],
['image', []],
]);
$userInfo = $userServices->get((int)$data['uid']);
if ((int)$data['uid'] == 0) $data['uid'] = $data['image']['uid'];
$userInfo = $userServices->getUserInfo($data['uid'], 'is_division,is_agent,is_staff');
if (!$userInfo) throw new AdminException(100100);
$data['division_id'] = $this->adminInfo['division_id'];
if ($data['edit'] == 0) {
if ($userInfo['is_division']) throw new AdminException('此用户是事业部,请勿添加为代理商');
if ($userInfo['is_agent']) throw new AdminException('此用户是代理商,无法重复添加');
if ($userInfo['is_staff']) throw new AdminException('此用户是下级员工,无法添加为代理商');
$divisionUserInfo = $userServices->count(['uid' => (int)$data['division_id'], 'is_division' => 1, 'division_id' => $data['division_id']]);
if (!$divisionUserInfo) throw new AdminException(100100);
}
$this->services->divisionAgentSave($data);
return app('json')->success(100000);
}
@ -236,4 +250,63 @@ class Division extends AuthController
$applyServices->delApply($id);
return app('json')->success(100002);
}
/**
* 添加员工表单
* @param $uid
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @author 吴汐
* @email 442384644@qq.com
* @date 2024/1/22
*/
public function divisionStaffCreate($uid)
{
return app('json')->success($this->services->getDivisionStaffForm((int)$uid));
}
/**
* 保存员工
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2024/1/22
*/
public function divisionStaffSave()
{
$data = $this->request->getMore([
['uid', 0],
['division_percent', 0],
['agent_id', 0],
['image', []],
]);
$this->services->divisionStaffSave($data);
return app('json')->success(100000);
}
/**
* 分销统计
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2025/4/8
*/
public function divisionStatistics()
{
[$type, $time, $page, $limit, $sort, $order] = $this->request->getMore([
['type', 0],
['time', ''],
['page', 1],
['limit', 15],
['sort', 'order_sum'],
['order', 'desc'],
], true);
$time = $time != '' ? explode('-', $time) : [];
$data = $this->services->divisionStatistics($type, $time, $page, $limit, $sort, $order);
return app('json')->success($data);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace app\adminapi\controller\v1\agent;
use app\adminapi\controller\AuthController;
use app\services\agent\SpreadApplyServices;
use think\facade\App;
class SpreadApply extends AuthController
{
public function __construct(App $app, SpreadApplyServices $services)
{
parent::__construct($app);
$this->services = $services;
}
public function applyList()
{
$where = $this->request->getMore([
['status', ''],
['keyword', ''],
]);
return app('json')->success($this->services->applyList($where));
}
public function applyExamine($id, $uid, $status)
{
[$refusal_reason] = $this->request->postMore([
['refusal_reason', ''],
], true);
$this->services->applyExamine($id, $uid, $status, $refusal_reason);
return app('json')->success($status == 1 ? '审核通过' : '拒绝成功');
}
public function applyDelete($id)
{
$this->services->applyDelete($id);
return app('json')->success('删除成功');
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace app\adminapi\controller\v1\application\routine;
use app\adminapi\controller\AuthController;
use app\services\wechat\RoutineSchemeServices;
use think\facade\App;
class RoutineScheme extends AuthController
{
public function __construct(App $app, RoutineSchemeServices $services)
{
parent::__construct($app);
$this->services = $services;
}
public function schemeList()
{
$where = $this->request->postMore([
['title', ''],
]);
return app('json')->success($this->services->schemeList($where));
}
public function schemeForm($id)
{
return app('json')->success($this->services->schemeForm($id));
}
public function schemeSave($id)
{
$data = $this->request->postMore([
['title', ''],
['path', ''],
['expire_type', -1],
['expire_num', 0],
]);
$this->services->schemeSave($id, $data);
return app('json')->success(100000);
}
public function schemeDel($id)
{
$res = $this->services->delete($id);
if (!$res) return app('json')->fail(100008);
return app('json')->success(100002);
}
}

View File

@ -11,8 +11,8 @@
namespace app\adminapi\controller\v1\application\routine;
use app\jobs\notice\SyncMessageJob;
use app\services\message\SystemNotificationServices;
use app\services\other\QrcodeServices;
use app\services\message\TemplateMessageServices;
use app\services\system\attachment\SystemAttachmentServices;
use crmeb\exceptions\AdminException;
use think\exception\ValidateException;
@ -34,9 +34,9 @@ class RoutineTemplate extends AuthController
* 构造方法
* WechatTemplate constructor.
* @param App $app
* @param TemplateMessageServices $services
* @param SystemNotificationServices $services
*/
public function __construct(App $app, TemplateMessageServices $services)
public function __construct(App $app, SystemNotificationServices $services)
{
parent::__construct($app);
$this->services = $services;
@ -54,16 +54,17 @@ class RoutineTemplate extends AuthController
if (!sys_config('routine_appId') || !sys_config('routine_appsecret')) {
throw new AdminException(400236);
}
$all = $this->services->getTemplateList(['status' => 1, 'type' => 0]);
$list = MiniProgramService::getSubscribeTemplateList();
foreach ($list->data as $v) {
MiniProgramService::delSubscribeTemplate($v['priTmplId']);
}
if ($all['list']) {
foreach ($all['list'] as $template) {
SyncMessageJob::dispatch('SyncSubscribe', [$template]);
}
$tempKeys = $this->services->getTempKey('routine');
foreach ($tempKeys as $key => $content) {
SyncMessageJob::dispatch('SyncSubscribe', [$key, $content]);
}
return app('json')->success(100038);
}

View File

@ -50,6 +50,7 @@ class Menus extends AuthController
public function save()
{
$buttons = request()->post('button/a', []);
if(strlen($buttons[0]['name']) > 15) return app('json')->fail('菜单名称不能大于5个字');
if (!count($buttons)) return app('json')->fail(400238);
$this->services->saveMenu($buttons);
return app('json')->success(100001);

View File

@ -63,6 +63,7 @@ class Reply extends AuthController
['key', ''],
['type', ''],
]);
$where['key_type'] = 0;
$list = $this->services->getKeyAll($where);
return app('json')->success($list);
}

View File

@ -179,9 +179,15 @@ class WechatNewsCategory extends AuthController
$errorLog[] = $v['nickname'] . '没有关注发送失败(不是微信公众号用户)';
}
}
} else return app('json')->fail(100031);
if (!count($errorLog)) return app('json')->success(100030);
else return app('json')->success(100030);
if (!count($errorLog)) {
return app('json')->success(100030);
} else {
return app('json')->fail(100031);
}
} else {
return app('json')->fail(100031);
}
}
}

View File

@ -12,8 +12,8 @@ namespace app\adminapi\controller\v1\application\wechat;
use app\adminapi\controller\AuthController;
use app\jobs\notice\SyncMessageJob;
use app\services\message\SystemNotificationServices;
use crmeb\exceptions\AdminException;
use app\services\message\TemplateMessageServices;
use crmeb\services\app\WechatService;
use think\facade\App;
@ -28,9 +28,9 @@ class WechatTemplate extends AuthController
* 构造方法
* WechatTemplate constructor.
* @param App $app
* @param TemplateMessageServices $services
* @param SystemNotificationServices $services
*/
public function __construct(App $app, TemplateMessageServices $services)
public function __construct(App $app, SystemNotificationServices $services)
{
parent::__construct($app);
$this->services = $services;
@ -48,13 +48,16 @@ class WechatTemplate extends AuthController
if (!sys_config('wechat_appid') || !sys_config('wechat_appsecret')) {
throw new AdminException(400248);
}
$all = $this->services->getTemplateList(['status' => 1, 'type' => 1]);
$list = WechatService::getPrivateTemplates();
foreach ($list->template_list as $v) {
WechatService::deleleTemplate($v['template_id']);
$tempIds = $this->services->getTempId('wechat');
foreach ($tempIds as $v) {
WechatService::deleleTemplate($v);
}
foreach ($all['list'] as $template) {
SyncMessageJob::dispatch('SyncWechat', [$template]);
$tempKeys = $this->services->getTempKey('wechat');
foreach ($tempKeys as $key => $content) {
SyncMessageJob::dispatch('SyncWechat', [$key, $content['wechat_content']]);
}
return app('json')->success(100038);
}

View File

@ -40,6 +40,10 @@ class Article extends AuthController
/**
* 获取列表
* @return mixed
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
@ -81,6 +85,10 @@ class Article extends AuthController
* 获取单个文章数据
* @param int $id
* @return mixed
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function read($id = 0)
{

View File

@ -87,6 +87,7 @@ class ArticleCategory extends AuthController
$data['add_time'] = time();
$this->service->save($data);
CacheService::delete('ARTICLE_CATEGORY');
CacheService::delete('ARTICLE_CATEGORY_PC');
return app('json')->success(100021);
}
@ -121,6 +122,7 @@ class ArticleCategory extends AuthController
]);
$this->service->update($data);
CacheService::delete('ARTICLE_CATEGORY');
CacheService::delete('ARTICLE_CATEGORY_PC');
return app('json')->success(100001);
}
@ -135,6 +137,7 @@ class ArticleCategory extends AuthController
if (!$id) return app('json')->fail(100100);
$this->service->del($id);
CacheService::delete('ARTICLE_CATEGORY');
CacheService::delete('ARTICLE_CATEGORY_PC');
return app('json')->success(100002);
}
@ -150,6 +153,7 @@ class ArticleCategory extends AuthController
if ($status == '' || $id == 0) return app('json')->fail(100100);
$this->service->setStatus($id, $status);
CacheService::delete('ARTICLE_CATEGORY');
CacheService::delete('ARTICLE_CATEGORY_PC');
return app('json')->success(100014);
}
@ -165,6 +169,7 @@ class ArticleCategory extends AuthController
/**
* 树形列表
* @return mixed
* @throws \ReflectionException
*/
public function getTreeList()
{

View File

@ -347,6 +347,27 @@ class Diy extends AuthController
return $info;
}
/**
* 推荐商品展示
* @param $type
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/3/11
*/
public function getGroomList($type)
{
[$page, $limit] = $this->request->getMore([
['page', 1],
['limit', 6],
], true);
$list = $this->get_groom_list($type, $limit);
return app('json')->success($list);
}
/**
* 获取uni-app路径
* @return mixed
@ -355,9 +376,13 @@ class Diy extends AuthController
{
$url = sys_data('uni_app_link');
if ($url) {
foreach ($url as &$link) {
$model_checkbox = sys_config('model_checkbox', ['seckill', 'bargain', 'combination']);
foreach ($url as $key => &$link) {
$link['url'] = $link['link'];
$link['parameter'] = trim($link['param']);
if (!in_array('seckill', $model_checkbox) && strpos($link['name'], '秒杀') !== false) unset($url[$key]);
if (!in_array('bargain', $model_checkbox) && strpos($link['name'], '砍价') !== false) unset($url[$key]);
if (!in_array('combination', $model_checkbox) && strpos($link['name'], '拼团') !== false) unset($url[$key]);
}
} else {
/** @var CacheServices $cache */
@ -585,6 +610,8 @@ class Diy extends AuthController
['status', 0],
['order_status', 0],
['my_banner_status', 0],
['my_menus_status', 0],
['business_status', 0],
['routine_my_banner', []],
['routine_my_menus', []]
]);

View File

@ -0,0 +1,151 @@
<?php
namespace app\adminapi\controller\v1\diy;
use app\adminapi\controller\AuthController;
use app\services\diy\DiyProServices;
use app\services\product\product\StoreProductServices;
use think\facade\App;
class DiyPro extends AuthController
{
public function __construct(App $app, DiyProServices $services)
{
parent::__construct($app);
$this->services = $services;
}
public function getList()
{
return app('json')->success($this->services->getList());
}
public function getInfo($id = 0)
{
if ($id == 0) return app('json')->fail('参数错误');
return app('json')->success($this->services->getInfo($id));
}
public function saveInfo($id = 0)
{
$data = $this->request->postMore([
['name', ''],
['title', ''],
['value', ''],
['type', 1],
['cover_image', ''],
['is_show', 0],
['is_bg_color', 0],
['is_bg_pic', 0],
['bg_tab_val', 0],
['color_picker', ''],
['bg_pic', ''],
['is_diy', 1],
['is_pro', 1],
['type', 2],
]);
$value = is_string($data['value']) ? json_decode($data['value'], true) : $data['value'];
foreach ($value as &$item) {
if ($item['name'] === 'goodList') {
if (isset($item['selectConfig']['list'])) {
unset($item['selectConfig']['list']);
}
if (isset($item['goodsList']['list']) && is_array($item['goodsList']['list'])) {
$limitMax = config('database.page.limitMax', 50);
if (isset($item['numConfig']['val']) && isset($item['tabConfig']['tabVal']) && $item['tabConfig']['tabVal'] == 0 && $item['numConfig']['val'] > $limitMax) {
return app('json')->fail('您设置得商品个数超出系统限制,最大限制' . $limitMax . '个商品');
}
$item['goodsList']['ids'] = array_column($item['goodsList']['list'], 'id');
unset($item['goodsList']['list'], $item['productList']['list']);
}
} elseif ($item['name'] === 'articleList') {
if (isset($item['selectList']['list']) && is_array($item['selectList']['list'])) {
unset($item['selectList']['list']);
}
} elseif ($item['name'] === 'promotionList') {
if (isset($item['tabConfig']['list']) && $item['tabConfig']['list']) {
$list = $item['tabConfig']['list'];
foreach ($list as &$tabValue) {
if (isset($tabValue['goodsList']['list']) && is_array($tabValue['goodsList']['list'])) {
$limitMax = config('database.page.limitMax', 50);
if (isset($tabValue['numConfig']['val']) && isset($tabValue['tabConfig']['tabVal']) && $tabValue['tabConfig']['tabVal'] == 0 && $tabValue['numConfig']['val'] > $limitMax) {
return app('json')->fail('您设置得商品个数超出系统限制,最大限制' . $limitMax . '个商品');
}
$tabValue['goodsList']['ids'] = array_column($tabValue['goodsList']['list'], 'id');
}
unset($tabValue['goodsList']['list'], $tabValue['productList']['list']);
}
$item['tabConfig']['list'] = $list;
}
} elseif ($item['name'] === 'newVip') {
unset($item['newVipList']['list']);
} elseif ($item['name'] === 'shortVideo') {
unset($item['videoList']);
}
}
$data['value'] = json_encode($value);
$data['version'] = uniqid();
return app('json')->success($id ? '修改成功' : '保存成功', ['id' => $this->services->saveInfo($id, $data)]);
}
public function delInfo($id)
{
$this->services->delInfo($id);
return app('json')->success('删除成功');
}
public function setInfoStatus($id)
{
return app('json')->success($this->services->setInfoStatus($id));
}
public function getProduct()
{
$where = $this->request->getMore([
['cate_id', []],//搜索分类
['salesOrder', ''],//销量排序
['priceOrder', ''],//价格排序
['store_label_id', []],//标签ID
['ids', []],//商品ID
]);
$where['is_show'] = 1;
$where['is_del'] = 0;
[$page, $limit] = $this->services->getPageValue();
$list = app()->make(StoreProductServices::class)->getSearchList($where, $page, $limit, ['id,store_name,cate_id,image,IFNULL(sales, 0) + IFNULL(ficti, 0) as sales,price,stock,activity,ot_price,spec_type,recommend_image,unit_name,is_vip,vip_price']);
return app('json')->success($list);
}
public function updateName($id = 0)
{
[$name] = $this->request->postMore([
['name', '']
], true);
if (!$name) return app('json')->fail('请输入名称');
$this->services->updateName($id, $name);
return app('json')->success('修改成功');
}
public function exportDIYData($id)
{
$value = $this->services->exportDIYData($id);
$filename = 'DIY数据_' . date('YmdHis', time()) . '.txt';
return app('json')->success('导出成功', ['value' => $value, 'filename' => $filename]);
}
public function importDIYData()
{
// 获取文件
$file = $this->request->file('file');
if (!$file) return app('json')->fail('请上传文件');
// 获取文件的临时路径
$tempPath = $file->getRealPath();
// 使用文件流读取内容
$content = file_get_contents($tempPath);
// 保存内容
$this->services->importDIYData($content);
return app('json')->success('导入成功');
}
}

View File

@ -12,6 +12,7 @@
namespace app\adminapi\controller\v1\diy;
use app\adminapi\controller\AuthController;
use app\services\diy\DiyProServices;
use app\services\diy\DiyServices;
use app\services\diy\PageCategoryServices;
use app\services\diy\PageLinkServices;
@ -112,4 +113,77 @@ class PageLink extends AuthController
return app('json')->success(100002);
}
public function getLinkCategory()
{
return app('json')->success(app()->make(PageCategoryServices::class)->getSonCategoryList(1));
}
public function getLinkCategoryForm($cate_id, $pid)
{
return app('json')->success(app()->make(PageCategoryServices::class)->getLinkCategoryForm($cate_id, $pid));
}
public function getLinkCategorySave($cate_id)
{
$data = $this->request->postMore([
['pid', 0],
['name', ''],
['type', ''],
['sort', 0],
['status', ''],
]);
$res = app()->make(PageCategoryServices::class)->getLinkCategorySave($cate_id, $data);
return app('json')->success('保存成功');
}
public function getLinkCategoryDel($cate_id)
{
$res = app()->make(PageCategoryServices::class)->getLinkCategoryDel($cate_id);
return app('json')->success('删除成功');
}
public function getLinkList($cate_id, PageCategoryServices $pageCategoryServices)
{
if (!$cate_id) return app('json')->fail('参数错误');
$category = $pageCategoryServices->get((int)$cate_id);
if (!$category) {
return app('json')->fail(400103);
}
switch ($category['type']) {
case 'special':
/** @var DiyProServices $diyServices */
$diyProServices = app()->make(DiyProServices::class);
$data = $diyProServices->getList('link');
break;
case 'product_category':
/** @var StoreCategoryServices $storeCategoryServices */
$storeCategoryServices = app()->make(StoreCategoryServices::class);
$data = $storeCategoryServices->getList(['cate_name' => '', 'pid' => '', 'is_show' => '']);
break;
default:
$data = $this->services->getLinkList(['cate_id' => $cate_id]);
break;
}
return app('json')->success($data);
}
public function getLinkSave($id)
{
$data = $this->request->postMore([
['cate_id', 0],
['name', ''],
['url', ''],
['sort', 0],
['status', 1],
]);
$this->services->getLinkSave($id, $data);
return app('json')->success('保存成功');
}
public function getLinkDel($id)
{
$this->services->del($id);
return app('json')->success('删除成功');
}
}

View File

@ -72,7 +72,8 @@ class ExportExcel extends AuthController
['label_id', ''],
['now_money', 'normal'],
['field_key', ''],
['isMember', '']
['isMember', ''],
['ids', []]
]);
return app('json')->success($this->service->exportUserList($where));
}
@ -95,12 +96,25 @@ class ExportExcel extends AuthController
['pay_type', ''],
['order', ''],
['field_key', ''],
['ids', []],
]);
$where['is_system_del'] = 0;
$where['pid'] = 0;
return app('json')->success($this->service->exportOrderList($where));
}
/**
* 发货订单列表导出
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function orderDeliveryList()
{
return app('json')->success($this->service->exportOrderDeliveryList());
}
/**
* 商品列表导出
* @return mixed
@ -110,7 +124,8 @@ class ExportExcel extends AuthController
$where = $this->request->getMore([
['store_name', ''],
['cate_id', ''],
['type', 1]
['type', 1],
['ids', []]
]);
return app('json')->success($this->service->exportProductList($where));
}
@ -206,6 +221,7 @@ class ExportExcel extends AuthController
['price_max', ''],
['price_min', ''],
['excel', '1'],
['time', ''],
]);
$data = $services->getCommissionList($where, false);
return app('json')->success($this->service->userCommission($data['list'] ?? []));

View File

@ -12,6 +12,7 @@ namespace app\adminapi\controller\v1\file;
use app\adminapi\controller\AuthController;
use app\services\system\attachment\SystemAttachmentServices;
use crmeb\services\CacheService;
use think\facade\App;
/**
@ -43,7 +44,9 @@ class SystemAttachment extends AuthController
public function index()
{
$where = $this->request->getMore([
['pid', 0]
['pid', 0],
['real_name', ''],
['type', 0],
]);
return app('json')->success($this->service->getImageList($where));
}
@ -135,4 +138,89 @@ class SystemAttachment extends AuthController
$res = $this->service->videoUpload($data, $_FILES['file']);
return app('json')->success($res);
}
/**
* 获取扫码上传页面链接以及参数
* @return \think\Response
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/06/13
*/
public function scanUploadQrcode()
{
[$pid] = $this->request->getMore([
['pid', 0]
], true);
$uploadToken = md5(time());
CacheService::set('scan_upload', $uploadToken, 600);
$url = sys_config('site_url') . '/app/upload?pid=' . $pid . '&token=' . $uploadToken;
return app('json')->success(['url' => $url]);
}
/**
* 删除二维码
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/6/26
*/
public function removeUploadQrcode()
{
CacheService::delete('scan_upload');
return app('json')->success();
}
/**
* 获取扫码上传的图片数据
* @param $scan_token
* @return \think\Response
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/06/13
*/
public function scanUploadImage($scan_token)
{
return app('json')->success($this->service->scanUploadImage($scan_token));
}
/**
* 网络图片上传
* @return \think\Response
* @throws \Exception
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/06/13
*/
public function onlineUpload()
{
$data = $this->request->postMore([
['pid', 0],
['images', []]
]);
$this->service->onlineUpload($data);
return app('json')->success(100032);
}
public function videoDataSave()
{
$data = $this->request->postMore([
['pid', 0],
['video_name', ''],
['video_path', '']
]);
$this->service->attachmentAdd(
$data['video_name'],
0,
'video/mp4',
$data['video_path'],
$data['video_path'],
$data['pid'],
(int)sys_config('upload_type', 1),
time(),
1,
1,
$data['video_name']
);;
return app('json')->success(100032);
}
}

View File

@ -38,15 +38,21 @@ class SystemAttachmentCategory extends AuthController
/**
* 显示资源列表
* @return mixed
* @return \think\Response
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$where = $this->request->getMore([
['name', ''],
['pid', 0]
['pid', 0],
['all', 0],
['type', 0],
]);
if ($where['name'] != '') $where['pid'] = '';
if ($where['name'] != '' || $where['all'] == 1) $where['pid'] = '';
return app('json')->success($this->service->getAll($where));
}
@ -55,9 +61,13 @@ class SystemAttachmentCategory extends AuthController
* @return mixed
* @throws \FormBuilder\Exception\FormBuilderException
*/
public function create($id)
public function create()
{
return app('json')->success($this->service->createForm($id));
[$id, $type] = $this->request->getMore([
['id', 0],
['type', 0],
], true);
return app('json')->success($this->service->createForm($id, $type));
}
/**
@ -68,8 +78,10 @@ class SystemAttachmentCategory extends AuthController
{
$data = $this->request->postMore([
['pid', 0],
['name', '']
['name', ''],
['type', 0],
]);
if (is_array($data['pid'])) $data['pid'] = end($data['pid']);
if (!$data['name']) {
return app('json')->fail(400100);
}
@ -99,9 +111,13 @@ class SystemAttachmentCategory extends AuthController
['pid', 0],
['name', '']
]);
if (is_array($data['pid'])) $data['pid'] = end($data['pid']);
if (!$data['name']) {
return app('json')->fail(400100);
}
if ($data['pid'] == $id) {
return app('json')->fail('上级分类不能是自己');
}
$info = $this->service->get($id);
$count = $this->service->count(['pid' => $id]);
if ($count && $info['pid'] != $data['pid']) return app('json')->fail(400105);

View File

@ -135,6 +135,15 @@ class UserExtract extends AuthController
public function adopt($id)
{
if (!$id) app('json')->fail(100100);
return app('json')->success($this->services->adopt((int)$id) ? 100014 : 100015);
$res = $this->services->adopt((int)$id);
if ($res) {
if ($res === 'v3_extract') {
return app('json')->success('提现成功,等待用户确认收款');
} else {
return app('json')->success('提现成功');
}
} else {
return app('json')->success('操作失败');
}
}
}

View File

@ -43,7 +43,8 @@ class Express extends AuthController
public function index()
{
$where = $this->request->getMore([
['keyword', '']
['keyword', ''],
['is_show', '']
]);
return app('json')->success($this->services->getExpressList($where));
}
@ -102,12 +103,6 @@ class Express extends AuthController
['sort', 0],
['is_show', 0]]);
if (!$expressInfo = $this->services->get($id)) return app('json')->fail(100026);
if ($expressInfo['partner_id'] == 1 && !$data['account']) {
return app('json')->fail(400402);
}
if ($expressInfo['partner_key'] == 1 && !$data['key']) {
return app('json')->fail(400403);
}
if ($expressInfo['net'] == 1 && !$data['net_name']) {
return app('json')->fail(400404);
}

View File

@ -62,7 +62,11 @@ class StoreService extends AuthController
['data', '', '', 'time'],
['type', '', '', 'user_type'],
]);
[$list, $count] = $services->getWhereUserList($where, 'u.nickname,u.uid,u.avatar as headimgurl,w.subscribe,w.province,w.country,w.city,w.sex,u.user_type,u.is_del');
$where['is_del'] = 0;
[$list, $count] = $services->getWhereUserList($where, 'u.nickname,u.uid,u.avatar as headimgurl,w.subscribe,w.province,w.country,w.city,w.sex,u.user_type,u.is_del,u.phone,u.add_time');
foreach ($list as &$item) {
$item['add_time'] = date('Y-m-d', $item['add_time']);
}
return app('json')->success(compact('list', 'count'));
}

View File

@ -0,0 +1,82 @@
<?php
/**
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/8/3
*/
namespace app\adminapi\controller\v1\kefu;
use app\adminapi\controller\AuthController;
use app\services\wechat\WechatReplyServices;
class StoreServiceAutoReply extends AuthController
{
/**
* @return \think\Response
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/8/3
*/
public function autoReplyList()
{
$where = $this->request->getMore([
['key', ''],
['type', ''],
]);
$where['key_type'] = 1;
$list = app()->make(WechatReplyServices::class)->getKeyAll($where);
return app('json')->success($list);
}
/**
* 获取自动回复表单
* @param int $id
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/8/3
*/
public function autoReplyForm($id = 0)
{
return app('json')->success(app()->make(WechatReplyServices::class)->autoReplyForm($id));
}
/**
* 保存自动回复
* @param int $id
* @return \think\Response
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/8/3
*/
public function autoReplySave($id = 0)
{
$data = $this->request->postMore([
['keys', ''],
['type', ''],
['data', ''],
['status', 1],
]);
app()->make(WechatReplyServices::class)->autoReplySave($id, $data);
return app('json')->success(100000);
}
/**
* 删除自动回复
* @param $id
* @return \think\Response
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/8/3
*/
public function autoReplyDel($id)
{
app()->make(WechatReplyServices::class)->autoReplyDel($id);
return app('json')->success(100002);
}
}

View File

@ -0,0 +1,117 @@
<?php
/**
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/7/31
*/
namespace app\adminapi\controller\v1\marketing;
use app\adminapi\controller\AuthController;
use app\services\system\SystemSignRewardServices;
use think\facade\App;
class SignRewards extends AuthController
{
/**
* @param App $app
* @param SystemSignRewardServices $services
*/
public function __construct(App $app, SystemSignRewardServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 签到奖励列表
* @return \think\Response
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/7/31
*/
public function index()
{
[$type] = $this->request->getMore([
['type', 0]
], true);
$data = $this->services->getList($type);
return app('json')->success($data);
}
/**
* 新增签到奖励
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/7/31
*/
public function addRewards()
{
[$type] = $this->request->getMore([
['type', 0]
], true);
$data = $this->services->rewardsForm(0, $type);
return app('json')->success($data);
}
/**
* 修改签到奖励
* @param $id
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/7/31
*/
public function editRewards($id)
{
$data = $this->services->rewardsForm($id);
return app('json')->success($data);
}
/**
* 保存签到奖励
* @param $id
* @return \think\Response
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/7/31
*/
public function saveRewards($id)
{
$data = $this->request->postMore([
['type', 0],
['days', 0],
['point', 0],
['exp', 0]
]);
$this->services->saveRewards($id, $data);
return app('json')->success(100000);
}
/**
* 删除签到奖励
* @param $id
* @return \think\Response
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/7/31
*/
public function delRewards($id)
{
$this->services->delete($id);
return app('json')->success(100002);
}
}

View File

@ -47,6 +47,7 @@ class StoreBargain extends AuthController
['start_status', ''],
['status', ''],
['store_name', ''],
['product_id', 0],
]);
$where['is_del'] = 0;
$list = $this->services->getStoreBargainList($where);
@ -65,6 +66,7 @@ class StoreBargain extends AuthController
['info', ''],
['unit_name', ''],
['section_time', []],
['image', ''],
['images', []],
['bargain_max_price', 0],
['bargain_min_price', 0],
@ -87,6 +89,7 @@ class StoreBargain extends AuthController
['postage', 0],//邮费
['custom_form', ''],
['virtual_type', 0],
['is_commission', 0],
]);
$this->validate($data, \app\adminapi\validate\marketing\StoreBargainValidate::class, 'save');
if ($data['section_time']) {
@ -151,9 +154,16 @@ class StoreBargain extends AuthController
{
/** @var StoreBargainUserServices $bargainUserService */
$bargainUserService = app()->make(StoreBargainUserServices::class);
$bargainUserService->userBargainStatusFail($id, false);
if ($status == 0) {
$bargainUserService->userBargainStatusFail($id, false);
} else {
$info = $this->services->get($id);
if ($info['stop_time'] < time()) {
return app('json')->fail('活动已结束,无法继续上架');
}
}
$this->services->update($id, ['status' => $status]);
return app('json')->success($status == 0 ? 100001 : 100007);
return app('json')->success(100001);
}
/**
@ -181,7 +191,7 @@ class StoreBargain extends AuthController
{
/** @var StoreBargainUserHelpServices $bargainUserHelpService */
$bargainUserHelpService = app()->make(StoreBargainUserHelpServices::class);
$list = $bargainUserHelpService->getHelpList($id);
$list = $bargainUserHelpService->getHelpList((int)$id);
return app('json')->success(compact('list'));
}

View File

@ -42,7 +42,8 @@ class StoreCombination extends AuthController
$where = $this->request->getMore([
['start_status', ''],
['is_show', ''],
['store_name', '']
['store_name', ''],
['product_id', 0]
]);
$where['is_del'] = 0;
$list = $this->services->systemPage($where);
@ -86,6 +87,7 @@ class StoreCombination extends AuthController
[['title', 's'], ''],
[['info', 's'], ''],
[['unit_name', 's'], ''],
['image', ''],
['images', []],
['section_time', []],
[['is_host', 'd'], 0],
@ -160,8 +162,14 @@ class StoreCombination extends AuthController
*/
public function set_status($id, $status)
{
if ($status == 1) {
$info = $this->services->get($id);
if ($info['stop_time'] < time()) {
return app('json')->fail('活动已结束,无法继续上架');
}
}
$this->services->update($id, ['is_show' => $status]);
return app('json')->success($status == 0 ? 100014 : 100015);
return app('json')->success('设置成功');
}
/**
@ -182,7 +190,11 @@ class StoreCombination extends AuthController
/**
* 拼团人列表
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function order_pink($id)
{
@ -207,12 +219,20 @@ class StoreCombination extends AuthController
* 活动参与人
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function combinationStatisticsList($id)
{
$where = $this->request->getMore([
['real_name', '', '', 'keyword'],
['status', '']
]);
$where['cid'] = $id;
/** @var StorePinkServices $storePinkServices */
$storePinkServices = app()->make(StorePinkServices::class);
$list = $storePinkServices->systemPage(['cid' => $id]);
$list = $storePinkServices->systemPage($where);
return app('json')->success($list);
}
@ -229,4 +249,23 @@ class StoreCombination extends AuthController
]);
return app('json')->success($this->services->combinationStatisticsOrder($id, $where));
}
/**
* 立即成团
* @param $id
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2025/6/18
*/
public function immediatelyCombination($id)
{
/** @var StorePinkServices $storePinkServices */
$storePinkServices = app()->make(StorePinkServices::class);
$storePinkServices->virtualCombination($id, 'admin');
return app('json')->success('成团成功');
}
}

View File

@ -41,8 +41,9 @@ class StoreCouponIssue extends AuthController
$where = $this->request->getMore([
['status', 1],
['coupon_title', ''],
['receive_type', ''],
['receive_type', '', '', 'receive_types'],
['type', ''],
['coupon_type', ''],
]);
$list = $this->services->getCouponIssueList($where);
return app('json')->success($list);
@ -55,6 +56,7 @@ class StoreCouponIssue extends AuthController
public function saveCoupon()
{
$data = $this->request->postMore([
['id', 0],
['coupon_title', ''],
['coupon_price', 0.00],
['use_min_price', 0.00],
@ -72,6 +74,7 @@ class StoreCouponIssue extends AuthController
['sort', 0],
['status', 0],
['receive_limit', 1],
['user_type', 1],
]);
$res = $this->services->saveCoupon($data);
if ($res) return app('json')->success(100000);
@ -99,6 +102,13 @@ class StoreCouponIssue extends AuthController
if (!$id) return app('json')->fail(100100);
$info = $this->services->get($id);
if ($info) $info = $info->toArray();
if ($info['receive_type'] == 1 || $info['receive_type'] == 3) {
$info['user_type'] = 1;
}
if ($info['receive_type'] == 4) {
$info['user_type'] = 2;
$info['receive_type'] = 1;
}
if ($info['product_id'] != '') {
$productIds = explode(',', $info['product_id']);
/** @var StoreProductServices $product */

View File

@ -12,6 +12,7 @@ namespace app\adminapi\controller\v1\marketing;
use app\adminapi\controller\AuthController;
use app\services\activity\seckill\StoreSeckillServices;
use app\services\activity\StoreActivityServices;
use app\services\product\sku\StoreProductAttrValueServices;
use crmeb\services\CacheService;
use think\facade\App;
@ -41,7 +42,11 @@ class StoreSeckill extends AuthController
$where = $this->request->getMore([
['start_status', ''],
[['status', 's'], ''],
[['store_name', 's'], '']
[['store_name', 's'], ''],
[['product_id', 'd'], 0],
['activity_name', ''],
['time', ''],
['time_ids', []],
]);
return app('json')->success($this->services->systemPage($where));
}
@ -75,7 +80,7 @@ class StoreSeckill extends AuthController
[['status', 'd'], 0],
[['num', 'd'], 0],
[['once_num', 'd'], 0],
[['time_id', 'd'], 0],
['time_id', []],
[['temp_id', 'd'], 0],
[['sort', 'd'], 0],
[['description', 's'], ''],
@ -87,6 +92,7 @@ class StoreSeckill extends AuthController
['postage', 0],//邮费
['custom_form', ''],
['virtual_type', 0],
['is_commission', 0],
]);
$this->validate($data, \app\adminapi\validate\marketing\StoreSeckillValidate::class, 'save');
$this->services->saveData($id, $data);
@ -106,10 +112,7 @@ class StoreSeckill extends AuthController
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
$unique = $storeProductAttrValueServices->value(['product_id' => $id, 'type' => 1], 'unique');
if ($unique) {
$name = 'seckill_' . $unique . '_1';
/** @var CacheService $cache */
$cache = app()->make(CacheService::class);
$cache->del($name);
CacheService::delete('seckill_' . $unique . '_1');
}
return app('json')->success(100002);
}
@ -122,6 +125,12 @@ class StoreSeckill extends AuthController
*/
public function set_status($id, $status)
{
if ($status == 1) {
$info = $this->services->get($id);
if ($info['stop_time'] < time()) {
return app('json')->fail('活动已结束,无法继续上架');
}
}
$this->services->update($id, ['status' => $status]);
return app('json')->success(100014);
}
@ -133,12 +142,21 @@ class StoreSeckill extends AuthController
public function time_list()
{
$list['data'] = sys_data('routine_seckill_time');
foreach ($list['data'] as &$item) {
$startTime = sprintf("%02d:00", $item['time']);
$endTime = sprintf("%02d:00", $item['time'] + $item['continued']);
$item['time_name'] = $startTime . '-' . $endTime;
}
return app('json')->success(compact('list'));
}
/**
* 秒杀统计
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function seckillStatistics($id)
{
@ -154,7 +172,7 @@ class StoreSeckill extends AuthController
public function seckillPeople($id)
{
[$keyword] = $this->request->getMore([
['keyword', '']
['real_name', '', '', 'keyword']
], true);
return app('json')->success($this->services->seckillPeople($id, $keyword));
}
@ -172,4 +190,50 @@ class StoreSeckill extends AuthController
]);
return app('json')->success($this->services->seckillOrder($id, $where));
}
public function seckillActivityList()
{
$where = $this->request->getMore([
['time', ''],
['status', ''],
['title', ''],
['time_ids', []]
]);
$where['is_del'] = 0;
$where['type'] = 1;
return app('json')->success(app()->make(StoreActivityServices::class)->activityList($where));
}
public function seckillActivityInfo($id)
{
return app('json')->success(app()->make(StoreActivityServices::class)->activityInfo($id));
}
public function seckillActivitySave($id)
{
$data = $this->request->postMore([
['title', ''],
['section_time', []],
['time_ids', []],
['num', 0],
['once_num', 0],
['status', 1],
['is_commission', 0],
['product_infos', []]
]);
$this->services->seckillActivitySave($id, $data);
return app('json')->success('保存成功');
}
public function seckillActivityDel($id)
{
app()->make(StoreActivityServices::class)->activityDel($id, 1);
return app('json')->success('删除成功');
}
public function seckillActivityStatus($id, $status)
{
app()->make(StoreActivityServices::class)->activityStatus($id, $status, 1);
return app('json')->success('修改成功');
}
}

View File

@ -326,7 +326,7 @@ class StoreIntegralOrder extends AuthController
*/
public function order_dump($order_id, StoreOrderDeliveryServices $storeOrderDeliveryServices)
{
return app('json')->success($storeOrderDeliveryServices->orderDump($order_id));
return app('json')->success($storeOrderDeliveryServices->orderDump($order_id, 'integral_order'));
}

View File

@ -37,7 +37,7 @@ class StorePointRecord extends AuthController
{
$where = $this->request->getMore([
['time', ''],
['trading_type', 0]
['trading_type', '']
]);
$date = $this->services->pointRecord($where);
return app('json')->success($date);

View File

@ -72,9 +72,14 @@ class LiveGoods extends AuthController
[$goods_info] = $this->request->postMore([
['goods_info', []]
], true);
$error = false;
foreach ($goods_info as $goods) {
$this->validate($goods, \app\adminapi\validate\marketing\LiveGoodsValidate::class, 'save');
if (!preg_match('/.*(\.png|\.jpg|\.jpeg|\.gif)$/', $goods['image']) && strpos(strtolower($goods['image']), "phar://") !== false) {
$error = true;
}
}
if ($error) return app('json')->fail(40137);
$this->services->add($goods_info);
return app('json')->success(100000);
}

View File

@ -78,6 +78,9 @@ class LiveRoom extends AuthController
['replay_status', 1],
['sort', 0]
]);
if (mb_strlen($data['name']) < 6 || mb_strlen($data['name']) > 17) {
return app('json')->fail(500030);
}
$this->validate($data, \app\adminapi\validate\marketing\LiveRoomValidate::class, 'save');
$this->services->add($data);
return app('json')->success(100000);

View File

@ -41,11 +41,12 @@ class LuckLottery extends AuthController
*/
public function index()
{
$where = $this->request->postMore([
['start_status', '', '', 'start'],
['status', ''],
$where = $this->request->getMore([
['factor', ''],
['store_name', '', '', 'keyword'],
['start', ''],
['status', ''],
['time', ''],
['keyword', ''],
]);
return app('json')->success($this->services->getList($where));
}
@ -63,28 +64,15 @@ class LuckLottery extends AuthController
if (!$id) {
return app('json')->fail(100100);
}
return app('json')->success($this->services->getlotteryInfo((int)$id));
}
/**
* 根据类型获取详情
* @param $factor
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function factorInfo($factor)
{
if (!$factor) {
return app('json')->fail(100100);
}
return app('json')->success($this->services->getlotteryFactorInfo((int)$factor));
return app('json')->success($this->services->getLotteryInfo((int)$id));
}
/**
* 添加抽奖
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
@ -219,4 +207,20 @@ class LuckLottery extends AuthController
$this->services->setStatus((int)$id, (int)$status);
return app('json')->success(100014);
}
public function factorList()
{
return app('json')->success($this->services->factorList());
}
public function factorUse()
{
$data = $this->request->postMore([
[['point', 'd'], 0],
[['pay', 'd'], 0],
[['evaluate', 'd'], 0],
]);
$this->services->factorUse($data);
return app('json')->success('保存成功');
}
}

View File

@ -42,12 +42,10 @@ class LuckLotteryRecord extends AuthController
public function index()
{
$where = $this->request->postMore([
['is_receive', ''],
['is_deliver', ''],
['type', ''],
['keyword', ''],
['data', '', '', 'time'],
['factor', ''],
['time', ''],
['lottery_id', ''],
]);
return app('json')->success($this->services->getList($where));
}

View File

@ -10,10 +10,11 @@
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\notification\sms;
use app\services\system\config\SystemConfigServices;
use app\services\yihaotong\SmsAdminServices;
use app\services\serve\ServeServices;
use crmeb\services\CacheService;
use app\adminapi\controller\AuthController;
use crmeb\services\CacheService;
use think\facade\App;
/**
@ -64,6 +65,7 @@ class SmsConfig extends AuthController
*/
public function is_login(ServeServices $services)
{
$configServices = app()->make(SystemConfigServices::class);
$sms_info = CacheService::get('sms_account');
$data = ['status' => false, 'info' => ''];
if ($sms_info) {
@ -103,14 +105,10 @@ class SmsConfig extends AuthController
*/
public function logout()
{
$res = CacheService::delete('sms_account');
if ($res) {
$this->services->updateSmsConfig('', '');
CacheService::clear();
return app('json')->success(100042);
} else {
return app('json')->fail(100043);
}
CacheService::delete('sms_account');
$this->services->updateSmsConfig('', '');
CacheService::clear();
return app('json')->success(100042);
}
/**

View File

@ -57,7 +57,13 @@ class RefundOrder extends AuthController
/**
* 订单详情
* @param $uni
* @return mixed
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/02
*/
public function getRefundInfo($uni)
{
@ -140,7 +146,7 @@ class RefundOrder extends AuthController
return app('json')->fail(400144);
}
if ($data['type'] == 1) {
if ($data['type'] == 1 || $data['type'] == 5) {
$data['refund_type'] = 6;
} else if ($data['type'] == 2) {
$data['refund_type'] = 3;
@ -163,12 +169,12 @@ class RefundOrder extends AuthController
return app('json')->fail(400147);
}
$refund_price = $data['refund_price'];
}
$data['refunded_price'] = bcadd($data['refund_price'], $orderRefund['refunded_price'], 2);
$bj = bccomp((string)$orderRefund['refund_price'], (string)$data['refunded_price'], 2);
if ($bj < 0) {
return app('json')->fail(400148);
}
$data['refunded_price'] = bcadd($data['refund_price'], $orderRefund['refunded_price'], 2);
$bj = bccomp((string)$orderRefund['refund_price'], (string)$data['refunded_price'], 2);
if ($bj < 0) {
return app('json')->fail(400148);
}
unset($data['type']);
@ -183,7 +189,9 @@ class RefundOrder extends AuthController
$wechatUserServices = app()->make(WechatUserServices::class);
$refund_data['open_id'] = $wechatUserServices->uidToOpenid((int)$order['uid'], 'routine') ?? '';
$refund_data['refund_no'] = $orderRefund['order_id'];
$refund_data['order_id'] = $orderRefund['order_id'];
//修改订单退款状态
// $data['refund_price'] = $data['refunded_price'];
unset($data['refund_price']);
if ($this->services->agreeRefund($id, $refund_data)) {
$this->services->update($id, $data);

View File

@ -12,7 +12,10 @@ namespace app\adminapi\controller\v1\order;
use app\adminapi\controller\AuthController;
use app\adminapi\validate\order\StoreOrderValidate;
use app\jobs\OrderExpressJob;
use app\services\serve\ServeServices;
use app\services\wechat\WechatUserServices;
use crmeb\services\FileService;
use app\services\order\{StoreOrderCartInfoServices,
StoreOrderDeliveryServices,
StoreOrderRefundServices,
@ -54,7 +57,10 @@ class StoreOrder extends AuthController
{
$where = $this->request->getMore([
['data', '', '', 'time'],
[['type', 'd'], 0],
['type', ''],
['pay_type', ''],
['field_key', 'all'],
['real_name', ''],
]);
$data = $this->services->orderCount($where);
return app('json')->success($data);
@ -185,6 +191,7 @@ class StoreOrder extends AuthController
['status', ''],
], true);
if ($status != '') $data['status'] = $status;
if ($status == 'undefined') $data['status'] = 1;
$data['is_show'] = 1;
return app('json')->success($services->express($data));
}
@ -242,7 +249,7 @@ class StoreOrder extends AuthController
['delivery_id', ''],//快递单号
['delivery_code', ''],//快递公司编码
['express_record_type', 2],//发货记录类型
['express_record_type', 2],//发货记录类型:2=电子面单;3=商家寄件
['express_temp_id', ""],//电子面单模板
['to_name', ''],//寄件人姓名
['to_tel', ''],//寄件人电话
@ -252,10 +259,12 @@ class StoreOrder extends AuthController
['sh_delivery_id', ''],//送货人电话
['sh_delivery_uid', ''],//送货人ID
['fictitious_content', '']//虚拟发货内容
['fictitious_content', ''],//虚拟发货内容
['day_type', 0], //顺丰传 0今天,1明天,2后台
['pickup_time', []],//开始时间 9:00,结束时间 10:00 开始时间和结束时间之间不能小于一个小时
]);
$services->delivery((int)$id, $data);
return app('json')->success(100010);
return app('json')->success(100010, $services->delivery((int)$id, $data));
}
/**
@ -263,6 +272,9 @@ class StoreOrder extends AuthController
* @param $id
* @param StoreOrderDeliveryServices $services
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function split_delivery($id, StoreOrderDeliveryServices $services)
{
@ -284,7 +296,11 @@ class StoreOrder extends AuthController
['fictitious_content', ''],//虚拟发货内容
['cart_ids', []]
['cart_ids', []],
['day_type', 0], //顺丰传 0今天,1明天,2后台
['pickup_time', []],//开始时间 9:00,结束时间 10:00 开始时间和结束时间之间不能小于一个小时
['service_type', ''],//快递业务类型
]);
if (!$id) {
return app('json')->fail(100100);
@ -301,6 +317,58 @@ class StoreOrder extends AuthController
return app('json')->success(100010);
}
/**
* 获取寄件预扣金额
* @param ServeServices $services
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/6/16
*/
public function getPrice(ServeServices $services)
{
$data = $this->request->postMore([
['kuaidicom', ''],
['send_address', ''],
['orderId', ''],
['service_type', ''],
['cart_ids', []],
]);
$orderInfo = $this->services->get($data['orderId'], ['user_address', 'cart_id']);
if (!$orderInfo) {
return app('json')->fail('订单没有查询到');
}
$weight = '0';
if ($data['cart_ids']) {
$cartIds = array_column($data['cart_ids'], 'cart_id');
$cartList = app()->make(StoreOrderCartInfoServices::class)->getColumn([
['cart_id', 'in', $cartIds]
], 'cart_info', 'cart_id');
foreach ($data['cart_ids'] as $cart) {
if (!isset($cart['cart_id']) || !$cart['cart_id'] || !isset($cart['cart_num']) || !$cart['cart_num']) {
return app('json')->fail(400159);
}
if (isset($cartList[$cart['cart_id']])) {
$value = is_string($cartList[$cart['cart_id']]) ? json_decode($cartList[$cart['cart_id']], true) : $cartList[$cart['cart_id']];
$weightnew = bcmul($value['attrInfo']['weight'], (string)$cart['cart_num'], 2);
$weight = bcadd($weightnew, $weight, 2);
}
}
} else {
$orderCartInfoList = app()->make(StoreOrderCartInfoServices::class)->getCartInfoPrintProduct($data['orderId']);
foreach ($orderCartInfoList as $item) {
$weightnew = bcmul($item['attrInfo']['weight'], (string)$item['cart_num'], 2);
$weight = bcadd($weightnew, $weight, 2);
}
}
$data['address'] = $orderInfo['user_address'];
if ($weight > 0) {
$data['weight'] = $weight;
}
return app('json')->success($services->express()->getPrice($data));
}
/**
* 获取订单可拆分发货商品列表
* @param $id
@ -317,7 +385,11 @@ class StoreOrder extends AuthController
/**
* 获取订单拆分子订单列表
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function split_order($id)
{
@ -385,7 +457,7 @@ class StoreOrder extends AuthController
if (!$id) {
return app('json')->fail(100100);
}
return app('json')->success($services->refundOrderForm((int)$id));
return app('json')->success($services->refundOrderForm((int)$id, 'order'));
}
/**
@ -400,7 +472,7 @@ class StoreOrder extends AuthController
{
$data = $this->request->postMore([
['refund_price', 0],
['type', 1]
['cart_ids', []]
]);
if (!$id) {
return app('json')->fail(100100);
@ -409,44 +481,64 @@ class StoreOrder extends AuthController
if (!$order) {
return app('json')->fail(400118);
}
$refundData = [
'refund_reason' => '后台主动退款',
'refund_explain' => '后台主动退款',
'refund_img' => json_encode([]),
];
$res = $services->applyRefund((int)$id, $order['uid'], $order, $data['cart_ids'], 1, (float)$data['refund_price'], $refundData);
if (!$res) {
return app('json')->fail('退款单生成失败');
}
$orderRefund = $services->getOrderOne(['store_order_id' => $id]);
$data['refund_status'] = 2;
$data['refund_type'] = 6;
$data['refunded_time'] = time();
//0元退款
if ($order['pay_price'] == 0 && in_array($order['refund_status'], [0, 1])) {
if ($orderRefund['refund_price'] == 0 && in_array($orderRefund['refund_type'], [1, 5])) {
$refund_price = 0;
} else {
if ($order['pay_price'] == $order['refund_price']) {
return app('json')->fail(400147);
}
if (!$data['refund_price']) {
return app('json')->fail(400146);
}
$refund_price = $data['refund_price'];
$data['refund_price'] = bcadd($data['refund_price'], $order['refund_price'], 2);
$bj = bccomp((string)$order['pay_price'], (string)$data['refund_price'], 2);
if ($bj < 0) {
return app('json')->fail(400148);
if ($orderRefund['refund_price'] == $orderRefund['refunded_price']) {
return app('json')->fail(400147);
}
$refund_price = $data['refund_price'];
}
if ($data['type'] == 1) {
$data['refund_status'] = 2;
} else if ($data['type'] == 2) {
$data['refund_status'] = 0;
$data['refunded_price'] = bcadd($data['refund_price'], $orderRefund['refunded_price'], 2);
$bj = bccomp((string)$orderRefund['refund_price'], (string)$data['refunded_price'], 2);
if ($bj < 0) {
return app('json')->fail(400148);
}
$data['refund_type'] = 6;
$type = $data['type'];
unset($data['type']);
$refund_data['pay_price'] = $order['pay_price'];
$refund_data['refund_price'] = $refund_price;
if ($order['refund_price'] > 0) {
mt_srand();
$refund_data['refund_id'] = $order['order_id'] . rand(100, 999);
}
//退款处理
$services->payOrderRefund($type, $order, $refund_data);
($order['pid'] > 0) ? $refund_data['order_id'] = $this->services->value(['id' => (int)$order['pid']], 'order_id') : $refund_data['order_id'] = $order['order_id'];
/** @var WechatUserServices $wechatUserServices */
$wechatUserServices = app()->make(WechatUserServices::class);
$refund_data['open_id'] = $wechatUserServices->uidToOpenid((int)$order['uid'], 'routine') ?? '';
$refund_data['refund_no'] = $orderRefund['order_id'];
$refund_data['order_id'] = $orderRefund['order_id'];
//修改订单退款状态
if ($this->services->update($id, $data)) {
$services->storeProductOrderRefundY($data, $order, $refund_price);
unset($data['refund_price']);
if ($services->agreeRefund($orderRefund['id'], $refund_data)) {
$services->update($orderRefund['id'], $data);
return app('json')->success(400149);
} else {
$services->storeProductOrderRefundYFasle((int)$id, $refund_price);
$services->storeProductOrderRefundYFasle((int)$orderRefund['id'], $refund_price);
return app('json')->fail(400150);
}
}
@ -455,10 +547,11 @@ class StoreOrder extends AuthController
* 订单详情
* @param $id 订单id
* @return mixed
* @throws \ReflectionException
*/
public function order_info($id)
{
if (!$id || !($orderInfo = $this->services->get($id))) {
if (!$id || !($orderInfo = $this->services->get($id, [], ['refund', 'invoice']))) {
return app('json')->fail(400118);
}
/** @var UserServices $services */
@ -497,6 +590,13 @@ class StoreOrder extends AuthController
} else
$orderInfo['_store_name'] = '';
$orderInfo['spread_name'] = $services->value(['uid' => $orderInfo['spread_uid']], 'nickname') ?? '无';
$orderInfo['_info'] = app()->make(StoreOrderCartInfoServices::class)->getOrderCartInfo((int)$orderInfo['id']);
$cart_num = 0;
$refund_num = array_sum(array_column($orderInfo['refund'], 'refund_num'));
foreach ($orderInfo['_info'] as $items) {
$cart_num += $items['cart_info']['cart_num'];
}
$orderInfo['is_all_refund'] = $refund_num == $cart_num;
$userInfo = $userInfo->toArray();
return app('json')->success(compact('orderInfo', 'userInfo'));
}
@ -551,6 +651,7 @@ class StoreOrder extends AuthController
/**
* 不退款表单结构
* @param StoreOrderRefundServices $services
* @param $id
* @return mixed
* @throws \FormBuilder\Exception\FormBuilderException
@ -591,7 +692,13 @@ class StoreOrder extends AuthController
}
$services->storeProductOrderRefundNo((int)$id, $refund_reason);
//提醒推送
event('notice.notice', [['orderInfo' => $orderInfo], 'send_order_refund_no_status']);
event('NoticeListener', [['orderInfo' => $orderInfo], 'send_order_refund_no_status']);
//自定义消息-订单拒绝退款
$orderInfo['time'] = date('Y-m-d H:i:s');
$orderInfo['phone'] = $orderInfo['user_phone'];
event('CustomNoticeListener', [$orderInfo['uid'], $orderInfo, 'order_refund_fail']);
return app('json')->success(100010);
}
@ -747,8 +854,89 @@ class StoreOrder extends AuthController
*/
public function order_dump($order_id, StoreOrderDeliveryServices $storeOrderDeliveryServices)
{
return app('json')->success($storeOrderDeliveryServices->orderDump($order_id));
$storeOrderDeliveryServices->orderDump($order_id);
return app('json')->success(400121);
}
/**
* 获取快递信息
* @param ServeServices $services
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/5/15
*/
public function getKuaidiComs(ServeServices $services)
{
return app('json')->success($services->express()->getKuaidiComs());
}
/**
* 取消商家寄件
* @param $id
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/5/15
*/
public function shipmentCancelOrder($id)
{
if (!$id) {
return app('json')->fail('缺少参数');
}
$msg = $this->request->post('msg', '');
if (!$msg) {
return app('json')->fail('请填写取消寄件原因');
}
if ($this->services->shipmentCancelOrder((int)$id, $msg)) {
return app('json')->success('取消成功');
} else {
return app('json')->fail('取消失败');
}
}
/**
* 导入批量发货
* @return \think\Response|void
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function importExpress()
{
[$file] = $this->request->getMore([
['file', '']
], true);
if (!$file) return app('json')->fail(400168);
$file = public_path() . substr($file, 1);
// 获取文件后缀
$suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (!in_array($suffix, ['xls', 'xlsx'])) {
return app('json')->fail('文件格式不正确,请上传xls或xlsx格式的文件!');
}
$expressData = app()->make(FileService::class)->readExcel($file, 'express', 2, ucfirst($suffix));
foreach ($expressData as $item) {
OrderExpressJob::dispatch([$item]);
}
return app('json')->success('批量发货成功');
}
/**
* 配货单
* @param $order_id
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author: 吴汐
* @email: 442384644@qq.com
* @date: 2023/10/11
*/
public function printShipping($order_id)
{
if (!$order_id) {
return app('json')->fail('参数错误');
}
$data = $this->services->printShippingData($order_id);
return app('json')->success($data);
}
}

View File

@ -1,138 +1,309 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\order;
use app\adminapi\controller\AuthController;
use app\services\order\StoreOrderInvoiceServices;
use app\services\order\StoreOrderServices;
use app\services\product\product\StoreProductServices;
use app\services\system\store\SystemStoreServices;
use app\services\user\UserServices;
use think\facade\App;
/**
* 发票管理
* Class StoreOrderInvoice
* @package app\adminapi\controller\v1\order
*/
class StoreOrderInvoice extends AuthController
{
/**
* StoreOrderInvoice constructor.
* @param App $app
* @param StoreOrderInvoiceServices $services
*/
public function __construct(App $app, StoreOrderInvoiceServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 获取订单类型数量
* @return mixed
*/
public function chart()
{
$where = $this->request->getMore([
['data', '', '', 'time'],
[['type', 'd'], 0],
]);
$data = $this->services->chart($where);
return app('json')->success($data);
}
/**
* 查询发票列表
* @return mixed
*/
public function list()
{
$where = $this->request->getMore([
['status', 0],
['real_name', ''],
['header_type', ''],
['type', ''],
['data', '', '', 'time'],
['field_key', ''],
]);
return app('json')->success($this->services->getList($where));
}
/**
* 设置发票状态
* @param string $id
* @return mixed
*/
public function set_invoice($id = '')
{
if ($id == '') return app('json')->fail(100100);
$data = $this->request->postMore([
['is_invoice', 0],
['invoice_number', 0],
['remark', '']
]);
if ($data['is_invoice'] == 1 && !$data['invoice_number']) {
return app('json')->fail(400166);
}
if ($data['invoice_number'] && !preg_match('/^\d{8,10}$/', $data['invoice_number'])) {
return app('json')->fail(400167);
}
$this->services->setInvoice((int)$id, $data);
return app('json')->success(100014);
}
/**
* 订单详情
* @param $id 订单id
* @return mixed
*/
public function orderInfo(StoreProductServices $productServices, StoreOrderServices $orderServices, $id)
{
if (!$id || !($orderInfo = $orderServices->get($id))) {
return app('json')->fail(400118);
}
/** @var UserServices $services */
$services = app()->make(UserServices::class);
$userInfo = $services->get($orderInfo['uid']);
if (!$userInfo) {
return app('json')->fail(400119);
}
$userInfo = $userInfo->hidden(['pwd', 'add_ip', 'last_ip', 'login_type']);
$userInfo['spread_name'] = '';
if ($userInfo['spread_uid'])
$userInfo['spread_name'] = $services->value(['uid' => $userInfo['spread_uid']], 'nickname');
$orderInfo = $orderServices->tidyOrder($orderInfo->toArray(), true, true);
//核算优惠金额
$vipTruePrice = array_column($orderInfo['cartInfo'], 'vip_sum_truePrice');
$vipTruePrice = array_sum($vipTruePrice);
$orderInfo['vip_true_price'] = $vipTruePrice ?: 0;
$orderInfo['add_time'] = $orderInfo['_add_time'] ?? '';
$productId = array_column($orderInfo['cartInfo'], 'product_id');
$cateData = $productServices->productIdByProductCateName($productId);
foreach ($orderInfo['cartInfo'] as &$item) {
$item['class_name'] = $cateData[$item['product_id']] ?? '';
}
if ($orderInfo['store_id'] && $orderInfo['shipping_type'] == 2) {
/** @var $storeServices */
$storeServices = app()->make(SystemStoreServices::class);
$orderInfo['_store_name'] = $storeServices->value(['id' => $orderInfo['store_id']], 'name');
} else {
$orderInfo['_store_name'] = '';
}
$userInfo = $userInfo->toArray();
$invoice = $this->services->getOne(['order_id' => $id]);
return app('json')->success(compact('orderInfo', 'userInfo', 'invoice'));
}
}
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\order;
use app\adminapi\controller\AuthController;
use app\services\order\StoreOrderCartInfoServices;
use app\services\order\StoreOrderInvoiceServices;
use app\services\order\StoreOrderServices;
use app\services\product\product\StoreProductServices;
use app\services\serve\ServeServices;
use app\services\system\store\SystemStoreServices;
use app\services\user\UserServices;
use think\facade\App;
/**
* 发票管理
* Class StoreOrderInvoice
* @package app\adminapi\controller\v1\order
*/
class StoreOrderInvoice extends AuthController
{
/**
* StoreOrderInvoice constructor.
* @param App $app
* @param StoreOrderInvoiceServices $services
*/
public function __construct(App $app, StoreOrderInvoiceServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 获取订单类型数量
* @return mixed
*/
public function chart()
{
$where = $this->request->getMore([
['data', '', '', 'time'],
['real_name', ''],
['field_key', ''],
[['type', 'd'], 0],
]);
$data = $this->services->chart($where);
return app('json')->success($data);
}
/**
* 查询发票列表
* @return mixed
*/
public function list()
{
$where = $this->request->getMore([
['status', 0],
['real_name', ''],
['header_type', ''],
['type', ''],
['data', '', '', 'time'],
['field_key', ''],
]);
return app('json')->success($this->services->getList($where));
}
/**
* 设置发票状态
* @param string $id
* @return mixed
*/
public function set_invoice($id = '')
{
if ($id == '') return app('json')->fail(100100);
$data = $this->request->postMore([
['is_invoice', 0],
['invoice_number', 0],
['remark', '']
]);
if ($data['is_invoice'] == 1 && !$data['invoice_number']) {
return app('json')->fail(400166);
}
if ($data['invoice_number'] && !preg_match('/^\d{8,10}$/', $data['invoice_number'])) {
return app('json')->fail(400167);
}
$this->services->setInvoice((int)$id, $data);
return app('json')->success(100014);
}
/**
* 订单详情
* @param $id 订单id
* @return mixed
*/
public function orderInfo(StoreProductServices $productServices, StoreOrderServices $orderServices, $id)
{
if (!$id || !($orderInfo = $orderServices->get($id))) {
return app('json')->fail(400118);
}
/** @var UserServices $services */
$services = app()->make(UserServices::class);
$userInfo = $services->get($orderInfo['uid']);
if (!$userInfo) {
return app('json')->fail(400119);
}
$userInfo = $userInfo->hidden(['pwd', 'add_ip', 'last_ip', 'login_type']);
$userInfo['spread_name'] = '';
if ($userInfo['spread_uid'])
$userInfo['spread_name'] = $services->value(['uid' => $userInfo['spread_uid']], 'nickname');
$orderInfo = $orderServices->tidyOrder($orderInfo->toArray(), true, true);
//核算优惠金额
$vipTruePrice = array_column($orderInfo['cartInfo'], 'vip_sum_truePrice');
$vipTruePrice = array_sum($vipTruePrice);
$orderInfo['vip_true_price'] = $vipTruePrice ?: 0;
$orderInfo['add_time'] = $orderInfo['_add_time'] ?? '';
$productId = array_column($orderInfo['cartInfo'], 'product_id');
$cateData = $productServices->productIdByProductCateName($productId);
foreach ($orderInfo['cartInfo'] as &$item) {
$item['class_name'] = $cateData[$item['product_id']] ?? '';
}
if ($orderInfo['store_id'] && $orderInfo['shipping_type'] == 2) {
/** @var $storeServices */
$storeServices = app()->make(SystemStoreServices::class);
$orderInfo['_store_name'] = $storeServices->value(['id' => $orderInfo['store_id']], 'name');
} else {
$orderInfo['_store_name'] = '';
}
$userInfo = $userInfo->toArray();
$invoice = $this->services->getOne(['order_id' => $id]);
return app('json')->success(compact('orderInfo', 'userInfo', 'invoice'));
}
/**
* 获取电子发票配置信息
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/16
*/
public function elecInvoiceConfig()
{
$data = [
'elec_invoice' => (int)sys_config('elec_invoice'),
'auto_invoice' => (int)sys_config('auto_invoice'),
'elec_invoice_cate' => (int)sys_config('elec_invoice_cate'),
'elec_invoice_cate_name' => sys_config('elec_invoice_cate_name'),
'elec_invoice_tax_rate' => (int)sys_config('elec_invoice_tax_rate')
];
return app('json')->success($data);
}
/**
* 获取发票开具页面iframe地址
* @param $id
* @return \think\Response
* @throws \ReflectionException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/13
*/
public function invoiceIssuanceUrl($id)
{
if (sys_config('elec_invoice', 1) != 1) {
return app('json')->fail('电子发票功能未开启,请在一号通中开启并且在商城后台一号通配置中开启');
}
$info = $this->services->getOne(['id' => $id]);
$unique = app()->make(StoreOrderServices::class)->value(['id' => $info['order_id']], 'order_id');
$cartInfo = app()->make(StoreOrderCartInfoServices::class)->getOrderCartInfo($info['order_id']);
$goods = [];
foreach ($cartInfo as $item) {
$goods[] = [
'store_name' => $item['cart_info']['productInfo']['store_name'],
'unit_price' => bcadd($item['cart_info']['truePrice'], $item['cart_info']['postage_price'], 2),
'num' => $item['cart_info']['cart_num']
];
}
$data = [];
$data['unique'] = $unique;
$data['goods'] = $goods;
$data['account_name'] = $info['name'];
$data['email'] = $info['email'];
if ($info['header_type'] == 1) {
$data['invoice_type'] = 82;
$data['is_enterprise'] = 0;
} else {
$data['invoice_type'] = $info['type'] == 1 ? 82 : 81;
$data['tax_id'] = $info['duty_number'];
$data['is_enterprise'] = 1;
}
$invoice = app()->make(ServeServices::class)->invoice();
return app('json')->success($invoice->invoiceIssuanceUrl($data));
}
/**
* 保存发票信息
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/14
*/
public function saveInvoiceInfo($id)
{
$data = $this->request->postMore([
['invoice_num', ''],
['invoice_type', ''],
['invoice_serial_number', ''],
]);
$info = $this->services->getOne(['id' => $id]);
$data['unique_num'] = app()->make(StoreOrderServices::class)->value(['id' => $info['order_id']], 'order_id');
$data['is_invoice'] = 1;
$data['invoice_time'] = time();
$this->services->update($id, $data);
return app('json')->success('保存成功');
}
/**
* 查看发票详情
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/14
*/
public function invoiceInfo($id)
{
$info = $this->services->getOne(['id' => $id]);
$invoice = app()->make(ServeServices::class)->invoice();
return app('json')->success($invoice->invoiceInfo($info['invoice_num']));
}
/**
* 下载发票
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/14
*/
public function downInvoice($id)
{
$info = $this->services->getOne(['id' => $id]);
$invoice = app()->make(ServeServices::class)->invoice();
return app('json')->success($invoice->downloadInvoice($info['invoice_num']));
}
/**
* 电子发票分类
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/15
*/
public function invoiceCategory()
{
$where = $this->request->getMore([
['name', ''],
['page', 1],
['limit', 100],
]);
$invoice = app()->make(ServeServices::class)->invoice();
return app('json')->success($invoice->category($where));
}
/**
* 开具发票
* @param $id
* @return \think\Response
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/15
*/
public function invoiceIssuance($id)
{
$this->services->invoiceIssuance($id);
return app('json')->success('开票成功');
}
/**
* 负数发票开具
* @param $id
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/5/16
*/
public function redInvoiceIssuance($id)
{
$this->services->redInvoiceIssuance($id);
return app('json')->success('开具负数发票成功');
}
}

View File

@ -57,7 +57,11 @@ class StoreCategory extends AuthController
/**
* 商品分类搜索
* @param $type
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function tree_list($type)
{
@ -103,6 +107,9 @@ class StoreCategory extends AuthController
/**
* 保存新增分类
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function save()
{
@ -133,6 +140,9 @@ class StoreCategory extends AuthController
* 更新分类
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function update($id)
{

View File

@ -12,6 +12,7 @@ namespace app\adminapi\controller\v1\product;
use app\adminapi\controller\AuthController;
use app\adminapi\controller\v1\system\SystemClearData;
use app\services\order\StoreCartServices;
use app\services\other\CacheServices;
use app\services\product\product\StoreCategoryServices;
@ -19,6 +20,7 @@ use app\services\product\product\StoreProductServices;
use crmeb\services\FileService;
use app\services\other\UploadService;
use think\facade\App;
use think\Request;
/**
* Class StoreProduct
@ -40,7 +42,17 @@ class StoreProduct extends AuthController
*/
public function type_header()
{
$list = $this->service->getHeader();
$where = $this->request->getMore([
['store_name', ''],
['cate_id', ''],
['spec_type', ''],
['is_gift', ''],
['vip_product', ''],
['price_s', []],
['stock_s', []],
['sales_s', []],
]);
$list = $this->service->getHeader($where);
return app('json')->success(compact('list'));
}
@ -122,7 +134,17 @@ class StoreProduct extends AuthController
['store_name', ''],
['cate_id', ''],
['type', 1],
['sales', 'normal']
['sales', 'normal'],
['spec_type', ''],
['is_gift', ''],
['vip_product', ''],
['price_s', []],
['stock_s', []],
['sales_s', []],
['store_label_id', []],
['logistics', ''],
['time', ''],
['virtual_type', ''],
]);
$data = $this->service->getList($where);
return app('json')->success($data);
@ -136,6 +158,8 @@ class StoreProduct extends AuthController
*/
public function set_show($is_show = '', $id = '')
{
$del = $this->service->value(['id' => $id], 'is_del');
if ($del == 1) return app('json')->fail('商品已删除,请先恢复商品');
$this->service->setShow([$id], $is_show);
return app('json')->success(100014);
}
@ -237,7 +261,13 @@ class StoreProduct extends AuthController
['is_copy', 0],//是否是复制商品
['is_limit', 0],//是否限购
['limit_type', 0],//限购类型
['limit_num', 0]//限购数量
['limit_num', 0],//限购数量
['min_qty', 1],//起购数量
['params_list', []],//商品参数
['label_list', []],//商品标签
['protection_list', []],//商品保障
['is_gift', 0],//是否礼品
['gift_price', 0],//礼品附加费
]);
$this->service->save((int)$id, $data);
return app('json')->success(100000);
@ -260,6 +290,31 @@ class StoreProduct extends AuthController
return app('json')->success($res);
}
/**
* 批量移动到回收站
* @return \think\Response
*/
public function batchDelete()
{
[$ids] = $this->request->postMore([
['ids', []],
], true);
return app('json')->success($this->service->batchDelete($ids));
}
/**
* 批量从回收站恢复
* @return \think\Response
*/
public function batchRecover()
{
[$ids] = $this->request->postMore([
['ids', []],
], true);
$this->service->batchRecover($ids);
return app('json')->success('恢复成功');
}
/**
* 生成规格列表
* @param int $id
@ -274,7 +329,6 @@ class StoreProduct extends AuthController
['is_virtual', 0],
['virtual_type', 0]
]);
if ($id > 0 && $type == 1) $this->service->checkActivity($id);
$info = $this->service->getAttr($data, $id, $type);
return app('json')->success(compact('info'));
}
@ -293,10 +347,11 @@ class StoreProduct extends AuthController
['is_live', 0],
['is_new', ''],
['is_virtual', -1],
['is_presale', -1]
['is_presale', -1],
['is_show', 1],
]);
$where['is_show'] = 1;
$where['is_del'] = 0;
$where['cate_id'] = toIntArray($where['cate_id']);
/** @var StoreCategoryServices $storeCategoryServices */
$storeCategoryServices = app()->make(StoreCategoryServices::class);
if ($where['cate_id'] !== '') {
@ -339,10 +394,21 @@ class StoreProduct extends AuthController
* @return mixed
* @throws \Exception
*/
public function getTempKeys()
public function getTempKeys(Request $request)
{
$upload = UploadService::init();
$re = $upload->getTempKeys();
$type = (int)sys_config('upload_type', 1);
$key = $request->get('key', '');
$path = $request->get('path', '');
$contentType = $request->get('contentType', '');
if ($type === 5) {
if (!$key || !$contentType) {
return app('json')->fail('缺少参数');
}
$re = $upload->getTempKeys($key, $path, $contentType);
} else {
$re = $upload->getTempKeys();
}
return $re ? app('json')->success($re) : app('json')->fail(100016);
}
@ -371,9 +437,14 @@ class StoreProduct extends AuthController
]);
if (!$data['file']) return app('json')->fail(400168);
$file = public_path() . substr($data['file'], 1);
// 获取文件后缀
$suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (!in_array($suffix, ['xls', 'xlsx'])) {
return app('json')->fail('文件格式不正确,请上传xls或xlsx格式的文件!');
}
/** @var FileService $readExcelService */
$readExcelService = app()->make(FileService::class);
$cardData = $readExcelService->readExcel($file);
$cardData = $readExcelService->readExcel($file, 'card', 1, ucfirst($suffix));
return app('json')->success($cardData);
}
@ -393,10 +464,98 @@ class StoreProduct extends AuthController
['give_integral', 0],
['coupon_ids', []],
['label_id', []],
['label_list', []],
['recommend', []],
['type', 0]
['type', 0],
['is_gift', 0],
['gift_price', 0],
]);
$this->service->batchSetting($data);
return app('json')->success(100014);
}
/**
* 商品类型接口
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/9/29
*/
public function productTypeConfig()
{
$productTypeConfig = sys_config('product_type_config');
foreach ($productTypeConfig as $key => $value) {
$productTypeConfig[$key] = intval($value);
}
return app('json')->success(sys_config('product_type_config'));
}
/**
* 商品迁移导出
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/10/9
*/
public function productExport()
{
$where = $this->request->getMore([
['store_name', ''],
['cate_id', ''],
['type', 1],
['sales', 'normal']
]);
$where['virtual_type'] = 0;
return app('json')->success($this->service->productExportList($where));
}
/**
* 商品迁移导入
* @return \think\Response
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/10/9
*/
public function productImport()
{
[$file] = $this->request->getMore([
['file', ""]
], true);
if (!$file) return app('json')->fail(400168);
$res = $this->service->productImport($file);
return app('json')->success('导入成功', $res);
}
/**
* 回收站商品彻底删除
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/10/9
*/
public function fullDel($id)
{
app()->make(SystemClearData::class)->recycleProduct($id);
return app('json')->success('删除成功');
}
public function otherInfo($id, $type)
{
if (!$id) return app('json')->fail('参数错误');
return app('json')->success($this->service->otherInfo($id, $type));
}
public function otherSave($id, $type)
{
$data = $this->request->postMore([
['is_sub', 0],
['is_vip', 0],
['vip_product', 0],
['attr_value', []],
]);
$this->service->otherSave($id, $type, $data);
return app('json')->success('保存成功');
}
}

View File

@ -0,0 +1,112 @@
<?php
namespace app\adminapi\controller\v1\product;
use app\adminapi\controller\AuthController;
use app\services\product\product\StoreProductLabelCateServices;
use app\services\product\product\StoreProductLabelServices;
use think\facade\App;
class StoreProductLabel extends AuthController
{
protected $labelCateServices;
protected $labelServices;
public function __construct(App $app, StoreProductLabelCateServices $labelCateServices, StoreProductLabelServices $labelServices)
{
parent::__construct($app);
$this->labelCateServices = $labelCateServices;
$this->labelServices = $labelServices;
}
public function labelCateList()
{
$where = $this->request->getMore([
['name', ''],
]);
$where['is_del'] = 0;
return app('json')->success($this->labelCateServices->getLabelCateList($where));
}
public function labelCateForm($id)
{
return app('json')->success($this->labelCateServices->labelCateForm($id));
}
public function labelCateSave($id)
{
$data = $this->request->postMore([
['name', ''],
['sort', 0],
]);
$this->labelCateServices->labelCateSave($id, $data);
return app('json')->success('保存成功');
}
public function labelCateDel($id)
{
$this->labelCateServices->labelCateDel($id);
return app('json')->success('删除成功');
}
public function labelList()
{
$where = $this->request->getMore([
['name', ''],
['cate_id', ''],
['status', ''],
['is_show', ''],
]);
$where['is_del'] = 0;
return app('json')->success($this->labelServices->LabelList($where));
}
public function labelInfo($id)
{
return app('json')->success($this->labelServices->labelInfo($id));
}
public function labelSave()
{
$data = $this->request->postMore([
['id', 0],
['name', ''],
['cate_id', 0],
['type', 0],
['font_color', ''],
['bg_color', ''],
['border_color', ''],
['image', ''],
['sort', 0],
['status', 1],
['is_show', 1],
]);
$this->labelServices->labelSave($data);
return app('json')->success('保存成功');
}
public function labelDel($id)
{
$this->labelServices->labelDel($id);
return app('json')->success('删除成功');
}
public function labelIsShow($id, $is_show)
{
$this->labelServices->labelIsShow($id, $is_show);
return app('json')->success('修改成功');
}
public function labelStatus($id, $status)
{
$this->labelServices->labelStatus($id, $status);
return app('json')->success('修改成功');
}
public function labelUseList()
{
return app('json')->success($this->labelServices->labelUseList());
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace app\adminapi\controller\v1\product;
use app\adminapi\controller\AuthController;
use app\services\product\product\StoreProductParamServices;
use think\facade\App;
/**
* 商品参数
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
class StoreProductParam extends AuthController
{
/**
* @param App $app
* @param StoreProductParamServices $services
*/
public function __construct(App $app, StoreProductParamServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 获取参数列表
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
public function getParamList()
{
$where = $this->request->getMore([
['name', '']
]);
return app('json')->success($this->services->getParamList($where));
}
/**
* 获取参数详情
* @param $id
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
public function getParamInfo($id)
{
if (!$id) return app('json')->fail('参数错误');
$info = $this->services->getParamInfo($id);
return app('json')->success($info);
}
/**
* 获取参数值
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
public function getParamValue($id)
{
if (!$id) return app('json')->fail('参数错误');
$info = $this->services->getParamValue($id);
return app('json')->success($info);
}
/**
* 保存参数
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
public function saveParamData($id)
{
$data = $this->request->postMore([
['name', ''],
['value', []],
['sort', 0],
['status', 1]
]);
if (!$data['name']) return app('json')->fail('请输入参数名称');
if (!count($data['value'])) return app('json')->fail('请输入参数值');
$this->services->saveParamData($id, $data);
return app('json')->success('保存成功');
}
/**
* 修改参数状态
* @param $id
* @param $status
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
public function setParamStatus($id, $status)
{
if (!$id) return app('json')->fail('参数错误');
$this->services->setParamStatus($id, $status);
return app('json')->success('修改成功');
}
/**
* 删除参数
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/12/17
*/
public function delParamData($id)
{
if (!$id) return app('json')->fail('参数错误');
$this->services->delParamData($id);
return app('json')->success('删除成功');
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace app\adminapi\controller\v1\product;
use app\adminapi\controller\AuthController;
use app\services\product\product\StoreProductProtectionServices;
use think\facade\App;
class StoreProductProtection extends AuthController
{
public function __construct(App $app, StoreProductProtectionServices $services)
{
parent::__construct($app);
$this->services = $services;
}
public function protectionList()
{
$where = $this->request->getMore([
['title', ''],
['status', '']
]);
$where['is_del'] = 0;
return app('json')->success($this->services->protectionList($where));
}
public function protectionInfo($id)
{
if (!$id) return app('json')->fail('参数错误');
$info = $this->services->protectionInfo($id);
return app('json')->success($info);
}
public function protectionForm($id)
{
return app('json')->success($this->services->protectionForm($id));
}
public function protectionSave($id)
{
$data = $this->request->postMore([
['title', ''],
['content', ''],
['image', ''],
['sort', 0],
['status', 0]
]);
$this->services->protectionSave($id, $data);
return app('json')->success('保存成功');
}
public function protectionStatus($id, $status)
{
if (!$id) return app('json')->fail('参数错误');
$this->services->protectionStatus($id, $status);
return app('json')->success('修改成功');
}
public function protectionDel($id)
{
if (!$id) return app('json')->fail('参数错误');
$this->services->protectionDel($id);
return app('json')->success('删除成功');
}
}

View File

@ -41,7 +41,8 @@ class StoreProductReply extends AuthController
['data', ''],
['product_id', 0],
['key', ''],
['order', '']
['order', ''],
['status', ''],
]);
$list = $this->services->sysPage($where);
return app('json')->success($list);
@ -100,7 +101,8 @@ class StoreProductReply extends AuthController
['product_score', 0],
['service_score', 0],
['product_id', 0],
['add_time', 0]
['add_time', 0],
['suk', ''],
]);
if (!$data['product_id']) {
$data['product_id'] = $data['image']['product_id'] ?? '';
@ -109,4 +111,36 @@ class StoreProductReply extends AuthController
$this->services->saveReply($data);
return app('json')->success(100000);
}
/**
* 商品评论审核
* @param $id
* @param $status
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/4/22
*/
public function set_status($id, $status)
{
$this->services->update($id, ['status' => $status]);
return app('json')->success($status == 1 ? '审核通过' : '拒绝成功');
}
/**
* 批量商品评论审核
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2025/6/18
*/
public function batch_set_status()
{
list($ids, $status) = $this->request->postMore([
['ids', []],
['status', 0]
], true);
$this->services->batchUpdate($ids, ['status' => $status]);
return app('json')->success($status == 1 ? '审核通过' : '拒绝成功');
}
}

View File

@ -80,4 +80,21 @@ class Export extends AuthController
}
return app('json')->success(['isOpen' => $res]);
}
/**
* @param ServeServices $services
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/5/15
*/
public function getShipmentOrderList(ServeServices $services)
{
$where = $this->request->getMore([
['page', 1],
['limit', 10],
]);
return app('json')->success($services->express()->getShipmentOrderList($where));
}
}

View File

@ -92,4 +92,4 @@ class LangType extends AuthController
CacheService::delete('lang_type_data');
return app('json')->success(100002);
}
}
}

View File

@ -169,9 +169,13 @@ class SystemAdmin extends AuthController
['new_pwd', ''],
['conf_pwd', ''],
]);
if (!preg_match('/^(?![^a-zA-Z]+$)(?!\D+$).{6,}$/', $data['new_pwd'])) {
return app('json')->fail(400183);
if ($data['pwd']) {
if (!preg_match('/^(?![^a-zA-Z]+$)(?!\D+$).{6,}$/', $data['new_pwd'])) {
return app('json')->fail(400183);
}
}
if ($this->services->updateAdmin($this->adminId, $data))
return app('json')->success(100001);
else

View File

@ -133,11 +133,20 @@ class SystemCity extends AuthController
*/
public function clean_cache()
{
$res = CacheService::delete('CITY_LIST');
if ($res) {
return app('json')->success(400185);
} else {
return app('json')->fail(400186);
}
CacheService::delete('CITY_LIST');
CacheService::delete('CITY_FULL_LIST');
return app('json')->success(400185);
}
/**
* 获取城市数据完整列表
* @return \think\Response
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/04/10
*/
public function fullList()
{
return app('json')->success($this->services->fullList('parent_id,name as label,city_id as value'));
}
}

View File

@ -12,9 +12,11 @@ namespace app\adminapi\controller\v1\setting;
use app\adminapi\controller\AuthController;
use app\Request;
use app\services\order\StoreOrderServices;
use app\services\system\config\SystemConfigServices;
use app\services\system\config\SystemConfigTabServices;
use app\services\system\SystemPemServices;
use crmeb\services\CacheService;
use crmeb\services\easywechat\orderShipping\MiniOrderService;
use think\facade\App;
/**
@ -38,16 +40,19 @@ class SystemConfig extends AuthController
/**
* 显示资源列表
*
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$where = $this->request->getMore([
['tab_id', 0],
['config_name', ''],
['status', -1]
]);
if (!$where['tab_id']) {
if (!$where['tab_id'] && $where['config_name'] == '') {
return app('json')->fail(100100);
}
if ($where['status'] == -1) {
@ -58,8 +63,11 @@ class SystemConfig extends AuthController
/**
* 显示创建资源表单页.
* @param $type
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function create()
{
@ -72,7 +80,6 @@ class SystemConfig extends AuthController
/**
* 保存新建的资源
*
* @return \think\Response
*/
public function save()
@ -91,8 +98,11 @@ class SystemConfig extends AuthController
['info', ''],
['desc', ''],
['sort', 0],
['level', 0],
['link_data', []],
['status', 0]
]);
if (is_array($data['config_tab_id'])) $data['config_tab_id'] = end($data['config_tab_id']);
if (!$data['info']) return app('json')->fail(400274);
if (!$data['menu_name']) return app('json')->fail(400275);
if (!$data['desc']) return app('json')->fail(400276);
@ -113,6 +123,11 @@ class SystemConfig extends AuthController
if (!$data['parameter']) return app('json')->fail(400283);
$this->services->valiDateRadioAndCheckbox($data);
}
if ($data['level'] == 1) {
if (!$data['link_data']) return app('json')->fail('请选择关联顶级选项');
$data['link_id'] = $data['link_data'][0];
$data['link_value'] = $data['link_data'][1];
}
$data['value'] = json_encode($data['value']);
$config = $this->services->getOne(['menu_name' => $data['menu_name']]);
if ($config) {
@ -120,7 +135,7 @@ class SystemConfig extends AuthController
} else {
$this->services->save($data);
}
\crmeb\services\CacheService::clear();
CacheService::clear();
return app('json')->success(400284);
}
@ -179,20 +194,27 @@ class SystemConfig extends AuthController
['info', ''],
['desc', ''],
['sort', 0],
['level', 0],
['link_data', []],
['status', 0]
]);
if (is_array($data['config_tab_id'])) $data['config_tab_id'] = end($data['config_tab_id']);
if (!$this->services->get($id)) {
return app('json')->fail(100026);
}
if ($data['level'] == 1) {
if (!$data['link_data']) return app('json')->fail('请选择关联顶级选项');
$data['link_id'] = $data['link_data'][0];
$data['link_value'] = $data['link_data'][1];
}
$data['value'] = json_encode($data['value']);
$this->services->update($id, $data);
\crmeb\services\CacheService::clear();
CacheService::clear();
return app('json')->success(100001);
}
/**
* 删除指定资源
*
* @param int $id
* @return \think\Response
*/
@ -201,7 +223,7 @@ class SystemConfig extends AuthController
if (!$this->services->delete($id))
return app('json')->fail(100008);
else {
\crmeb\services\CacheService::clear();
CacheService::clear();
return app('json')->success(100002);
}
}
@ -218,7 +240,7 @@ class SystemConfig extends AuthController
return app('json')->fail(100100);
}
$this->services->update($id, ['status' => $status]);
\crmeb\services\CacheService::clear();
CacheService::clear();
return app('json')->success(100014);
}
@ -307,15 +329,9 @@ class SystemConfig extends AuthController
return app('json')->fail(400763);
}
}
//支付接口类型选择,如果有订单就不能再进行切换
// if (isset($post['pay_wechat_type'])) {
// /** @var StoreOrderServices $orderServices */
// $orderServices = app()->make(StoreOrderServices::class);
// if ($post['pay_wechat_type'] != -1 && $orderServices->count()) {
// return app('json')->fail('支付接口类型已经选择,不能再次进行切换,切换后会导致无法退款等问题。');
// }
// }
if (isset($post['uni_brokerage_price']) && preg_match('/\.[0-9]{2,}[1-9][0-9]*$/', (string)$post['uni_brokerage_price']) > 0) {
return app('json')->fail(500029);
}
if (isset($post['weixin_ckeck_file'])) {
$from = public_path() . $post['weixin_ckeck_file'];
@ -331,9 +347,112 @@ class SystemConfig extends AuthController
@copy($from, $toHome);
@copy($from, $toPublic);
}
if(isset($post['reward_integral']) || isset($post['reward_money'])) {
if($post['reward_integral'] < 0 || $post['reward_money'] < 0) return app('json')->fail(400558);
if (isset($post['reward_integral']) || isset($post['reward_money'])) {
if ($post['reward_money'] < 0) return app('json')->fail('赠送余额不能小于0元');
if ($post['reward_integral'] < 0) return app('json')->fail('赠送积分不能小于0');
}
if (isset($post['sign_give_point'])) {
if (!is_int($post['sign_give_point']) || $post['sign_give_point'] < 0) {
return app('json')->fail('签到赠送积分请填写大于等于0的整数');
}
}
if (isset($post['sign_give_exp'])) {
if ((int)$post['sign_give_exp'] < 0) {
return app('json')->fail('签到赠送经验请填写大于等于0的整数');
}
}
if (isset($post['integral_frozen'])) {
if (!ctype_digit($post['integral_frozen']) || $post['integral_frozen'] < 0) {
return app('json')->fail('积分冻结天数请填写大于等于0的整数');
}
}
if (isset($post['store_free_postage'])) {
if (!is_int($post['store_free_postage']) || $post['store_free_postage'] < 0) {
return app('json')->fail('满额包邮请填写大于等于0的整数');
}
}
if (isset($post['withdrawal_fee'])) {
if ($post['withdrawal_fee'] < 0 || $post['withdrawal_fee'] > 100) {
return app('json')->fail('提现手续费范围在0-100之间');
}
}
if (isset($post['routine_auth_type']) && count($post['routine_auth_type']) == 0) {
return app('json')->fail('微信和手机号登录开关至少开启一个');
}
if (isset($post['integral_max_num'])) {
if (!ctype_digit($post['integral_max_num']) || $post['integral_max_num'] < 0) {
return app('json')->fail('积分抵扣上限请填写大于等于0的整数');
}
}
if (isset($post['customer_phone'])) {
if (!ctype_digit($post['customer_phone']) || strlen($post['customer_phone']) > 11) {
return app('json')->fail('客服手机号为11位数字');
}
}
if (isset($post['refund_time_available'])) {
if (!ctype_digit($post['refund_time_available'])) {
return app('json')->fail('售后期限必须为大于0的整数');
}
}
if (isset($post['sms_save_type']) && sys_config('sms_account', '') != '') {
return app('json')->success(100001);
}
if (isset($post['param_filter_data'])) {
$post['param_filter_data'] = base64_encode($post['param_filter_data']);
}
if (isset($post['product_type_config'])) {
if (count($post['product_type_config']) == 0) {
return app('json')->fail('商品类型至少选择一项');
}
}
if (isset($post['yue_pay_status']) && $post['yue_pay_status'] == 1) {
$post['balance_func_status'] = 1;
}
if (isset($post['pay_weixin_client_cert'])) {
$certData = [
'type' => 'wechat',
'name' => 'pay_weixin_client_cert',
'path' => 'cert' . time() . rand(1000, 9999),
'content' => $post['pay_weixin_client_cert'] != '' ? file_get_contents($this->getPemPath($post['pay_weixin_client_cert'])) : '',
];
$keyData = [
'type' => 'wechat',
'name' => 'pay_weixin_client_key',
'path' => 'key' . time() . rand(1000, 9999),
'content' => $post['pay_weixin_client_key'] != '' ? file_get_contents($this->getPemPath($post['pay_weixin_client_key'])) : '',
];
$systemPemServices = app()->make(SystemPemServices::class);
$systemPemServices->savePem($certData);
$systemPemServices->savePem($keyData);
}
if (isset($post['merchant_cert_path'])) {
$merchantCertData = [
'type' => 'alipay',
'name' => 'merchant_cert_path',
'path' => 'merchant_cert' . time() . rand(1000, 9999),
'content' => $post['merchant_cert_path'] != '' ? file_get_contents($this->getPemPath($post['merchant_cert_path'])) : '',
];
$alipayCertData = [
'type' => 'alipay',
'name' => 'alipay_cert_path',
'path' => 'alipay_cert' . time() . rand(1000, 9999),
'content' => $post['alipay_cert_path'] != '' ? file_get_contents($this->getPemPath($post['alipay_cert_path'])) : '',
];
$alipayRootCertData = [
'type' => 'alipay',
'name' => 'alipay_root_cert_path',
'path' => 'alipay_root_cert' . time() . rand(1000, 9999),
'content' => $post['alipay_root_cert_path'] != '' ? file_get_contents($this->getPemPath($post['alipay_root_cert_path'])) : '',
];
$systemPemServices = app()->make(SystemPemServices::class);
$systemPemServices->savePem($merchantCertData);
$systemPemServices->savePem($alipayCertData);
$systemPemServices->savePem($alipayRootCertData);
}
foreach ($post as $k => $v) {
$config_one = $this->services->getOne(['menu_name' => $k]);
if ($config_one) {
@ -342,9 +461,28 @@ class SystemConfig extends AuthController
$this->services->update($k, ['value' => json_encode($v)], 'menu_name');
}
}
\crmeb\services\CacheService::clear();
CacheService::clear();
return app('json')->success(100001);
}
/**
* 获取证书文件路径
* @param string $path
* @return string
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/10/21
*/
public function getPemPath(string $path)
{
if (strstr($path, 'http://') || strstr($path, 'https://')) {
$path = parse_url($path)['path'] ?? '';
}
$path = root_path('runtime/pem') . ltrim($path, '/');
if (!file_exists($path)) {
$path = public_path('uploads') . ltrim($path, '/');
}
return $path;
}
/**
@ -365,6 +503,7 @@ class SystemConfig extends AuthController
$config_tab = [];
} else {
$config_tab = $services->getConfigTab($pid);
if (empty($config_tab)) $config_tab[] = $services->get($pid, ['id', 'id as value', 'title as label', 'pid', 'icon', 'type']);
}
return app('json')->success(compact('config_tab'));
}

View File

@ -74,7 +74,9 @@ class SystemConfigTab extends AuthController
['type', 0],
['sort', 0],
['pid', 0],
['menus_id', 0],
]);
if (is_array($data['pid'])) $data['pid'] = end($data['pid']);
if (!$data['title']) return app('json')->fail(400291);
$this->services->save($data);
return app('json')->success(400292);
@ -118,7 +120,9 @@ class SystemConfigTab extends AuthController
['type', 0],
['sort', 0],
['pid', 0],
['menus_id', 0],
]);
if (is_array($data['pid'])) $data['pid'] = end($data['pid']);
if (!$data['title']) return app('json')->fail(400291);
if (!$data['eng_title']) return app('json')->fail(400275);
$this->services->update($id, $data);

File diff suppressed because it is too large Load Diff

View File

@ -109,6 +109,10 @@ class SystemGroupData extends AuthController
}
}
}
if ($group && $group['config_name'] == 'user_recharge_quota') {
if ($params['price'] <= 0) return app('json')->fail('售价必须大于0');
if ($params['give_money'] < 0) return app('json')->fail('赠送不能小于0');
}
$this->services->checkSeckillTime($services, $gid, $params);
$this->checkSign($services, $gid, $params);
$fields = json_decode($group['fields'], true) ?? [];
@ -175,6 +179,11 @@ class SystemGroupData extends AuthController
$groupData = $this->services->get($id);
$fields = $services->getValueFields((int)$groupData["gid"]);
$params = request()->post();
$group = $services->getOne(['id' => $params['gid']], 'id,config_name,fields');
if ($group && $group['config_name'] == 'user_recharge_quota') {
if ($params['price'] <= 0) return app('json')->fail('售价必须大于0');
if ($params['give_money'] < 0) return app('json')->fail('赠送不能小于0');
}
$this->services->checkSeckillTime($services, $groupData["gid"], $params, $id);
$this->checkSign($services, $groupData["gid"], $params);
$value = [];
@ -231,7 +240,6 @@ class SystemGroupData extends AuthController
}
/**
* 检查签到配置
* @param SystemGroupServices $services

View File

@ -13,6 +13,8 @@ namespace app\adminapi\controller\v1\setting;
use app\adminapi\controller\AuthController;
use app\services\system\SystemMenusServices;
use app\services\system\SystemRouteCateServices;
use app\services\system\SystemRouteServices;
use think\facade\App;
use think\facade\Route;
@ -38,16 +40,39 @@ class SystemMenus extends AuthController
/**
* 菜单展示列表
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/05/06
*/
public function index()
{
$where = $this->request->getMore([
['is_show', ''],
['keyword', ''],
['auth_type', ''],
]);
return app('json')->success($this->services->getList($where));
}
/**
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/14
*/
public function unique()
{
$adminInfo = $this->request->adminInfo();
[$menus, $uniqueAuth] = app()->make(SystemMenusServices::class)->getMenusList($adminInfo['roles'], (int)$adminInfo['level']);
return app('json')->success(compact('menus', 'uniqueAuth'));
}
/**
* 显示创建资源表单页.
*
@ -86,7 +111,7 @@ class SystemMenus extends AuthController
['is_show', 0],
['is_show_path', 0],
]);
$data['is_show_path'] = $data['is_show'];
if (!$data['menu_name'])
return app('json')->fail(400198);
$data['path'] = implode('/', $data['path']);
@ -97,6 +122,73 @@ class SystemMenus extends AuthController
}
}
/**
* 批量保存权限
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/11
*/
public function batchSave()
{
$menus = $this->request->post('menus', []);
if (!$menus) {
return app('json')->fail(100026);
}
$data = [];
$uniqueAuthAll = $this->services->getColumn(['is_del' => 0, 'is_show' => 1], 'unique_auth');
$uniqueAuthAll = array_filter($uniqueAuthAll, function ($item) {
return !!$item;
});
$uniqueAuthAll = array_unique($uniqueAuthAll);
$uniqueFn = function ($path) use ($uniqueAuthAll) {
$attPath = explode('/', $path);
$uniqueAuth = '';
if ($attPath) {
$pathData = [];
foreach ($attPath as $vv) {
if (strstr($vv, '<') === false) {
$pathData[] = $vv;
}
}
$uniqueAuth = implode('-', $pathData);
}
if (in_array($uniqueAuth, $uniqueAuthAll)) {
$uniqueAuth .= '-' . uniqid();
}
array_push($uniqueAuthAll, $uniqueAuth);
return $uniqueAuth;
};
foreach ($menus as $menu) {
if (empty($menu['menu_name'])) {
return app('json')->fail(400198);
}
if (isset($menu['unique_auth']) && $menu['unique_auth']) {
$menu['unique_auth'] = explode('/', $menu['api_url']);
}
$data[] = [
'methods' => $menu['method'],
'menu_name' => $menu['menu_name'],
'unique_auth' => !empty($menu['unique_auth']) ? $menu['unique_auth'] : $uniqueFn($menu['api_url']),
'api_url' => $menu['api_url'],
'pid' => $menu['path'],
'auth_type' => 2,
'is_show' => 1,
'is_show_path' => 1,
];
}
$this->services->saveAll($data);
return app('json')->success(100021);
}
/**
* 获取一条菜单权限信息
* @param int $id
@ -183,7 +275,7 @@ class SystemMenus extends AuthController
}
/**
* 显示和隐藏
* 权限的开启和关闭,显示和隐藏
* @param $id
* @return mixed
*/
@ -193,9 +285,14 @@ class SystemMenus extends AuthController
return app('json')->fail(100100);
}
[$show] = $this->request->postMore([['is_show', 0]], true);
[$isShow, $isShowPath] = $this->request->postMore([['is_show', 0], ['is_show_path', 0]], true);
if ($isShow == -1) {
$res = $this->services->update($id, ['is_show_path' => $isShowPath]);
} else {
$res = $this->services->update($id, ['is_show' => $isShow, 'is_show_path' => $isShow]);
}
if ($this->services->update($id, ['is_show' => $show])) {
if ($res) {
return app('json')->success(100001);
} else {
return app('json')->fail(100007);
@ -215,26 +312,28 @@ class SystemMenus extends AuthController
return app('json')->success(['menus' => $menus, 'unique' => $unique]);
}
/**
* 获取路由分类
* @param SystemRouteCateServices $service
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/25
*/
public function ruleCate(SystemRouteCateServices $service)
{
return app('json')->success($service->getAllList('adminapi'));
}
/**
* 获取接口列表
* @return array
*/
public function ruleList()
public function ruleList(SystemRouteServices $services)
{
$cateId = request()->get('cate_id', 0);
//获取所有的路由
$ruleList = Route::getRuleList();
$menuApiList = $this->services->getColumn(['auth_type' => 2, 'is_del' => 0], "concat(`api_url`,'_',lower(`methods`)) as rule");
if ($menuApiList) $menuApiList = array_column($menuApiList, 'rule');
$list = [];
foreach ($ruleList as $item) {
$item['rule'] = str_replace('adminapi/', '', $item['rule']);
if (!in_array($item['rule'] . '_' . $item['method'], $menuApiList)) {
$item['real_name'] = $item['option']['real_name'] ?? '';
unset($item['option']);
$item['method'] = strtoupper($item['method']);
$list[] = $item;
}
}
return app('json')->success($list);
$ruleList = $services->selectList(['cate_id' => $cateId, 'app_name' => 'adminapi'])->toArray();
return app('json')->success($ruleList);
}
}

View File

@ -34,8 +34,10 @@ class SystemNotification extends AuthController
/**
* 显示资源列表
*
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
@ -46,9 +48,59 @@ class SystemNotification extends AuthController
}
/**
* 显示编辑
*
* 添加消息
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/2/19
*/
public function notForm($id)
{
return app('json')->success($this->services->getNotForm($id));
}
/**
* 保存自定义消息
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/2/20
*/
public function notFormSave($id)
{
$data = $this->request->postMore([
['custom_trigger', ''],
['name', ''],
['mark', ''],
]);
$this->services->notFormSave($id, $data);
return app('json')->success(100000);
}
/**
* 删除消息
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/2/20
*/
public function delNot($id)
{
if (!$id) return app('json')->fail(100100);
$this->services->delete($id);
return app('json')->success(100002);
}
/**
* 显示编辑
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function info()
{
@ -81,20 +133,24 @@ class SystemNotification extends AuthController
['system_title', ''],
['system_text', ''],
['tempid', ''],
['tempkey', ''],
['content', ''],
['ent_wechat_text', ''],
['url', ''],
['wechat_id', ''],
['routine_id', ''],
['mark', ''],
['sms_id', ''],
['key_list', ''],
['sms_text', ''],
['wechat_link', ''],
['routine_link', ''],
['wechat_to_routine', ''],
]);
if ($data['mark'] == 'verify_code') $data['type'] = 'is_sms';
if (!$data['id']) return app('json')->fail(100100);
if ($this->services->saveData($data)) {
CacheService::delete('NOTICE_SMS_' . $data['mark']);
CacheService::delete('wechat_' . $data['mark']);
CacheService::delete('routine_' . $data['mark']);
CacheService::delete('TEMP_IDS_LIST');
CacheService::clear();
return app('json')->success(100001);
} else {
return app('json')->fail(100007);
@ -117,10 +173,7 @@ class SystemNotification extends AuthController
if ($type == '' || $status == '' || $id == 0) return app('json')->fail(100100);
$this->services->update($id, [$type => $status]);
$res = $this->services->getOneNotce(['id' => $id]);
CacheService::delete('NOTICE_SMS_' . $res->mark);
CacheService::delete('wechat_' . $res->mark);
CacheService::delete('routine_' . $res->mark);
CacheService::delete('TEMP_IDS_LIST');
CacheService::clear();
return app('json')->success(100014);
}
}

View File

@ -91,11 +91,8 @@ class SystemOutAccount extends AuthController
]);
$this->validate($data, StoreOutAccountValidate::class, 'save');
if ($this->services->getOne(['appid' => $data['appid']])) return app('json')->fail('账号重复');
if (!$data['appsecret']) {
unset($data['appsecret']);
} else {
$data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
}
$data['apppwd'] = $data['appsecret'];
$data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
$data['add_time'] = time();
$data['rules'] = implode(',', $data['rules']);
if (!$this->services->save($data)) {
@ -122,12 +119,9 @@ class SystemOutAccount extends AuthController
]);
$this->validate($data, StoreOutAccountValidate::class, 'update');
if (!$data['appsecret']) {
unset($data['appsecret']);
} else {
$data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
}
if (!$this->services->getOne(['id' => $id])) return app('json')->fail('没有此账号');
$data['apppwd'] = $data['appsecret'];
$data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
$data['rules'] = implode(',', $data['rules']);
$res = $this->services->update($id, $data);
if (!$res) {
@ -256,6 +250,6 @@ class SystemOutAccount extends AuthController
['push_password', 0],
['push_token_url', '']
]);
return app('json')->success('100014',$this->services->textOutUrl($data));
return app('json')->success('100014', $this->services->textOutUrl($data));
}
}

View File

@ -77,6 +77,7 @@ class SystemRole extends AuthController
if (!$data['role_name']) return app('json')->fail(400220);
if (!is_array($data['rules']) || !count($data['rules']))
return app('json')->fail(400221);
$data['rules'] = implode(',', $data['rules']);
if ($id) {
if (!$this->services->update($id, $data)) return app('json')->fail(100007);
@ -105,7 +106,7 @@ class SystemRole extends AuthController
if (!$role) {
return app('json')->fail(100100);
}
$menus = $services->getMenus($this->adminInfo['level'] == 0 ? [] : $this->adminInfo['roles']);
$menus = $services->getMenus($this->adminInfo['level'] == 0 ? [] : $this->adminInfo['roles'], explode(',', $role['rules']));
return app('json')->success(['role' => $role->toArray(), 'menus' => $menus]);
}

View File

@ -0,0 +1,170 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace app\adminapi\controller\v1\setting;
use app\adminapi\controller\AuthController;
use app\services\system\SystemRouteServices;
use crmeb\services\CacheService;
use think\facade\App;
/**
* Class SystemRoute
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
* @package app\adminapi\controller\v1\setting
*/
class SystemRoute extends AuthController
{
/**
* SystemRoute constructor.
* @param App $app
* @param SystemRouteServices $services
*/
public function __construct(App $app, SystemRouteServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 同步路由权限
* @param string $appName
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function syncRoute(string $appName = 'adminapi')
{
$this->services->syncRoute($appName);
return app('json')->success(100038);
}
/**
* 列表数据
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/7
*/
public function index()
{
$where = $this->request->getMore([
['name_like', ''],
['app_name', 'adminapi']
]);
return app('json')->success($this->services->getList($where));
}
/**
* tree数据
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/7
*/
public function tree()
{
[$name, $appName] = $this->request->getMore([
['name_like', ''],
['app_name', 'adminapi']
], true);
return app('json')->success($this->services->getTreeList($appName, $name));
}
/**
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/7
*/
public function save($id = 0)
{
$data = $this->request->postMore([
['cate_id', 0],
['name', ''],
['path', ''],
['method', ''],
['type', 0],
['app_name', ''],
['query', []],
['header', []],
['request', []],
['response', []],
['request_example', []],
['response_example', []],
['describe', ''],
['error_code', []],
]);
// if (!$data['name']) {
// return app('json')->fail(500031);
// }
// if (!$data['path']) {
// return app('json')->fail(500032);
// }
// if (!$data['method']) {
// return app('json')->fail(500033);
// }
// if (!$data['app_name']) {
// return app('json')->fail(500034);
// }
if ($id) {
$this->services->update($id, $data);
} else {
$data['add_time'] = date('Y-m-d H:i:s');
$this->services->save($data);
}
CacheService::clear();
return app('json')->success($id ? 100001 : 100021);
}
/**
* @param $id
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/7
*/
public function read($id)
{
return app('json')->success($this->services->getInfo((int)$id));
}
/**
* @param $id
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/7
*/
public function delete($id)
{
if (!$id) {
return app('json')->fail(500035);
}
$this->services->destroy($id);
return app('json')->success(100002);
}
}

View File

@ -0,0 +1,156 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace app\adminapi\controller\v1\setting;
use app\adminapi\controller\AuthController;
use app\services\system\SystemRouteCateServices;
use app\services\system\SystemRouteServices;
use think\facade\App;
use think\Request;
/**
* Class SystemRouteCate
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
* @package app\adminapi\controller\v1\setting
*/
class SystemRouteCate extends AuthController
{
/**
* SystemRouteCate constructor.
* @param App $app
* @param SystemRouteCateServices $services
*/
public function __construct(App $app, SystemRouteCateServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function index()
{
return app('json')->success($this->services->getAllList());
}
/**
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function create()
{
return app('json')->success($this->services->getFrom(0, $this->request->get('app_name', 'adminapi')));
}
/**
* @param Request $request
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function save(Request $request)
{
$data = $request->postMore([
['path', []],
['name', ''],
['sort', 0],
['app_name', ''],
]);
if (!$data['name']) {
return app('json')->fail(500037);
}
$data['add_time'] = time();
$data['pid'] = $data['path'][count($data['path']) - 1] ?? 0;
$this->services->save($data);
return app('json')->success(100000);
}
/**
* @param $id
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function edit($id)
{
return app('json')->success($this->services->getFrom($id, $this->request->get('app_name', 'adminapi')));
}
/**
* @param Request $request
* @param $id
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function update(Request $request, $id)
{
$data = $request->postMore([
['path', []],
['name', ''],
['sort', 0],
['app_name', ''],
]);
if (!$data['name']) {
return app('json')->fail(500037);
}
$data['pid'] = $data['path'][count($data['path']) - 1] ?? 0;
$this->services->update($id, $data);
return app('json')->success(100001);
}
/**
* @param SystemRouteServices $service
* @param $id
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/4/6
*/
public function delete(SystemRouteServices $service, $id)
{
if (!$id) {
return app('json')->fail(500035);
}
if ($service->count(['cate_id' => $id])) {
return app('json')->fail(500038);
}
$this->services->delete($id);
return app('json')->success(100002);
}
}

View File

@ -79,24 +79,17 @@ class SystemStorage extends AuthController
}
/**
* @param SystemConfigServices $services
* @return mixed
*/
public function saveConfig(SystemConfigServices $services)
public function saveConfig( )
{
$type = (int)$this->request->post('type', 0);
// $services->update('upload_type', ['value' => json_encode($type)], 'menu_name');
// if (1 === $type) {
// $this->services->transaction(function () {
// $this->services->update(['status' => 1, 'is_delete' => 0], ['status' => 0]);
// });
// }
// \crmeb\services\CacheService::clear();
$data = $this->request->postMore([
['accessKey', ''],
['secretKey', ''],
['appid', ''],
['storageRegion', ''],
]);
$this->services->saveConfig((int)$type, $data);
@ -166,7 +159,10 @@ class SystemStorage extends AuthController
//设置跨域规则
try {
$upload = UploadService::init($info->type);
$upload->setBucketCors($info->name, $info->region);
$res = $upload->setBucketCors($info->name, $info->region);
if (false === $res) {
return app('json')->fail($upload->getError());
}
} catch (\Throwable $e) {
}
@ -199,6 +195,7 @@ class SystemStorage extends AuthController
public function updateDomain($id)
{
$domain = $this->request->post('domain', '');
$cdn = $this->request->post('cdn', '');
$data = $this->request->postMore([
['pri', ''],
['ca', '']
@ -214,7 +211,7 @@ class SystemStorage extends AuthController
// return app('json')->fail('域名为HTTPS访问时,必须填写证书');
// }
$this->services->updateDomain($id, $domain);
$this->services->updateDomain($id, $domain, ['cdn' => $cdn]);
return app('json')->success(100001);
}

View File

@ -0,0 +1,69 @@
<?php
namespace app\adminapi\controller\v1\statistic;
use app\adminapi\controller\AuthController;
use app\services\user\UserMoneyServices;
use think\facade\App;
class BalanceStatistic extends AuthController
{
/**
* @param App $app
* @param UserMoneyServices $services
*/
public function __construct(App $app, UserMoneyServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 余额统计基础信息
* @return mixed
*/
public function getBasic()
{
$data = $this->services->getBasic();
return app('json')->success($data);
}
/**
* 余额统计趋势图
* @return mixed
*/
public function getTrend()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getTrend($where);
return app('json')->success($data);
}
/**
* 余额来源
* @return mixed
*/
public function getChannel()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getChannel($where);
return app('json')->success($data);
}
/**
* 余额类型
* @return mixed
*/
public function getType()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getType($where);
return app('json')->success($data);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace app\adminapi\controller\v1\statistic;
use app\adminapi\controller\AuthController;
use app\services\statistic\OrderStatisticServices;
use think\facade\App;
class OrderStatistic extends AuthController
{
public function __construct(App $app, OrderStatisticServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 订单统计基础信息
* @return mixed
*/
public function getBasic()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getBasic($where);
return app('json')->success($data);
}
/**
* 订单统计趋势图
* @return mixed
*/
public function getTrend()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getTrend($where);
return app('json')->success($data);
}
/**
* 订单来源
* @return mixed
*/
public function getChannel()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getChannel($where);
return app('json')->success($data);
}
/**
* 订单类型
* @return mixed
*/
public function getType()
{
$where = $this->request->getMore([
['time', '']
]);
$data = $this->services->getType($where);
return app('json')->success($data);
}
}

View File

@ -0,0 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\statistic;
use app\adminapi\controller\AuthController;
use app\services\statistic\ProductStatisticServices;
use think\facade\App;
/**
* Class ProductStatistic
* @package app\adminapi\controller\v1\statistic
*/
class ProductStatistic extends AuthController
{
/**
* ProductStatistic constructor.
* @param App $app
* @param ProductStatisticServices $services
*/
public function __construct(App $app, ProductStatisticServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 商品基础
* @return mixed
*/
public function getBasic()
{
$where = $this->request->getMore([
['data', '', '', 'time']
]);
return app('json')->success($this->services->getBasic($where));
}
/**
* 商品趋势
* @return mixed
*/
public function getTrend()
{
$where = $this->request->getMore([
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getTrend($where));
}
/**
* 商品排行
* @return mixed
*/
public function getProductRanking()
{
$where = $this->request->getMore([
['data', '', '', 'time'],
['sort', '']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getProductRanking($where));
}
/**
* 导出
* @return mixed
*/
public function getExcel()
{
$where = $this->request->getMore([
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getTrend($where, true));
}
/**
* 格式化时间
* @param $time
* @return string
*/
public function getDay($time)
{
if (strstr($time, '-') !== false) {
[$startTime, $endTime] = explode('-', $time);
if (!$startTime || !$endTime) {
return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
} else {
return date('Y/m/d 00:00:00', strtotime($startTime)).'-'.date('Y/m/d 23:59:59', strtotime($endTime));
}
} else {
return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
}
}
}

View File

@ -0,0 +1,74 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\statistic;
use app\adminapi\controller\AuthController;
use app\services\statistic\TradeStatisticServices;
use think\facade\App;
/**
* Class TradeStatistic
* @package app\controller\admin\v1\statistic
*/
class TradeStatistic extends AuthController
{
/**
* TradeStatistic constructor.
* @param App $app
* @param TradeStatisticServices $services
*/
public function __construct(App $app, TradeStatisticServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 顶部数据
* @return mixed
*/
public function topTrade()
{
$leftToday = $this->services->getTopLeftTrade(['time' => 'today']);
$leftyestoday = $this->services->getTopLeftTrade(['time' => 'yestoday']);
$rightOne = $this->services->getTopRightOneTrade();
$rightTwo = $this->services->getTopRightTwoTrade();
$right = ['today' => $rightOne, 'month' => $rightTwo];
$totalleft = [$leftToday, $leftyestoday];
$left = [];
foreach ($totalleft as $k => $v) {
$left['name'] = "当日订单金额";
$left['x'] = $v['curve']['x'];
$left['series'][$k]['money'] = round($v['total_money'], 2);
$left['series'][$k]['value'] = array_values($v['curve']['y']);
}
$data['left'] = $left;
$data['right'] = $right;
return app('json')->success($data);
}
/**
* 底部数据
* @return mixed
*/
public function bottomTrade()
{
$day = $this->request->getMore([
['data', ""],
]);
$bottom = $this->services->getBottomTrade($day);
return app('json')->success($bottom);
}
}

View File

@ -0,0 +1,152 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\statistic;
use app\adminapi\controller\AuthController;
use app\services\statistic\UserStatisticServices;
use think\facade\App;
/**
* Class UserStatistic
* @package app\adminapi\controller\v1\statistic
*/
class UserStatistic extends AuthController
{
/**
* UserStatistic constructor.
* @param App $app
* @param UserStatisticServices $services
*/
public function __construct(App $app, UserStatisticServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 用户基础信息
* @return mixed
*/
public function getBasic()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time']
]);
return app('json')->success($this->services->getBasic($where));
}
/**
* 用户趋势
* @return mixed
*/
public function getTrend()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getTrend($where));
}
/**
* 微信用户信息
* @return mixed
*/
public function getWechat()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getWechat($where));
}
/**
* 微信用户趋势
* @return mixed
*/
public function getWechatTrend()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getWechatTrend($where));
}
/**
* 用户地域
* @return mixed
*/
public function getRegion()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time'],
['sort', 'allNum']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getRegion($where));
}
/**
* 用户性别
* @return mixed
*/
public function getSex()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getSex($where));
}
/**
* 用户统计导出
* @return mixed
*/
public function getExcel()
{
$where = $this->request->getMore([
['channel_type', ''],
['data', '', '', 'time']
]);
$where['time'] = $this->getDay($where['time']);
return app('json')->success($this->services->getTrend($where, true));
}
/**
* 格式化时间
* @param $time
* @return string
*/
public function getDay($time)
{
if (strstr($time, '-') !== false) {
[$startTime, $endTime] = explode('-', $time);
if (!$startTime || !$endTime) {
return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
} else {
return date('Y/m/d 00:00:00', strtotime($startTime)).'-'.date('Y/m/d 23:59:59', strtotime($endTime));
}
} else {
return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
}
}
}

View File

@ -36,7 +36,10 @@ class AppVersion extends AuthController
/**
* 版本列表
* @return mixed
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/4/2
*/
public function list()
{
@ -48,7 +51,12 @@ class AppVersion extends AuthController
/**
* 新增版本表单
* @return mixed
* @param $id
* @return \think\Response
* @throws \FormBuilder\Exception\FormBuilderException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/4/2
*/
public function crate($id)
{
@ -57,7 +65,10 @@ class AppVersion extends AuthController
/**
* 保存数据
* @return mixed
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/4/2
*/
public function save()
{
@ -75,4 +86,18 @@ class AppVersion extends AuthController
$this->services->versionSave($id, $data);
return app('json')->success(100021);
}
/**
* 删除App版本
* @param $id
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/4/2
*/
public function del($id)
{
$this->services->delete($id);
return app('json')->success('删除成功');
}
}

View File

@ -100,11 +100,15 @@ class SystemClearData extends AuthController
* 清除回收站商品
* @return mixed
*/
public function recycleProduct()
public function recycleProduct($id = 0)
{
/** @var StoreProductServices $product */
$product = app()->make(StoreProductServices::class);
$ids = $product->getColumn(['is_del' => 1], 'id');
if ($id) {
$ids = [$id];
} else {
$ids = $product->getColumn(['is_del' => 1], 'id');
}
//清除规格表数据
/** @var StoreProductAttrServices $ProductAttr */
$productAttr = app()->make(StoreProductAttrServices::class);
@ -136,7 +140,7 @@ class SystemClearData extends AuthController
//删除商品收藏记录
/** @var StoreProductReplyServices $productRelation */
$productRelation = app()->make(StoreProductReplyServices::class);
$productRelation->delete([['product_id', 'in', $ids], ['category', '=', 'product']]);
$productRelation->delete([['product_id', 'in', $ids], ['reply_type', '=', 'product']]);
//删除商品的评论
/** @var StoreProductReplyServices $productReply */
@ -145,8 +149,13 @@ class SystemClearData extends AuthController
/** @var StoreProductServices $services */
$services = app()->make(StoreProductServices::class);
$services->delete(1, 'is_del');
return app('json')->success(100046);
if ($id) {
$services->delete($id);
return true;
} else {
$services->delete(1, 'is_del');
return app('json')->success(100046);
}
}
/**

View File

@ -0,0 +1,145 @@
<?php
namespace app\adminapi\controller\v1\system;
use app\adminapi\controller\AuthController;
use app\services\system\crontab\SystemCrontabServices;
use think\facade\App;
use think\facade\Env;
class SystemCrontab extends AuthController
{
public function __construct(App $app, SystemCrontabServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 获取定时任务列表
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getTimerList()
{
$where = $this->request->getMore([
['custom', 0],
]);
$where['is_del'] = 0;
return app('json')->success($this->services->getTimerList($where));
}
/**
* 获取定时任务详情
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getTimerInfo($id)
{
return app('json')->success($this->services->getTimerInfo($id));
}
/**
* 获取定时任务类型
* @return mixed
*/
public function getMarkList()
{
return app('json')->success($this->services->getMarkList());
}
/**
* 保存定时任务
* @return mixed
*/
public function saveTimer()
{
$data = $this->request->postMore([
['id', 0],
['name', ''],
['mark', ''],
['content', ''],
['type', 0],
['is_open', 0],
['month', 0],
['week', 0],
['day', 0],
['hour', 0],
['minute', 0],
['second', 0],
['customCode', ''],
['password', ''],
]);
if ($data['mark'] == 'customTimer') {
if (!Env::get('app_debug', false)) return app('json')->fail('生产环境下无法新增和修改自定义内容,如需修改请修改.env文件中app_debug项为true');
if ($data['password'] === '') return app('json')->fail('密码不能为空');
if (config('filesystem.password') !== $data['password']) return app('json')->fail('密码错误');
$adminInfo = $this->request->adminInfo();
if (!$adminInfo) return app('json')->fail('非法操作');
if ($adminInfo['level'] != 0) return app('json')->fail('仅超级管理员可以操作定时任务');
if (!$this->isSafePhpCode($data['customCode'])) return app('json')->fail('自定义内容存在危险代码,请检查代码');
}
$this->services->saveTimer($data);
return app('json')->success(100000);
}
/**
* 删除定时任务
* @param $id
* @return mixed
*/
public function delTimer($id)
{
$this->services->delTimer($id);
return app('json')->success(100002);
}
/**
* 设置定时任务状态
* @param $id
* @param $is_open
* @return mixed
*/
public function setTimerStatus($id, $is_open)
{
$this->services->setTimerStatus($id, $is_open);
return app('json')->success(100014);
}
/**
* 检查是否包含删除表,删除表数据,删除文件,修改文件内容以及后缀,执行命令等操作的关键词
* @param $code
* @return bool
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/6
*/
function isSafePhpCode($code)
{
// 检查是否包含删除表,删除表数据,删除文件,修改文件内容以及后缀,执行命令等操作的关键词
$dangerous_keywords = array(
'delete',
'destroy',
'DROP TABLE',
'DELETE FROM',
'unlink(',
'fwrite(',
'shell_exec(',
'exec(',
'system(',
'passthru('
);
foreach ($dangerous_keywords as $keyword) {
if (strpos($code, $keyword) !== false) {
return false;
}
}
return true; // 如果通过所有安全检查,返回 true
}
}

View File

@ -11,6 +11,7 @@
namespace app\adminapi\controller\v1\system;
use think\facade\App;
use think\facade\Db;
use think\facade\Session;
use app\adminapi\controller\AuthController;
use app\services\system\SystemDatabackupServices;
@ -49,16 +50,57 @@ class SystemDatabackup extends AuthController
*/
public function read()
{
$tablename = request()->param('tablename', '', 'htmlspecialchars');
[$tablename] = $this->request->getMore([
['tablename', ''],
], true);
return app('json')->success($this->services->getRead($tablename));
}
/**
* 更新数据表或者表字段备注
* @return \think\Response
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/04/11
*/
public function updateMark()
{
[$table, $field, $type, $mark, $is_field] = $this->request->postMore([
['table', ''],
['field', ''],
['type', ''],
['mark', ''],
['is_field', 0],
], true);
if ($is_field == 0) {
$sql = "ALTER TABLE $table COMMENT '$mark'";
} else {
$fieldInfo = Db::query("SHOW FULL COLUMNS FROM `{$table}` WHERE Field = '{$field}'");
$sql = "ALTER TABLE $table MODIFY COLUMN ";
$sql .= $field . ' ' . $type . ' ';
if ($fieldInfo[0]['Null'] == 'NO') {
$sql .= 'NOT NULL ';
if (!is_null($fieldInfo[0]['Default'])) {
$sql .= "DEFAULT '" . $fieldInfo[0]['Default'] . "' ";
}
}
if ($fieldInfo[0]['Extra']) {
$sql .= $fieldInfo[0]['Extra'] . ' ';
}
$sql .= "COMMENT '$mark'";
}
Db::execute($sql);
return app('json')->success(100024);
}
/**
* 优化表
*/
public function optimize()
{
$tables = $this->request->param('tables', '', 'htmlspecialchars');
[$tables] = $this->request->postMore([
['tables', ''],
], true);
$res = $this->services->getDbBackup()->optimize($tables);
return app('json')->success($res ? 100047 : 100048);
}
@ -68,7 +110,9 @@ class SystemDatabackup extends AuthController
*/
public function repair()
{
$tables = $this->request->param('tables', '', 'htmlspecialchars');
[$tables] = $this->request->postMore([
['tables', ''],
], true);
$res = $this->services->getDbBackup()->repair($tables);
return app('json')->success($res ? 100049 : 100050);
}
@ -78,7 +122,9 @@ class SystemDatabackup extends AuthController
*/
public function backup()
{
$tables = $this->request->param('tables', '', 'htmlspecialchars');
[$tables] = $this->request->postMore([
['tables', ''],
], true);
$data = $this->services->backup($tables);
return app('json')->success(100051);
}

View File

@ -0,0 +1,157 @@
<?php
namespace app\adminapi\controller\v1\system;
use app\adminapi\controller\AuthController;
use app\services\system\SystemEventServices;
use think\facade\App;
use think\facade\Env;
class SystemEvent extends AuthController
{
public function __construct(App $app, SystemEventServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 自定事件类型
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
public function getMarkList()
{
return app('json')->success($this->services->getMarkList());
}
/**
* 自定事件列表
* @return \think\Response
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
public function getEventList()
{
return app('json')->success($this->services->getEventList());
}
/**
* 自定事件详情
* @param $id
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
public function getEventInfo($id)
{
if (!$id) return app('json')->fail('参数错误');
return app('json')->success($this->services->getEventInfo($id));
}
/**
* 自定事件添加编辑
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
public function saveEvent()
{
$data = $this->request->postMore([
['id', 0],
['name', ''],
['mark', ''],
['content', ''],
['is_open', 0],
['customCode', ''],
['password', ''],
]);
if ($data['name'] == '') return app('json')->fail('请填写事件名称');
if ($data['mark'] == '') return app('json')->fail('请选择事件类型');
if (!Env::get('app_debug', false)) return app('json')->fail('生产环境下无法新增和修改自定义内容,如需修改请修改.env文件中app_debug项为true');
if ($data['password'] === '') return app('json')->fail('密码不能为空');
if (config('filesystem.password') !== $data['password']) return app('json')->fail('密码错误');
$adminInfo = $this->request->adminInfo();
if (!$adminInfo) return app('json')->fail('非法操作');
if ($adminInfo['level'] != 0) return app('json')->fail('仅超级管理员可以操作定时任务');
if (!$this->isSafePhpCode($data['customCode'])) return app('json')->fail('自定义内容存在危险代码,请检查代码');
$this->services->saveEvent($data);
return app('json')->success(100000);
}
/**
* 检查是否包含删除表,删除表数据,删除文件,修改文件内容以及后缀,执行命令等操作的关键词
* @param $code
* @return bool
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
function isSafePhpCode($code)
{
// 检查是否包含删除表,删除表数据,删除文件,修改文件内容以及后缀,执行命令等操作的关键词
$dangerous_keywords = [
'delete',
'destroy',
'DROP TABLE',
'DELETE FROM',
'unlink(',
'fwrite(',
'shell_exec(',
'exec(',
'system(',
'passthru('
];
foreach ($dangerous_keywords as $keyword) {
if (strpos($code, $keyword) !== false) {
return false;
}
}
return true; // 如果通过所有安全检查,返回 true
}
/**
* 自定事件是否开启开关
* @param $id
* @param $is_open
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
public function setEventStatus($id, $is_open)
{
$this->services->setEventStatus($id, $is_open);
return app('json')->success(100014);
}
/**
* 删除自定事件
* @param $id
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/6/7
*/
public function delEvent($id)
{
if (!$id) return app('json')->fail('参数错误');
$this->services->eventDel($id);
return app('json')->success(100002);
}
}

View File

@ -69,7 +69,36 @@ class SystemFile extends AuthController
//打开目录
public function opendir()
{
return app('json')->success($this->services->opendir());
[$dir, $fileDir, $superior] = $this->request->getMore([
['dir', ''],
['filedir', ''],
['superior', ''],
], true);
return app('json')->success($this->services->opendir($dir, $fileDir, $superior));
}
//文件备注
public function fileMark()
{
[$path, $fileToken] = $this->request->postMore([
['path', ''],
['fileToken', ''],
], true);
if ($path == '') return app('json')->fail(100100);
return app('json')->success($this->services->markForm($path, $fileToken));
}
//文件备注保存
public function fileMarkSave()
{
[$full_path, $mark] = $this->request->postMore([
['full_path', ''],
['mark', ''],
], true);
$full_path = $this->request->param('full_path');
if ($full_path == '') return app('json')->fail(100100);
$this->services->fileMarkSave($full_path, $mark);
return app('json')->success(100000);
}
//读取文件
@ -86,7 +115,7 @@ class SystemFile extends AuthController
$comment = $this->request->param('comment');
$filepath = $this->request->param('filepath');
if (empty($filepath)) {
return app('json')->fail(410087);
return app('json')->fail('文件路径不存在');
}
$res = $this->services->savefile($filepath, $comment);
if ($res) {

View File

@ -0,0 +1,88 @@
<?php
namespace app\adminapi\controller\v1\system;
use app\adminapi\controller\AuthController;
use app\services\system\SystemTicketServices;
use think\facade\App;
class SystemTicket extends AuthController
{
public function __construct(App $app, SystemTicketServices $services)
{
parent::__construct($app);
$this->services = $services;
}
public function ticketList()
{
$where = $this->request->getMore([
['type', 0],
['keyword', ''],
]);
return app('json')->success($this->services->ticketList($where));
}
public function ticketForm($id)
{
return app('json')->success($this->services->ticketForm($id));
}
public function ticketSave($id)
{
$data = $this->request->postMore([
['print_name', ''],
['type', 0],
['yly_user_id', ''],
['yly_app_id', ''],
['yly_app_secret', ''],
['yly_sn', ''],
['fey_user', ''],
['fey_ukey', ''],
['fey_sn', ''],
['times', 1],
['print_type', 1],
['status', 1],
]);
$this->services->ticketSave($id, $data);
return app('json')->success('保存成功');
}
public function ticketSetStatus($id, $status)
{
$this->services->ticketSetStatus($id, $status);
return app('json')->success('修改成功');
}
public function ticketDel($id)
{
$this->services->ticketDel($id);
return app('json')->success('删除成功');
}
public function ticketContent($id)
{
return app('json')->success($this->services->ticketContent($id));
}
public function ticketContentSave($id)
{
$data = $this->request->postMore([
['header', 0],
['delivery', 0],
['buyer_remarks', 0],
['goods', []],
['freight', 0],
['preferential', 0],
['pay', []],
['custom', 0],
['order', []],
['code', 0],
['code_url', ''],
['show_notice', 0],
['notice_content', '']
]);
$this->services->ticketContentSave($id, $data);
return app('json')->success('保存成功');
}
}

View File

@ -1,92 +0,0 @@
<?php
namespace app\adminapi\controller\v1\system;
use app\adminapi\controller\AuthController;
use app\services\system\timer\SystemTimerServices;
use think\facade\App;
class SystemTimer extends AuthController
{
public function __construct(App $app, SystemTimerServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 获取定时任务列表
* @return mixed
*/
public function getTimerList()
{
$where = ['is_del' => 0];
return app('json')->success($this->services->getTimerList($where));
}
/**
* 获取定时任务详情
* @param $id
* @return mixed
*/
public function getTimerInfo($id)
{
return app('json')->success($this->services->getTimerInfo($id));
}
/**
* 获取定时任务类型
* @return mixed
*/
public function getMarkList()
{
return app('json')->success($this->services->getMarkList());
}
/**
* 保存定时任务
* @return mixed
*/
public function saveTimer()
{
$data = $this->request->postMore([
['id', 0],
['name', ''],
['mark', ''],
['content', ''],
['type', 0],
['is_open', 0],
['week', 0],
['day', 0],
['hour', 0],
['minute', 0],
['second', 0],
]);
$this->services->saveTimer($data);
return app('json')->success(100000);
}
/**
* 删除定时任务
* @param $id
* @return mixed
*/
public function delTimer($id)
{
$this->services->delTimer($id);
return app('json')->success(100002);
}
/**
* 设置定时任务状态
* @param $id
* @param $is_open
* @return mixed
*/
public function setTimerStatus($id, $is_open)
{
$this->services->setTimerStatus($id, $is_open);
return app('json')->success(100014);
}
}

View File

@ -10,8 +10,10 @@
// +----------------------------------------------------------------------
namespace app\adminapi\controller\v1\user;
use app\services\system\config\SystemConfigServices;
use app\services\user\UserServices;
use app\adminapi\controller\AuthController;
use crmeb\services\CacheService;
use think\exception\ValidateException;
use think\facade\App;
@ -55,8 +57,16 @@ class User extends AuthController
['label_id', ''],
['now_money', 'normal'],
['field_key', ''],
['isMember', '']
['isMember', ''],
['balance', []],
['integral', []],
['before_pay_time', ''],
['pay_count_num', []],
['pay_count_money', []],
['recharge_count', []],
['agent_level', 0],
]);
$where['label_id'] = toIntArray($where['label_id']);
return app('json')->success($this->services->index($where));
}
@ -123,20 +133,19 @@ class User extends AuthController
if ($data['card_id']) {
if (!check_card($data['card_id'])) return app('json')->fail(400315);
}
if ($data['pwd']) {
if (!$data['true_pwd']) {
return app('json')->fail(400263);
}
if ($data['pwd'] != $data['true_pwd']) {
return app('json')->fail(400264);
}
if (strlen($data['pwd']) < 6 || strlen($data['pwd']) > 32) {
return app('json')->fail(400762);
}
$data['pwd'] = md5($data['pwd']);
} else {
unset($data['pwd']);
if (!$data['pwd']) {
return app('json')->fail(400256);
}
if (!$data['true_pwd']) {
return app('json')->fail(400263);
}
if ($data['pwd'] != $data['true_pwd']) {
return app('json')->fail(400264);
}
if (strlen($data['pwd']) < 6 || strlen($data['pwd']) > 32) {
return app('json')->fail(400762);
}
$data['pwd'] = md5($data['pwd']);
unset($data['true_pwd']);
$data['avatar'] = sys_config('h5_avatar');
$data['adminId'] = $this->adminId;
@ -171,6 +180,9 @@ class User extends AuthController
* 获取用户账户详情
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function read($id)
{
@ -195,6 +207,9 @@ class User extends AuthController
* 执行赠送会员等级
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function save_give_level($id)
{
@ -209,6 +224,7 @@ class User extends AuthController
* 赠送付费会员时长表单
* @param $id
* @return mixed
* @throws \FormBuilder\Exception\FormBuilderException
*/
public function give_level_time($id)
{
@ -220,6 +236,9 @@ class User extends AuthController
* 执行赠送付费会员时长
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function save_give_level_time($id)
{
@ -306,10 +325,10 @@ class User extends AuthController
* @return mixed
* @throws \FormBuilder\Exception\FormBuilderException
*/
public function edit_other($id)
public function edit_other($id, $type)
{
if (!$id) return app('json')->fail(100026);
return app('json')->success($this->services->editOther((int)$id));
return app('json')->success($this->services->editOther((int)$id, $type));
}
/**
@ -379,9 +398,18 @@ class User extends AuthController
['spread_open', 1]
]);
if (!$id) return app('json')->fail(100100);
if (!$data['real_name']) {
return app('json')->fail(410245);
}
if (!$data['phone']) {
return app('json')->fail(410245);
}
if ($data['phone']) {
if (!preg_match("/^1[3456789]\d{9}$/", $data['phone'])) return app('json')->fail(400252);
}
if ($this->services->count(['phone' => $data['phone'], 'is_del' => 0, 'not_uid' => $id])) {
return app('json')->fail(400314);
}
if ($data['card_id']) {
if (!check_card($data['card_id'])) return app('json')->fail(400315);
}
@ -431,4 +459,42 @@ class User extends AuthController
return app('json')->success(400318);
}
/**
* 新人礼
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/9/21
*/
public function getNewGift()
{
$data = [
'reward_money' => intval(sys_config('reward_money')),
'reward_integral' => intval(sys_config('reward_integral')),
'reward_coupon' => sys_config('reward_coupon') == '' ? [] : sys_config('reward_coupon')
];
return app('json')->success($data);
}
/**
* 保存新人礼
* @return \think\Response
* @author wuhaotian
* @email 442384644@qq.com
* @date 2024/9/21
*/
public function saveNewGift()
{
$data = $this->request->postMore([
['reward_money', 0],
['reward_integral', 0],
['reward_coupon', '']
]);
$configServices = app()->make(SystemConfigServices::class);
foreach ($data as $k => $v) {
$configServices->update($k, ['value' => json_encode($v)], 'menu_name');
}
CacheService::clear();
return app('json')->success('保存成功');
}
}

View File

@ -37,9 +37,13 @@ class UserLabel extends AuthController
/**
* 标签列表
* @param int $label_cate
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index($label_cate = 0)
public function index($label_cate = '')
{
return app('json')->success($this->services->getList(['label_cate' => $label_cate]));
}
@ -60,8 +64,10 @@ class UserLabel extends AuthController
/**
* 保存标签表单数据
* @param int $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function save()
{

View File

@ -43,14 +43,13 @@ class MemberCardBatch extends AuthController
{
$where = $this->request->getMore([
['title', ''],
// ['page', 1],
// ['limit', 20],
]);
$data = $this->services->getList($where);
return app('json')->success($data);
}
/** 保存卡片资源
/**
* 保存卡片资源
* @param $id
* @return mixed
*/

View File

@ -25,21 +25,34 @@ use crmeb\services\CacheService;
*/
class AdminAuthTokenMiddleware implements MiddlewareInterface
{
/**
* @param Request $request
* @param \Closure $next
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/04/07
*/
public function handle(Request $request, \Closure $next)
{
$authInfo = null;
$token = trim(ltrim($request->header(Config::get('cookie.token_name', 'Authori-zation')), 'Bearer'));
if (!$token) {
$token = trim(ltrim($request->get('token')));
}
/** @var AdminAuthServices $service */
$service = app()->make(AdminAuthServices::class);
$adminInfo = $service->parseToken($token);
Request::macro('isAdminLogin', function () use (&$adminInfo) {
$request->macro('isAdminLogin', function () use (&$adminInfo) {
return !is_null($adminInfo);
});
Request::macro('adminId', function () use (&$adminInfo) {
$request->macro('adminId', function () use (&$adminInfo) {
return $adminInfo['id'];
});
Request::macro('adminInfo', function () use (&$adminInfo) {
$request->macro('adminInfo', function () use (&$adminInfo) {
return $adminInfo;
});

View File

@ -14,66 +14,106 @@ use think\facade\Route;
* 分销管理 相关路由
*/
Route::group('agent', function () {
//推销员列表
Route::get('index', 'v1.agent.AgentManage/index')->option(['real_name' => '分销员列表']);
//修改上级推广人
Route::put('spread', 'v1.agent.AgentManage/editSpread')->option(['real_name' => '修改上级推广人']);
//头部统计
Route::get('statistics', 'v1.agent.AgentManage/get_badge')->option(['real_name' => '分销员列表头部统计']);
//推广人列表
Route::get('stair', 'v1.agent.AgentManage/get_stair_list')->option(['real_name' => '推广人列表']);
//推广人头部统计
// Route::get('stair/statistics', 'v1.agent.AgentManage/get_stair_badge')->option(['real_name' => '推广人头部统计']);
//统计推广订单列表
Route::get('stair/order', 'v1.agent.AgentManage/get_stair_order_list')->option(['real_name' => '推广订单列表']);
//统计推广订单列表头部
// Route::get('stair/order/statistics', 'v1.agent.AgentManage/get_stair_order_badge')->option(['real_name' => '推广订单列表头部']);
//清除上级推广人
Route::put('stair/delete_spread/:uid', 'v1.agent.AgentManage/delete_spread')->option(['real_name' => '清除上级推广人']);
//取消推广资格
Route::put('stair/delete_system_spread/:uid', 'v1.agent.AgentManage/delete_system_spread')->option(['real_name' => '取消推广资格']);
//查看公众号推广二维码
Route::get('look_code', 'v1.agent.AgentManage/look_code')->option(['real_name' => '查看公众号推广二维码']);
//查看小程序推广二维码
Route::get('look_xcx_code', 'v1.agent.AgentManage/look_xcx_code')->option(['real_name' => '查看小程序推广二维码']);
//查看H5推广二维码
Route::get('look_h5_code', 'v1.agent.AgentManage/look_h5_code')->option(['real_name' => '查看H5推广二维码']);
//积分配置编辑表单
Route::get('config/edit_basics', 'v1.setting.SystemConfig/edit_basics')->option(['real_name' => '积分配置编辑表单']);
//积分配置保存数据
Route::post('config/save_basics', 'v1.setting.SystemConfig/save_basics')->option(['real_name' => '积分配置保存数据']);
//分销员等级资源路由
Route::resource('level', 'v1.agent.AgentLevel')->name('AgentLevelResource')->option(['real_name' => '分销员等级']);
//修改分销等级状态
Route::put('level/set_status/:id/:status', 'v1.agent.AgentLevel/set_status')->name('levelSetStatus')->option(['real_name' => '修改分销等级状态']);
//分销员等级任务资源路由
Route::resource('level_task', 'v1.agent.AgentLevelTask')->name('AgentLevelTaskResource')->option(['real_name' => '分销员等级任务']);
//修改分销任务状态
Route::put('level_task/set_status/:id/:status', 'v1.agent.AgentLevelTask/set_status')->name('levelTaskSetStatus')->option(['real_name' => '修改分销等级任务状态']);
//获取赠送分销等级表单
Route::get('get_level_form', 'v1.agent.AgentManage/getLevelForm')->name('getLevelForm')->option(['real_name' => '获取赠送分销等级表单']);
//赠送分销等级
Route::post('give_level', 'v1.agent.AgentManage/giveAgentLevel')->name('giveAgentLevel')->option(['real_name' => '赠送分销等级']);
/** 分销员管理 */
Route::group(function () {
//推销员列表
Route::get('index', 'v1.agent.AgentManage/index')->option(['real_name' => '分销员列表']);
//修改上级推广人
Route::put('spread', 'v1.agent.AgentManage/editSpread')->option(['real_name' => '修改上级推广人']);
//头部统计
Route::get('statistics', 'v1.agent.AgentManage/get_badge')->option(['real_name' => '分销员列表头部统计']);
//推广人列表
Route::get('stair', 'v1.agent.AgentManage/get_stair_list')->option(['real_name' => '推广人列表']);
//统计推广订单列表
Route::get('stair/order', 'v1.agent.AgentManage/get_stair_order_list')->option(['real_name' => '推广订单列表']);
//清除上级推广人
Route::put('stair/delete_spread/:uid', 'v1.agent.AgentManage/delete_spread')->option(['real_name' => '清除上级推广人']);
//取消推广资格
Route::put('stair/delete_system_spread/:uid', 'v1.agent.AgentManage/delete_system_spread')->option(['real_name' => '取消推广资格']);
//查看公众号推广二维码
Route::get('look_code', 'v1.agent.AgentManage/look_code')->option(['real_name' => '查看公众号推广二维码']);
//查看小程序推广二维码
Route::get('look_xcx_code', 'v1.agent.AgentManage/look_xcx_code')->option(['real_name' => '查看小程序推广二维码']);
//查看H5推广二维码
Route::get('look_h5_code', 'v1.agent.AgentManage/look_h5_code')->option(['real_name' => '查看H5推广二维码']);
})->option(['parent' => 'agent', 'cate_name' => '分销员管理']);
/** 分销设置 */
Route::group(function () {
//分销配置编辑表单
Route::get('config/edit_basics', 'v1.setting.SystemConfig/edit_basics')->option(['real_name' => '积分配置编辑表单']);
//分销配置保存数据
Route::post('config/save_basics', 'v1.setting.SystemConfig/save_basics')->option(['real_name' => '积分配置保存数据']);
})->option(['parent' => 'agent', 'cate_name' => '分销设置']);
/** 分销等级 */
Route::group(function () {
//分销员等级资源路由
Route::resource('level', 'v1.agent.AgentLevel')->except(['read'])->name('AgentLevel')->option([
'real_name' => [
'index' => '获取分销员等级列表',
'create' => '获取分销员等级表单',
'save' => '保存分销员等级',
'edit' => '获取修改分销员等级表单',
'update' => '修改分销员等级',
'delete' => '删除分销员等级'
]
]);
//修改分销等级状态
Route::put('level/set_status/:id/:status', 'v1.agent.AgentLevel/set_status')->name('levelSetStatus')->option(['real_name' => '修改分销等级状态']);
//分销员等级任务资源路由
Route::resource('level_task', 'v1.agent.AgentLevelTask')->except(['read'])->option([
'real_name' => [
'index' => '获取分销员等级任务列表',
'create' => '获取分销员等级任务表单',
'save' => '保存分销员等级任务',
'edit' => '获取修改分销员等级任务表单',
'update' => '修改分销员等级任务',
'delete' => '删除分销员等级任务'
]
]);
//修改分销任务状态
Route::put('level_task/set_status/:id/:status', 'v1.agent.AgentLevelTask/set_status')->name('levelTaskSetStatus')->option(['real_name' => '修改分销等级任务状态']);
//获取赠送分销等级表单
Route::get('get_level_form', 'v1.agent.AgentManage/getLevelForm')->name('getLevelForm')->option(['real_name' => '获取赠送分销等级表单']);
//赠送分销等级
Route::post('give_level', 'v1.agent.AgentManage/giveAgentLevel')->name('giveAgentLevel')->option(['real_name' => '赠送分销等级']);
//设置任务完成数量表单
Route::get('get_task_num_form/:id', 'v1.agent.AgentLevel/getTaskNumForm')->name('getTaskNumForm')->option(['real_name' => '获取任务完成数量表单']);
//设置完成任务数量
Route::post('set_task_num/:id', 'v1.agent.AgentLevel/setTaskNum')->name('setTaskNum')->option(['real_name' => '设置完成任务数量']);
})->option(['parent' => 'agent', 'cate_name' => '分销等级']);
/** 事业部 */
Route::get('division/list', 'v1.agent.Division/divisionList')->name('divisionList')->option(['real_name' => '事业部列表']);//事业部/代理商/员工列表
Route::get('division/down_list', 'v1.agent.Division/divisionDownList')->name('divisionDownList')->option(['real_name' => '下级列表']);//下级列表
Route::get('division/create/:uid', 'v1.agent.Division/divisionCreate')->name('divisionCreate')->option(['real_name' => '添加事业部']);//添加事业部
Route::post('division/save', 'v1.agent.Division/divisionSave')->name('divisionSave')->option(['real_name' => '事业部保存']);//事业部保存
Route::get('division/agent/create/:uid', 'v1.agent.Division/divisionAgentCreate')->name('divisionAgentCreate')->option(['real_name' => '添加事业部']);//添加代理商
Route::post('division/agent/save', 'v1.agent.Division/divisionAgentSave')->name('divisionAgentSave')->option(['real_name' => '事业部保存']);//代理商保存
Route::put('division/set_status/:status/:uid', 'v1.agent.Division/setDivisionStatus')->name('setDivisionStatus')->option(['real_name' => '状态切换']);//状态切换
Route::delete('division/del/:type/:uid', 'v1.agent.Division/delDivision')->name('delDivision')->option(['real_name' => '删除代理商']);//状态切换
Route::get('division/agent_apply/list','v1.agent.Division/AdminApplyList')->name('AdminApplyList')->option(['real_name'=>'代理商申请列表']);//代理商申请列表
Route::get('division/examine_apply/:id/:type','v1.agent.Division/examineApply')->name('examineApply')->option(['real_name'=>'审核表单']);//审核表单
Route::post('division/apply_agent/save','v1.agent.Division/applyAgentSave')->name('applyAgentSave')->option(['real_name'=>'提交审核']);//提交审核
Route::delete('division/del_apply/:id','v1.agent.Division/delApply')->name('delApply')->option(['real_name'=>'删除审核']);//删除审核
Route::group(function () {
Route::get('division/list', 'v1.agent.Division/divisionList')->name('divisionList')->option(['real_name' => '事业部列表']);//事业部/代理商/员工列表
Route::get('division/down_list', 'v1.agent.Division/divisionDownList')->name('divisionDownList')->option(['real_name' => '下级列表']);//下级列表
Route::get('division/create/:uid', 'v1.agent.Division/divisionCreate')->name('divisionCreate')->option(['real_name' => '添加事业部']);//添加事业部
Route::post('division/save', 'v1.agent.Division/divisionSave')->name('divisionSave')->option(['real_name' => '事业部保存']);//事业部保存
Route::get('division/agent/create/:uid', 'v1.agent.Division/divisionAgentCreate')->name('divisionAgentCreate')->option(['real_name' => '添加事业部']);//添加代理商
Route::post('division/agent/save', 'v1.agent.Division/divisionAgentSave')->name('divisionAgentSave')->option(['real_name' => '事业部保存']);//代理商保存
Route::put('division/set_status/:status/:uid', 'v1.agent.Division/setDivisionStatus')->name('setDivisionStatus')->option(['real_name' => '状态切换']);//状态切换
Route::delete('division/del/:type/:uid', 'v1.agent.Division/delDivision')->name('delDivision')->option(['real_name' => '删除代理商']);//状态切换
Route::get('division/staff/create/:uid', 'v1.agent.Division/divisionStaffCreate')->name('divisionStaffCreate')->option(['real_name' => '添加事业部']);//添加代理商
Route::post('division/staff/save', 'v1.agent.Division/divisionStaffSave')->name('divisionStaffSave')->option(['real_name' => '事业部保存']);//代理商保存
Route::get('division/agent_apply/list', 'v1.agent.Division/AdminApplyList')->name('AdminApplyList')->option(['real_name' => '代理商申请列表']);//代理商申请列表
Route::get('division/examine_apply/:id/:type', 'v1.agent.Division/examineApply')->name('examineApply')->option(['real_name' => '审核表单']);//审核表单
Route::post('division/apply_agent/save', 'v1.agent.Division/applyAgentSave')->name('applyAgentSave')->option(['real_name' => '提交审核']);//提交审核
Route::delete('division/del_apply/:id', 'v1.agent.Division/delApply')->name('delApply')->option(['real_name' => '删除审核']);//删除审核
Route::get('division/statistics', 'v1.agent.Division/divisionStatistics')->name('divisionStatistics')->option(['real_name' => '事业部统计']);//事业部统计
})->option(['parent' => 'agent', 'cate_name' => '事业部']);
/** 分销员申请 */
Route::group(function () {
Route::get('spread/apply/list', 'v1.agent.SpreadApply/applyList')->name('applyList')->option(['real_name' => '分销员申请列表']);
Route::post('spread/apply/examine/:id/:uid/:status', 'v1.agent.SpreadApply/applyExamine')->name('applyExamine')->option(['real_name' => '分销员审核']);
Route::delete('spread/apply/del/:id', 'v1.agent.SpreadApply/applyDelete')->name('applyDelete')->option(['real_name' => '删除分销员申请']);
})->option(['parent' => 'agent', 'cate_name' => '分销员申请']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'agent', 'mark_name' => '分销模块']);

View File

@ -14,101 +14,145 @@ use think\facade\Route;
* 应用模块 相关路由
*/
Route::group('app', function () {
//小程序模板资源路由
Route::resource('routine', 'v1.application.routine.RoutineTemplate')->name('RoutineResource')->option(['real_name' => '小程序订阅消息']);
//一键同步订阅消息
Route::get('routine/syncSubscribe', 'v1.application.routine.RoutineTemplate/syncSubscribe')->name('syncSubscribe')->option(['real_name' => '一键同步订阅消息']);
//一键同步微信模版消息消息
Route::get('wechat/syncSubscribe', 'v1.application.wechat.WechatTemplate/syncSubscribe')->name('syncSubscribe')->option(['real_name' => '一键同步模版消息']);
//修改状态
Route::put('routine/set_status/:id/:status', 'v1.application.routine.RoutineTemplate/set_status')->name('RoutineSetStatus')->option(['real_name' => '修改订阅消息状态']);
//菜单值
Route::get('wechat/menu', 'v1.application.wechat.menus/index')->option(['real_name' => '微信公众号菜单列表']);
//保存菜单
Route::post('wechat/menu', 'v1.application.wechat.menus/save')->option(['real_name' => '保存微信公众号菜单']);
//微信模板消息资源路由
Route::resource('wechat/template', 'v1.application.wechat.WechatTemplate')->name('WechatTemplateResource')->option(['real_name' => '公众号模版消息']);
//微信模板消息修改状态
Route::put('wechat/template/set_status/:id/:status', 'v1.application.wechat.WechatTemplate/set_status')->name('WechatTemplateSetStatus')->option(['real_name' => '修改关键字回复状态']);
//关注回复
Route::get('wechat/reply', 'v1.application.wechat.Reply/reply')->option(['real_name' => '关注回复']);
//获取关注回复二维码
Route::get('wechat/code_reply/:id', 'v1.application.wechat.Reply/code_reply')->option(['real_name' => '获取关注回复二维码']);
//关键字回复列表
Route::get('wechat/keyword', 'v1.application.wechat.Reply/index')->option(['real_name' => '关键字回复列表']);
//关键字详情
Route::get('wechat/keyword/:id', 'v1.application.wechat.Reply/read')->option(['real_name' => '关键字回复详情']);
//保存关键字修改
Route::post('wechat/keyword/:id', 'v1.application.wechat.Reply/save')->option(['real_name' => '保存关键字回复']);
//删除关键字
Route::delete('wechat/keyword/:id', 'v1.application.wechat.Reply/delete')->option(['real_name' => '删除关键字回复']);
//修改关键字状态
Route::put('wechat/keyword/set_status/:id/:status', 'v1.application.wechat.Reply/set_status')->option(['real_name' => '修改关键字回复状态']);
//图文列表
Route::get('wechat/news', 'v1.application.wechat.WechatNewsCategory/index')->option(['real_name' => '图文列表']);
//详情
Route::get('wechat/news/:id', 'v1.application.wechat.WechatNewsCategory/read')->option(['real_name' => '图文详情']);
//保存图文
Route::post('wechat/news', 'v1.application.wechat.WechatNewsCategory/save')->option(['real_name' => '保存图文']);
//删除图文
Route::delete('wechat/news/:id', 'v1.application.wechat.WechatNewsCategory/delete')->option(['real_name' => '删除图文']);
//发送图文消息
Route::post('wechat/push', 'v1.application.wechat.WechatNewsCategory/push')->option(['real_name' => '发送图文消息']);
//用户行为列表
Route::get('wechat/action', 'v1.application.wechat.WechatMessage/index')->option(['real_name' => '用户行为列表']);
//用户行为列表操作名称列表
Route::get('wechat/action/operate', 'v1.application.wechat.WechatMessage/operate')->option(['real_name' => '用户行为列表操作名称列表']);
//下载小程序模版页面数据
Route::get('routine/info', 'v1.application.routine.RoutineTemplate/getDownloadInfo')->option(['real_name' => '下载小程序页面数据']);
//下载小程序模版
Route::post('routine/download', 'v1.application.routine.RoutineTemplate/downloadTemp')->option(['real_name' => '下载小程序模版']);
/** 公众号 */
Route::group(function () {
//菜单值
Route::get('wechat/menu', 'v1.application.wechat.menus/index')->option(['real_name' => '微信公众号菜单列表']);
//保存菜单
Route::post('wechat/menu', 'v1.application.wechat.menus/save')->option(['real_name' => '保存微信公众号菜单']);
//图文列表
Route::get('wechat/news', 'v1.application.wechat.WechatNewsCategory/index')->option(['real_name' => '图文列表']);
//详情
Route::get('wechat/news/:id', 'v1.application.wechat.WechatNewsCategory/read')->option(['real_name' => '图文详情']);
//保存图文
Route::post('wechat/news', 'v1.application.wechat.WechatNewsCategory/save')->option(['real_name' => '保存图文']);
//删除图文
Route::delete('wechat/news/:id', 'v1.application.wechat.WechatNewsCategory/delete')->option(['real_name' => '删除图文']);
//发送图文消息
Route::post('wechat/push', 'v1.application.wechat.WechatNewsCategory/push')->option(['real_name' => '发送图文消息']);
//关注回复
Route::get('wechat/reply', 'v1.application.wechat.Reply/reply')->option(['real_name' => '关注回复']);
//获取关注回复二维码
Route::get('wechat/code_reply/:id', 'v1.application.wechat.Reply/code_reply')->option(['real_name' => '获取关注回复二维码']);
//关键字回复列表
Route::get('wechat/keyword', 'v1.application.wechat.Reply/index')->option(['real_name' => '关键字回复列表']);
//关键字详情
Route::get('wechat/keyword/:id', 'v1.application.wechat.Reply/read')->option(['real_name' => '关键字回复详情']);
//保存关键字修改
Route::post('wechat/keyword/:id', 'v1.application.wechat.Reply/save')->option(['real_name' => '保存关键字回复']);
//删除关键字
Route::delete('wechat/keyword/:id', 'v1.application.wechat.Reply/delete')->option(['real_name' => '删除关键字回复']);
//修改关键字状态
Route::put('wechat/keyword/set_status/:id/:status', 'v1.application.wechat.Reply/set_status')->option(['real_name' => '修改关键字回复状态']);
//一键同步微信模版消息消息
Route::get('wechat/syncSubscribe', 'v1.application.wechat.WechatTemplate/syncSubscribe')->name('syncSubscribe')->option(['real_name' => '一键同步模版消息']);
})->option(['parent' => 'app', 'cate_name' => '公众号']);
/** 小程序 */
Route::group(function () {
//一键同步订阅消息
Route::get('routine/syncSubscribe', 'v1.application.routine.RoutineTemplate/syncSubscribe')->name('syncSubscribe')->option(['real_name' => '一键同步订阅消息']);
//下载小程序模版页面数据
Route::get('routine/info', 'v1.application.routine.RoutineTemplate/getDownloadInfo')->option(['real_name' => '下载小程序页面数据']);
//下载小程序模版
Route::post('routine/download', 'v1.application.routine.RoutineTemplate/downloadTemp')->option(['real_name' => '下载小程序模版']);
Route::get('routine/scheme_list', 'v1.application.routine.RoutineScheme/schemeList')->name('schemeList')->option(['real_name' => '小程序外链列表']);
Route::get('routine/scheme_form/:id', 'v1.application.routine.RoutineScheme/schemeForm')->name('schemeForm')->option(['real_name' => '小程序外链添加修改表单']);
Route::post('routine/scheme_save/:id', 'v1.application.routine.RoutineScheme/schemeSave')->name('schemeSave')->option(['real_name' => '小程序外链添加修改保存']);
Route::delete('routine/scheme_del/:id', 'v1.application.routine.RoutineScheme/schemeDel')->name('schemeDel')->option(['real_name' => '小程序外链删除']);
})->option(['parent' => 'app', 'cate_name' => '小程序']);
/** 公众号渠道码 */
Route::get('wechat_qrcode/cate/list', 'v1.application.wechat.WechatQrcode/getCateList')->option(['real_name' => '渠道码分类列表']);
Route::get('wechat_qrcode/cate/create/:id', 'v1.application.wechat.WechatQrcode/createForm')->option(['real_name' => '渠道码分类添加编辑表单']);
Route::post('wechat_qrcode/cate/save', 'v1.application.wechat.WechatQrcode/saveCate')->option(['real_name' => '渠道码分类保存']);
Route::delete('wechat_qrcode/cate/del/:id', 'v1.application.wechat.WechatQrcode/delCate')->option(['real_name' => '渠道码分类删除']);
Route::post('wechat_qrcode/save/:id', 'v1.application.wechat.WechatQrcode/saveQrcode')->option(['real_name' => '保存渠道码']);
Route::get('wechat_qrcode/info/:id', 'v1.application.wechat.WechatQrcode/qrcodeInfo')->option(['real_name' => '渠道码详情']);
Route::get('wechat_qrcode/list', 'v1.application.wechat.WechatQrcode/qrcodeList')->option(['real_name' => '渠道码列表']);
Route::delete('wechat_qrcode/del/:id', 'v1.application.wechat.WechatQrcode/delQrcode')->option(['real_name' => '删除渠道码']);
Route::put('wechat_qrcode/set_status/:id/:status', 'v1.application.wechat.WechatQrcode/setStatus')->option(['real_name' => '切换渠道码状态']);
Route::get('wechat_qrcode/user_list/:qid', 'v1.application.wechat.WechatQrcode/userList')->option(['real_name' => '渠道码用户列表']);
Route::get('wechat_qrcode/statistic/:qid', 'v1.application.wechat.WechatQrcode/qrcodeStatistic')->option(['real_name' => '渠道码统计']);
Route::group(function () {
Route::get('wechat_qrcode/cate/list', 'v1.application.wechat.WechatQrcode/getCateList')->option(['real_name' => '渠道码分类列表']);
Route::get('wechat_qrcode/cate/create/:id', 'v1.application.wechat.WechatQrcode/createForm')->option(['real_name' => '渠道码分类添加编辑表单']);
Route::post('wechat_qrcode/cate/save', 'v1.application.wechat.WechatQrcode/saveCate')->option(['real_name' => '渠道码分类保存']);
Route::delete('wechat_qrcode/cate/del/:id', 'v1.application.wechat.WechatQrcode/delCate')->option(['real_name' => '渠道码分类删除']);
Route::post('wechat_qrcode/save/:id', 'v1.application.wechat.WechatQrcode/saveQrcode')->option(['real_name' => '保存渠道码']);
Route::get('wechat_qrcode/info/:id', 'v1.application.wechat.WechatQrcode/qrcodeInfo')->option(['real_name' => '渠道码详情']);
Route::get('wechat_qrcode/list', 'v1.application.wechat.WechatQrcode/qrcodeList')->option(['real_name' => '渠道码列表']);
Route::delete('wechat_qrcode/del/:id', 'v1.application.wechat.WechatQrcode/delQrcode')->option(['real_name' => '删除渠道码']);
Route::put('wechat_qrcode/set_status/:id/:status', 'v1.application.wechat.WechatQrcode/setStatus')->option(['real_name' => '切换渠道码状态']);
Route::get('wechat_qrcode/user_list/:qid', 'v1.application.wechat.WechatQrcode/userList')->option(['real_name' => '渠道码用户列表']);
Route::get('wechat_qrcode/statistic/:qid', 'v1.application.wechat.WechatQrcode/qrcodeStatistic')->option(['real_name' => '渠道码统计']);
})->option(['parent' => 'app', 'cate_name' => '公众号渠道码']);
/** 客服相关 */
//客服反馈接口
Route::resource('feedback', 'v1.kefu.StoreServiceFeedback')->only(['index', 'delete', 'update', 'edit'])->option(['real_name' => '用户反馈']);
//话术接口
Route::resource('wechat/speechcraft', 'v1.kefu.StoreServiceSpeechcraft')->option(['real_name' => '客服话术']);
//话术分类接口
Route::resource('wechat/speechcraftcate', 'v1.kefu.StoreServiceSpeechcraftCate')->option(['real_name' => '客服话术分类']);
//客服列表
Route::get('wechat/kefu', 'v1.kefu.StoreService/index')->option(['real_name' => '客服列表']);
//客服登录
Route::get('wechat/kefu/login/:id', 'v1.kefu.StoreService/keufLogin')->option(['real_name' => '客服登录']);
//新增客服选择用户列表
Route::get('wechat/kefu/create', 'v1.kefu.StoreService/create')->option(['real_name' => '新增客服选择用户列表']);
//新增客服表单
Route::get('wechat/kefu/add', 'v1.kefu.StoreService/add')->option(['real_name' => '添加客服表单']);
//保存新建的数据
Route::post('wechat/kefu', 'v1.kefu.StoreService/save')->option(['real_name' => '添加客服']);
//编辑客服表单
Route::get('wechat/kefu/:id/edit', 'v1.kefu.StoreService/edit')->option(['real_name' => '修改客服表单']);
//保存编辑的数据
Route::put('wechat/kefu/:id', 'v1.kefu.StoreService/update')->option(['real_name' => '修改客服']);
//删除
Route::delete('wechat/kefu/:id', 'v1.kefu.StoreService/delete')->option(['real_name' => '删除客服']);
//修改状态
Route::put('wechat/kefu/set_status/:id/:status', 'v1.kefu.StoreService/set_status')->option(['real_name' => '修改客服状态']);
//聊天记录
Route::get('wechat/kefu/record/:id', 'v1.kefu.StoreService/chat_user')->option(['real_name' => '聊天记录']);
//查看对话
Route::get('wechat/kefu/chat_list', 'v1.kefu.StoreService/chat_list')->option(['real_name' => '查看对话']);
Route::group(function () {
//客服反馈接口
Route::resource('feedback', 'v1.kefu.StoreServiceFeedback')->only(['index', 'delete', 'update', 'edit'])->option([
'real_name' => [
'index' => '获取用户反馈列表',
'edit' => '获取修改用户反馈表单',
'update' => '修改用户反馈',
'delete' => '删除用户反馈'
]
]);
//话术接口
Route::resource('wechat/speechcraft', 'v1.kefu.StoreServiceSpeechcraft')->except(['read'])->option([
'real_name' => [
'index' => '获取客服话术列表',
'create' => '获取客服话术表单',
'save' => '保存客服话术',
'edit' => '获取修改客服话术表单',
'update' => '修改客服话术',
'delete' => '删除客服话术'
]
]);
//话术分类接口
Route::resource('wechat/speechcraftcate', 'v1.kefu.StoreServiceSpeechcraftCate')->except(['read'])->option([
'real_name' => [
'index' => '获取客服话术分类列表',
'create' => '获取客服话术分类表单',
'save' => '保存客服话术分类',
'edit' => '获取修改客服话术分类表单',
'update' => '修改客服话术分类',
'delete' => '删除客服话术分类'
]
]);
//客服列表
Route::get('wechat/kefu', 'v1.kefu.StoreService/index')->option(['real_name' => '客服列表']);
//客服登录
Route::get('wechat/kefu/login/:id', 'v1.kefu.StoreService/keufLogin')->option(['real_name' => '客服登录']);
//新增客服选择用户列表
Route::get('wechat/kefu/create', 'v1.kefu.StoreService/create')->option(['real_name' => '新增客服选择用户列表']);
//新增客服表单
Route::get('wechat/kefu/add', 'v1.kefu.StoreService/add')->option(['real_name' => '添加客服表单']);
//保存新建的数据
Route::post('wechat/kefu', 'v1.kefu.StoreService/save')->option(['real_name' => '添加客服']);
//编辑客服表单
Route::get('wechat/kefu/:id/edit', 'v1.kefu.StoreService/edit')->option(['real_name' => '修改客服表单']);
//保存编辑的数据
Route::put('wechat/kefu/:id', 'v1.kefu.StoreService/update')->option(['real_name' => '修改客服']);
//删除
Route::delete('wechat/kefu/:id', 'v1.kefu.StoreService/delete')->option(['real_name' => '删除客服']);
//修改状态
Route::put('wechat/kefu/set_status/:id/:status', 'v1.kefu.StoreService/set_status')->option(['real_name' => '修改客服状态']);
//聊天记录
Route::get('wechat/kefu/record/:id', 'v1.kefu.StoreService/chat_user')->option(['real_name' => '聊天记录']);
//查看对话
Route::get('wechat/kefu/chat_list', 'v1.kefu.StoreService/chat_list')->option(['real_name' => '查看对话']);
//客服自动回复列表
Route::get('kefu/auto_reply/list', 'v1.kefu.StoreServiceAutoReply/autoReplyList')->option(['real_name' => '客服自动回复列表']);
//客服自动回复添加修改表单
Route::get('kefu/auto_reply/form/:id', 'v1.kefu.StoreServiceAutoReply/autoReplyForm')->option(['real_name' => '客服自动回复添加修改表单']);
//客服自动回复添加修改保存
Route::post('kefu/auto_reply/save/:id', 'v1.kefu.StoreServiceAutoReply/autoReplySave')->option(['real_name' => '客服自动回复添加修改保存']);
//客服自动回复修改状态
Route::put('kefu/auto_reply/status/:id/:status', 'v1.kefu.StoreServiceAutoReply/autoReplyStatus')->option(['real_name' => '客服自动回复修改状态']);
//客服自动回复删除
Route::delete('kefu/auto_reply/del/:id', 'v1.kefu.StoreServiceAutoReply/autoReplyDel')->option(['real_name' => '客服自动回复删除']);
})->option(['parent' => 'app', 'cate_name' => '客服相关']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'app', 'mark_name' => '应用模块']);

View File

@ -14,23 +14,51 @@ use think\facade\Route;
* 文章管理 相关路由
*/
Route::group('cms', function () {
//文章资源路由
Route::resource('cms', 'v1.cms.Article')->name('ArticleResource')->option(['real_name' => '文章']);
//关联商品
Route::put('cms/relation/:id', 'v1.cms.Article/relation')->name('Relation')->option(['real_name' => '文章关联商品']);
//取消关联
Route::put('cms/unrelation/:id', 'v1.cms.Article/unrelation')->name('UnRelation')->option(['real_name' => '取消文章关联商品']);
//文章分类资源路由
Route::resource('category', 'v1.cms.ArticleCategory')->name('ArticleCategoryResource')->option(['real_name' => '文章分类']);
//修改状态
Route::put('category/set_status/:id/:status', 'v1.cms.ArticleCategory/set_status')->name('CategoryStatus')->option(['real_name' => '修改文章分类状态']);
//分类列表
Route::get('category_list', 'v1.cms.ArticleCategory/categoryList')->name('categoryList')->option(['real_name' => '分类列表']);
//分类树形列表
Route::get('category_tree_list', 'v1.cms.ArticleCategory/getTreeList')->name('getTreeList')->option(['real_name' => '分类树形列表']);
/** 文章 */
Route::group(function () {
//文章资源路由
Route::resource('cms', 'v1.cms.Article')->option([
'real_name' => [
'index' => '获取文章列表',
'create' => '获取文章表单',
'read' => '获取文章详细信息',
'save' => '保存文章',
'edit' => '获取修改文章表单',
'update' => '修改文章',
'delete' => '删除文章'
]
]);
//关联商品
Route::put('cms/relation/:id', 'v1.cms.Article/relation')->name('Relation')->option(['real_name' => '文章关联商品']);
//取消关联
Route::put('cms/unrelation/:id', 'v1.cms.Article/unrelation')->name('UnRelation')->option(['real_name' => '取消文章关联商品']);
})->option(['parent' => 'cms', 'cate_name' => '文章管理']);
/** 文章分类 */
Route::group(function () {
//文章分类资源路由
Route::resource('category', 'v1.cms.ArticleCategory')->except(['read'])->option([
'real_name' => [
'index' => '获取文章分类列表',
'create' => '获取文章分类表单',
'save' => '保存文章分类',
'edit' => '获取修改文章分类表单',
'update' => '修改文章分类',
'delete' => '删除文章分类'
]
]);
//修改状态
Route::put('category/set_status/:id/:status', 'v1.cms.ArticleCategory/set_status')->name('CategoryStatus')->option(['real_name' => '修改文章分类状态']);
//分类列表
Route::get('category_list', 'v1.cms.ArticleCategory/categoryList')->name('categoryList')->option(['real_name' => '分类列表']);
//分类树形列表
Route::get('category_tree_list', 'v1.cms.ArticleCategory/getTreeList')->name('getTreeList')->option(['real_name' => '分类树形列表']);
})->option(['parent' => 'cms', 'cate_name' => '文章分类']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'cms', 'mark_name' => '文章模块']);

View File

@ -14,7 +14,6 @@ use think\facade\Route;
* 文件下载、导出相关路由
*/
Route::group(function () {
//下载备份记录表
Route::get('backup/download', 'v1.system.SystemDatabackup/downloadFile')->option(['real_name' => '下载表备份记录']);
//首页统计数据
@ -23,9 +22,9 @@ Route::group(function () {
Route::get('home/order', 'Common/orderChart')->option(['real_name' => '首页订单图表']);
//首页用户图表
Route::get('home/user', 'Common/userChart')->option(['real_name' => '首页用户图表']);
//
//首页交易额排行
Route::get('home/rank', 'Common/purchaseRanking')->option(['real_name' => '首页交易额排行']);
// 消息提醒
//消息提醒
Route::get('jnotice', 'Common/jnotice')->option(['real_name' => '消息提醒']);
//验证授权
Route::get('check_auth', 'Common/auth')->option(['real_name' => '验证授权']);
@ -43,10 +42,12 @@ Route::group(function () {
Route::get('copyright', 'Common/copyright')->option(['real_name' => '申请版权']);
//保存版权
Route::post('copyright', 'Common/saveCopyright')->option(['real_name' => '保存版权']);
//后台菜单搜索
Route::post('menusSearch', 'Common/menusSearch')->option(['real_name' => '后台菜单搜索']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'common', 'mark_name' => '系统数据']);

View File

@ -0,0 +1,35 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
use think\facade\Route;
/**
* crud 自动加载路由
* 自动加载crud目录下的所有路由文件
*/
Route::group(function () {
$path = $this->app->getRootPath() . 'app' . DS . 'adminapi' . DS . 'route' . DS . 'crud';
if (is_dir($path)) {
$files = scandir($path);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
include $path . DS . $file;
}
}
}
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
])->option(['mark' => 'crud', 'mark_name' => '生成代码路由']);

View File

@ -12,7 +12,7 @@
use think\facade\Route;
/**
* 分销管理 相关路由
* diy 相关路由
*/
Route::group('diy', function () {
@ -64,14 +64,43 @@ Route::group('diy', function () {
Route::post('member_save', 'v1.diy.Diy/memberSaveData')->option(['real_name' => '个人中心保存']);
//获取diy小程序二维码
Route::get('get_routine_code/:id', 'v1.diy.Diy/getRoutineCode')->option(['real_name' => 'diy小程序预览码']);
//开屏广告
Route::get('open_adv/info', 'v1.diy.Diy/getOpenAdv')->option(['real_name' => '获取开屏广告']);
Route::post('open_adv/add', 'v1.diy.Diy/openAdvAdd')->option(['real_name' => '保存开屏广告']);
//推荐商品
Route::get('groom_list/:type', 'v1.diy.Diy/getGroomList')->option(['real_name' => '推荐商品']);
/** 系统链接管理 */
Route::get('link/category', 'v1.diy.PageLink/getLinkCategory')->option(['real_name' => '获取链接分类']);
Route::get('link/category/form/:cate_id/[:pid]', 'v1.diy.PageLink/getLinkCategoryForm')->option(['real_name' => '链接分类表单']);
Route::post('link/category/save/:cate_id', 'v1.diy.PageLink/getLinkCategorySave')->option(['real_name' => '链接分类保存']);
Route::delete('link/category/del/:cate_id', 'v1.diy.PageLink/getLinkCategoryDel')->option(['real_name' => '链接分类删除']);
Route::get('link/list/:cate_id', 'v1.diy.PageLink/getLinkList')->option(['real_name' => '链接列表']);
Route::post('link/save/:id', 'v1.diy.PageLink/getLinkSave')->option(['real_name' => '链接保存']);
Route::delete('link/del/:id', 'v1.diy.PageLink/getLinkDel')->option(['real_name' => '链接删除']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'diy', 'mark_name' => '页面装修']);
/**
* diy_pro 相关路由
*/
Route::group('diy_pro', function () {
Route::get('get_list', 'v1.diy.DiyPro/getList')->option(['real_name' => 'DiyPro模板列表']);
Route::get('get_info/:id', 'v1.diy.DiyPro/getInfo')->option(['real_name' => 'DiyPro模板详情']);
Route::post('save/:id', 'v1.diy.DiyPro/saveInfo')->option(['real_name' => 'DiyPro模板保存']);
Route::get('get_product', 'v1.diy.DiyPro/getProduct')->option(['real_name' => '获取商品列表']);
Route::post('update/name/:id', 'v1.diy.DiyPro/updateName')->option(['real_name' => '修改名称']);
Route::get('export/data/:id', 'v1.diy.DiyPro/exportDIYData')->option(['real_name' => '导出DIY数据']);
Route::post('import/data', 'v1.diy.DiyPro/importDIYData')->option(['real_name' => '导入DIY数据']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
])->option(['mark' => 'diy_pro', 'mark_name' => '页面装修']);

View File

@ -18,6 +18,8 @@ Route::group('export', function () {
Route::get('user_list', 'v1.export.ExportExcel/userList')->option(['real_name' => '用户列表导出']);
//订单列表
Route::get('order_list', 'v1.export.ExportExcel/orderList')->option(['real_name' => '订单列表导出']);
//发货订单列表
Route::get('order_delivery_list', 'v1.export.ExportExcel/orderDeliveryList')->option(['real_name' => '发货订单列表导出']);
//商品列表
Route::get('product_list', 'v1.export.ExportExcel/productList')->option(['real_name' => '商品列表导出']);
//砍价列表
@ -28,7 +30,8 @@ Route::group('export', function () {
Route::get('seckill_list', 'v1.export.ExportExcel/seckillList')->option(['real_name' => '秒杀商品列表导出']);
//导出会员卡
Route::get('member_card/:id', 'v1.export.ExportExcel/memberCardList')->option(['real_name' => '会员卡导出']);
//分销用户推广列表
Route::get('userAgent', 'v1.export.ExportExcel/userAgent')->option(['real_name' => '分销员推广列表导出']);
//用户资金监控
Route::get('userFinance', 'v1.export.ExportExcel/userFinance')->option(['real_name' => '用户资金导出']);
//用户佣金
@ -37,27 +40,9 @@ Route::group('export', function () {
Route::get('userPoint', 'v1.export.ExportExcel/userPoint')->option(['real_name' => '用户积分导出']);
//用户充值
Route::get('userRecharge', 'v1.export.ExportExcel/userRecharge')->option(['real_name' => '用户充值导出']);
//分销用户推广列表
Route::get('userAgent', 'v1.export.ExportExcel/userAgent')->option(['real_name' => '分销员推广列表导出']);
//微信用户
Route::get('wechatUser', 'v1.export.ExportExcel/wechatUser')->option(['real_name' => '微信用户导出']);
//商铺砍价活动
Route::get('storeBargain', 'v1.export.ExportExcel/storeBargain')->option(['real_name' => '砍价商品导出']);
//商铺拼团
Route::get('storeCombination', 'v1.export.ExportExcel/storeCombination')->option(['real_name' => '拼团商品导出']);
//商铺秒杀
Route::get('storeSeckill', 'v1.export.ExportExcel/storeSeckill')->option(['real_name' => '秒杀商品导出']);
//商铺产品
Route::get('storeProduct', 'v1.export.ExportExcel/storeProduct')->option(['real_name' => '商品导出']);
//商铺订单
Route::get('storeOrder', 'v1.export.ExportExcel/storeOrder')->option(['real_name' => '订单导出']);
//商铺提货点
Route::get('storeMerchant', 'v1.export.ExportExcel/storeMerchant')->option(['real_name' => '提货点导出']);
//导出会员卡
Route::get('memberCard/:id', 'v1.export.ExportExcel/memberCard')->option(['real_name' => '会员卡导出']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'export', 'mark_name' => '数据导出']);

View File

@ -27,14 +27,34 @@ Route::group('file', function () {
//上传图片
Route::post('upload/[:upload_type]', 'v1.file.SystemAttachment/upload')->option(['real_name' => '上传图片']);
//附件分类管理资源路由
Route::resource('category', 'v1.file.SystemAttachmentCategory')->option(['real_name' => '附件分类管理']);
Route::resource('category', 'v1.file.SystemAttachmentCategory')->except(['read'])->option([
'real_name' => [
'index' => '获取附件分类管理列表',
'create' => '获取附件分类管理表单',
'save' => '保存附件分类管理',
'edit' => '获取修改附件分类管理表单',
'update' => '修改附件分类管理',
'delete' => '删除附件分类管理'
],
]);
//获取上传类型
Route::get('upload_type', 'v1.file.SystemAttachment/uploadType')->option(['real_name' => '上传类型']);
//分片上传本地视频
Route::post('video_upload', 'v1.file.SystemAttachment/videoUpload')->option(['real_name' => '分片上传本地视频']);
//云存储视频保存数据
Route::post('video_data_save', 'v1.file.SystemAttachment/videoDataSave')->option(['real_name' => '云存储视频保存数据']);
//获取扫码上传页面链接以及参数
Route::get('scan_upload/qrcode', 'v1.file.SystemAttachment/scanUploadQrcode')->option(['real_name' => '扫码上传页面链接']);
//删除扫码上传token
Route::delete('scan_upload/qrcode', 'v1.file.SystemAttachment/removeUploadQrcode')->option(['real_name' => '删除扫码上传页面链接']);
//获取扫码上传的图片数据
Route::get('scan_upload/image/:scan_token', 'v1.file.SystemAttachment/scanUploadImage')->option(['real_name' => '获取扫码上传的图片数据']);
//网络图片上传
Route::post('online_upload', 'v1.file.SystemAttachment/onlineUpload')->option(['real_name' => '网络图片上传']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'file', 'mark_name' => '素材管理']);

View File

@ -14,44 +14,56 @@ use think\facade\Route;
* 财务模块 相关路由
*/
Route::group('finance', function () {
//筛选类型
Route::get('finance/bill_type', 'v1.finance.Finance/bill_type')->option(['real_name' => '资金记录类型']);
//资金记录
Route::get('finance/list', 'v1.finance.Finance/list')->option(['real_name' => '资金记录列表']);
//佣金记录
Route::get('finance/commission_list', 'v1.finance.Finance/get_commission_list')->option(['real_name' => '佣金记录列表']);
//佣金详情用户信息
Route::get('finance/user_info/:id', 'v1.finance.Finance/user_info')->option(['real_name' => '佣金详情用户信息']);
//佣金提现记录个人列表
Route::get('finance/extract_list/:id', 'v1.finance.Finance/get_extract_list')->option(['real_name' => '佣金提现记录个人列表']);
//申请列表
Route::get('extract', 'v1.finance.UserExtract/index')->option(['real_name' => '提现申请列表']);
//编辑表单
Route::get('extract/:id/edit', 'v1.finance.UserExtract/edit')->option(['real_name' => '提现记录修改表单']);
//保存修改
Route::put('extract/:id', 'v1.finance.UserExtract/update')->option(['real_name' => '提现记录修改']);
//拒绝申请
Route::put('extract/refuse/:id', 'v1.finance.UserExtract/refuse')->option(['real_name' => '拒绝提现申请']);
//通过申请
Route::put('extract/adopt/:id', 'v1.finance.UserExtract/adopt')->option(['real_name' => '通过提现申请']);
//充值记录列表
Route::get('recharge', 'v1.finance.UserRecharge/index')->option(['real_name' => '充值记录列表']);
//删除记录
Route::delete('recharge/:id', 'v1.finance.UserRecharge/delete')->option(['real_name' => '删除充值记录']);
//获取用户充值数据
Route::get('recharge/user_recharge', 'v1.finance.UserRecharge/user_recharge')->option(['real_name' => '获取用户充值数据']);
//退款表单
Route::get('recharge/:id/refund_edit', 'v1.finance.UserRecharge/refund_edit')->option(['real_name' => '充值退款表单']);
//退款
Route::put('recharge/:id', 'v1.finance.UserRecharge/refund_update')->option(['real_name' => '充值退款']);
/** 余额记录 */
Route::get('balance/list', 'v1.finance.UserBalance/balanceList')->option(['real_name' => '余额记录列表']);
Route::post('balance/set_mark/:id', 'v1.finance.UserBalance/balanceRecordRemark')->option(['real_name' => '余额记录备注']);
/** 提现 */
Route::group(function () {
//申请列表
Route::get('extract', 'v1.finance.UserExtract/index')->option(['real_name' => '提现申请列表']);
//编辑表单
Route::get('extract/:id/edit', 'v1.finance.UserExtract/edit')->option(['real_name' => '提现记录修改表单']);
//保存修改
Route::put('extract/:id', 'v1.finance.UserExtract/update')->option(['real_name' => '提现记录修改']);
//拒绝申请
Route::put('extract/refuse/:id', 'v1.finance.UserExtract/refuse')->option(['real_name' => '拒绝提现申请']);
//通过申请
Route::put('extract/adopt/:id', 'v1.finance.UserExtract/adopt')->option(['real_name' => '通过提现申请']);
})->option(['parent' => 'finance', 'cate_name' => '提现']);
/** 资金记录 */
Route::group(function () {
//筛选类型
Route::get('finance/bill_type', 'v1.finance.Finance/bill_type')->option(['real_name' => '资金记录类型']);
//资金记录
Route::get('finance/list', 'v1.finance.Finance/list')->option(['real_name' => '资金记录列表']);
//佣金记录
Route::get('finance/commission_list', 'v1.finance.Finance/get_commission_list')->option(['real_name' => '佣金记录列表']);
//佣金详情用户信息
Route::get('finance/user_info/:id', 'v1.finance.Finance/user_info')->option(['real_name' => '佣金详情用户信息']);
//佣金提现记录个人列表
Route::get('finance/extract_list/:id', 'v1.finance.Finance/get_extract_list')->option(['real_name' => '佣金提现记录个人列表']);
/** 余额记录 */
Route::get('balance/list', 'v1.finance.UserBalance/balanceList')->option(['real_name' => '余额记录列表']);
Route::post('balance/set_mark/:id', 'v1.finance.UserBalance/balanceRecordRemark')->option(['real_name' => '余额记录备注']);
})->option(['parent' => 'finance', 'cate_name' => '资金记录']);
/** 充值 */
Route::group(function () {
//充值记录列表
Route::get('recharge', 'v1.finance.UserRecharge/index')->option(['real_name' => '充值记录列表']);
//删除记录
Route::delete('recharge/:id', 'v1.finance.UserRecharge/delete')->option(['real_name' => '删除充值记录']);
//获取用户充值数据
Route::get('recharge/user_recharge', 'v1.finance.UserRecharge/user_recharge')->option(['real_name' => '获取用户充值数据']);
//退款表单
Route::get('recharge/:id/refund_edit', 'v1.finance.UserRecharge/refund_edit')->option(['real_name' => '充值退款表单']);
//退款
Route::put('recharge/:id', 'v1.finance.UserRecharge/refund_update')->option(['real_name' => '充值退款']);
})->option(['parent' => 'finance', 'cate_name' => '充值']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'finance', 'mark_name' => '财务管理']);

View File

@ -15,7 +15,16 @@ use think\facade\Route;
*/
Route::group('freight', function () {
//物流公司资源路由
Route::resource('express', 'v1.freight.Express')->name('ExpressResource')->option(['real_name' => '物流公司']);
Route::resource('express', 'v1.freight.Express')->except(['read'])->name('ExpressResource')->option([
'real_name' => [
'index' => '获取物流公司列表',
'create' => '获取物流公司表单',
'save' => '保存物流公司',
'edit' => '获取修改物流公司表单',
'update' => '修改物流公司',
'delete' => '删除物流公司'
],
]);
//修改状态
Route::put('express/set_status/:id/:status', 'v1.freight.Express/set_status')->option(['real_name' => '修改物流公司状态']);
//同步物流快递公司
@ -30,4 +39,4 @@ Route::group('freight', function () {
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
\app\adminapi\middleware\AdminCheckRoleMiddleware::class,
\app\adminapi\middleware\AdminLogMiddleware::class
]);
])->option(['mark' => 'freight', 'mark_name' => '物流管理']);

Some files were not shown because too many files have changed in this diff Show More