1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-07-27 04:20:43 +08:00

22 Commits

Author SHA1 Message Date
小莫唐尼 6ba87b1972 修改:修复文章详情页面不兼容其他pc端主题导致文章内容不显示的BUG 2023-02-07 15:39:58 +08:00
小莫唐尼 a0f3d1b220 修改:修复文章分享好友和朋友圈功能 2023-02-05 18:40:40 +08:00
小莫唐尼 6e80fa14c8 修改:修复文章和分类无封面图使用静态默认图片无法显示的BUG 2023-01-13 01:17:57 +08:00
小莫唐尼 22a8e92dc2 修改:修复tm-vuetify 在 HBuilderX3.6.14版本中 dayjs 找不到的问题 2022-12-26 20:09:30 +08:00
小莫唐尼 6b1e0e5cc0 新增:文章详情自定义广告 2022-12-15 17:34:26 +08:00
小莫唐尼 261617fc12 修改:修复恋爱日记在微信小程序ios下的日期转换错误bug;
修改:修复海报分享因为无图使用随机图在微信小程序下异常bug;
新增:halo.config.template.js 新增一个配置项 defaultStaticThumbnailUrl 默认静态图片用于海报在无图且使用了随机图时候的封面图片地址
2022-12-15 14:25:54 +08:00
小莫唐尼 5000da9a64 新增:文章详情评论弹幕设置功能 2022-12-13 10:51:21 +08:00
小莫唐尼 9573b303e2 新增:文章详情页面添加弹幕功能;
修改:修复友链列表单分组显示问题;
优化;对恋爱日记清单列表进行优化
2022-12-12 23:03:48 +08:00
小莫唐尼 f12262f4df 修改:调整恋爱日记相关UI 2022-12-12 00:30:47 +08:00
小莫唐尼 1305b4a555 修改:优化恋爱日记配置信息 2022-12-11 17:41:31 +08:00
小莫唐尼 b7e2025ebb 新增:新增恋爱日记功能 2022-12-11 16:52:32 +08:00
小莫唐尼 0da5feb2ee 修复:修复封面图片,如果是随机图api不生效的BUG 2022-12-10 14:30:32 +08:00
小莫唐尼 e46c5c2b6f 新增:文章版权说明;
新增:文章详情点击标签跳转查询标签下的文章列表;
优化:调整markdown文字大小
2022-12-10 14:24:36 +08:00
小莫唐尼 70c5b34de0 新增:留言评论头像形状设置;
修复:修复文章管理设置文章标签在小程序端不显示的bug;
修复:修复后台管理工作台因为无法读取用户信息页面不显示bug;
优化:优化友情链接动画效果
2022-12-10 12:26:47 +08:00
小莫唐尼 9d3ebac076 新增:更新halo.config.js 配置参数;
更新:更新项目UI框架;
修复:修复友链列表丢失白色背景色BUG;
2022-12-09 18:10:47 +08:00
小莫唐尼 3fd3b2247a 修复:后台管理文章设置BUG;
修复:友链列表不显示数据BUG;
修复:应用设置点击返回,触发提示BUG;
2022-12-09 10:48:00 +08:00
小莫唐尼 3702cb1618 新增:联系博主页面顶部返回按钮;
修复:修复 默认封面图、默认图片、默认头像在使用随机api时候无法显示的BUG;
修复:后台管理新增文章发布失败BUG;
删除:去除联系博主页面中的 联系博主 按钮;
优化:对友链页面进行重写;
优化:对部分页面和功能进行优化。
2022-12-09 00:24:39 +08:00
小莫唐尼 473655171b 修改:修正项目中的开源协议信息 2022-12-07 00:39:18 +08:00
小莫唐尼 9e2f090747 修改:更正开源协议 2022-12-07 00:33:26 +08:00
小莫唐尼 e05d0d7ce5 优化:重写友链列表,兼容微信小程序;
优化:解决分类功能滚动回弹问题;
2022-12-06 23:18:44 +08:00
小莫唐尼 3ba10fa105 修复:修复小程序文章图片不显示BUG 2022-12-06 18:36:06 +08:00
小莫唐尼 acc9070134 新增:首次启动页面配置 2022-12-06 18:02:36 +08:00
136 changed files with 4871 additions and 7869 deletions
+1
View File
@@ -2,4 +2,5 @@ node_modules/
unpackage/ unpackage/
config/halo.config.js config/halo.config.js
config/ad.config.js config/ad.config.js
config/love.config.js
package-lock.json package-lock.json
+4
View File
@@ -10,6 +10,10 @@
{ {
"launchtype" : "local" "launchtype" : "local"
}, },
"h5" :
{
"launchtype" : "local"
},
"mp-weixin" : "mp-weixin" :
{ {
"launchtype" : "local" "launchtype" : "local"
+1 -5
View File
@@ -64,14 +64,10 @@ export default {
@import './common/icons/mphtmliconfont.css'; @import './common/icons/mphtmliconfont.css';
/* #ifndef MP-WEIXIN */ /* #ifndef MP-WEIXIN */
@import './common/markdown/markdown.scss'; //引入markdown呈现 @import './common/markdown/markdown.scss';
/* #endif */ /* #endif */
page { page {
// background-color: #f3f5f7;
// background-color: #f7f7f7;
// background-color: #ffffff;
background-color: #fafafa; background-color: #fafafa;
// background-color: #f4f5f5;
} }
</style> </style>
+657 -16
View File
@@ -1,20 +1,661 @@
The MIT License (MIT) GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (c) 2018 RuoYi Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Permission is hereby granted, free of charge, to any person obtaining a copy of Preamble
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The GNU Affero General Public License is a free, copyleft license for
copies or substantial portions of the Software. software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR The licenses for most software and other practical works are designed
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS to take away your freedom to share and change the works. By contrast,
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR our General Public Licenses are intended to guarantee your freedom to
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER share and change all versions of a program--to make sure it remains free
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN software for all its users.
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a 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. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<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 Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
+8 -3
View File
@@ -94,12 +94,17 @@
## 🌈 在线体验 ## 🌈 在线体验
- 敬请期待... 微信小程序搜索:小莫唐尼
<br/>
![首页](https://uni-halo.925i.cn/assets/wx_white.51824be0.png)
## 🌈 交流群
QQ群号:632969367
## 🔍 许可证 ## 🔍 许可证
<a href="https://gitee.com/ialley-workshop-open/uni-halo/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
uni-halo 使用 MIT 协议开源,请遵守开源协议。 uni-halo 使用 AGPL-3.0 协议开源,请遵守开源协议。
## 🏭 贡献 ## 🏭 贡献
+1
View File
@@ -24,6 +24,7 @@ const createOrEditModel = {
"value": "string" "value": "string"
}], }],
"originalContent": "string", "originalContent": "string",
"formatContent": "",
"password": "string", "password": "string",
"slug": "string", "slug": "string",
"status": "DRAFT", "status": "DRAFT",
+2
View File
@@ -16,6 +16,7 @@ import archive from './archive.js'
import article from './article.js' import article from './article.js'
import blogger from './blogger.js' import blogger from './blogger.js'
import category from './category.js' import category from './category.js'
import tag from './tag.js'
import comment from './comment.js' import comment from './comment.js'
import journal from './journal.js' import journal from './journal.js'
import link from './link.js' import link from './link.js'
@@ -44,6 +45,7 @@ const ApiManager = {
...article, ...article,
...blogger, ...blogger,
...category, ...category,
...tag,
...comment, ...comment,
...journal, ...journal,
...link, ...link,
+24
View File
@@ -0,0 +1,24 @@
/**
* 标签接口
* @see https://api.halo.run/content-api.html#tag/tag-controller
*/
import HttpHandler from '@/common/http/request.js'
export default {
/**
* 查询标签列表
* @param {Object} params 查询参数
*/
getTagList: (params) => {
return HttpHandler.Get('/api/content/tags', params)
},
/**
* 查询标签下的文章
* @param {String} slug 别名
* @param {Object} params 查询参数
*/
getTagPostsList: (slug, params) => {
return HttpHandler.Get(`/api/content/tags/${slug}/posts`, params)
},
}
+8 -8
View File
@@ -44,53 +44,53 @@ export default {
color: var(--main); color: var(--main);
line-height: 24px; line-height: 24px;
position: relative; position: relative;
font-size:1.25em; font-size:1.2em;
`, `,
h2: ` h2: `
color: var(--main); color: var(--main);
line-height: 24px; line-height: 24px;
position: relative; position: relative;
margin: 22px 0 16px; margin: 22px 0 16px;
font-size: 1.2em; font-size: 1.16em;
`, `,
h3: ` h3: `
color: var(--main); color: var(--main);
line-height: 24px; line-height: 24px;
position: relative; position: relative;
margin: 26px 0 18px; margin: 26px 0 18px;
font-size: 1.3em; font-size: 1.14em;
`, `,
h4: ` h4: `
color: var(--main); color: var(--main);
line-height: 24px; line-height: 24px;
margin-bottom: 18px; margin-bottom: 18px;
position: relative; position: relative;
font-size: 1.18em; font-size: 1.12em;
`, `,
h5: ` h5: `
color: var(--main); color: var(--main);
line-height: 24px; line-height: 24px;
margin-bottom: 14px; margin-bottom: 14px;
position: relative; position: relative;
font-size: 1em; font-size: 1.1em;
`, `,
h6: ` h6: `
color: #303133; color: #303133;
line-height: 24px; line-height: 24px;
margin-bottom: 14px; margin-bottom: 14px;
position: relative; position: relative;
font-size: 1em; font-size: 14px;
`, `,
p: ` p: `
line-height: 1.65; line-height: 1.65;
margin-bottom: 14px; margin-bottom: 14px;
font-size: 15px; font-size: 14px;
`, `,
'code': ` `, 'code': ` `,
strong: 'font-weight: 700;color: rgb(248, 57, 41);', strong: 'font-weight: 700;color: rgb(248, 57, 41);',
video: 'width: 100%', video: 'width: 100%',
}, },
containStyle: 'font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;padding:12px;font-size: 16px;color: #606266;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 6px;background-color:#FFFFFF;', containStyle: 'font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;padding:12px;font-size: 14px;color: #606266;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 6px;background-color:#FFFFFF;',
loadingGif: HaloConfig.loadingGifUrl, loadingGif: HaloConfig.loadingGifUrl,
emptyGif: HaloConfig.loadingEmptyUrl, emptyGif: HaloConfig.loadingEmptyUrl,
+1 -1
View File
@@ -24,7 +24,7 @@ export default {
computed: { computed: {
// 获取全局应用设置 // 获取全局应用设置
globalAppSettings() { globalAppSettings() {
return uni.$tm.vx.getters().setting.getSettings; return uni.$tm.vx.getters().getSettings;
} }
}, },
created() { created() {
+66
View File
@@ -0,0 +1,66 @@
// 微信分享配置
import haloConfig from '@/config/halo.config.js'
import { jsonToUrlParams2 } from '@/utils/url.params.js'
export const haloWxShareMixin = {
data() {
return {
haloWxShareData: {
...haloConfig.wxShareConfig
},
}
},
//#ifdef MP-WEIXIN
onShareAppMessage(res) {
return {
...this.haloWxShareData,
success: res => {}
}
},
//#endif
/* 分享到微信好友 */
onShareAppMessage(res) {
const promise = new Promise(resolve => {
setTimeout(() => {
resolve({
title: this.haloWxShareData.title,
path: this.haloWxShareData.path,
})
}, 2000)
})
return {
title: this.haloWxShareData.title,
path: '',
promise
}
},
// 分享到朋友圈-这里封装不够,在页面还要声明一次,否则是拿不到参数的,被分享者在朋友圈打开链接是空的
onShareTimeline: function() {
return {
title: this.haloWxShareData.title,
query: {},
imageUrl: this.haloWxShareData.imageUrl,
}
},
methods: {
// 设置分享信息(需要在页面调用)
fnSetWxShareConfig(config = {}) {
let currentRoutes = getCurrentPages(); // 获取当前打开过的页面路由数组
let currentRoute = currentRoutes[currentRoutes.length - 1].route; //获取当前页面路由(分销思路,分享者点开使用的小程序将获取到分享者的id)
let sharePath = currentRoutes
if (config.params) {
const URLParams = config.params ? jsonToUrlParams2(config.params) : {};
sharePath += URLParams
}
let _config = Object.assign({}, {
path: sharePath,
copyLink: haloConfig.apiUrl,
query: {}
}, config)
uni.$tm.vx.commit('setWxShare', _config);
this.haloWxShareData = _config;
}
}
}
+117
View File
@@ -36,3 +36,120 @@
transform: rotateZ(360deg); transform: rotateZ(360deg);
} }
} }
// 自定义广告
.ad-card {
position: relative;
box-sizing: border-box;
padding: 24rpx;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03);
background-color: #ffffff;
border-radius: 12rpx;
&.is-lr {
display: flex;
.ad-card_tip {
top: initial;
left: 288rpx;
bottom: 24rpx;
// right: 160rpx;
padding: 4rpx 20rpx;
background-color: transparent;
border: 2rpx solid #607d8b;
color: #607d8b;
}
.ad-card_cover {
width: 240rpx;
height: 180rpx;
animation: adLinkAni 1s ease-in-out infinite;
}
.ad-card_info {
width: 0;
flex-grow: 1;
padding-left: 24rpx;
&-title {
margin-top: 0;
width: 100%;
font-size: 30rpx;
}
&-link {
top: initial;
// right: 150rpx;
bottom: 0;
transform: scale(1);
}
}
}
&_tip {
position: absolute;
left: 36rpx;
top: 36rpx;
display: inline-flex;
box-sizing: border-box;
border-radius: 6rpx;
padding: 4rpx 10rpx;
background-color: rgba(0, 0, 0, 0.3);
color: #ffffff;
font-size: 24rpx;
z-index: 2;
}
&_cover {
width: 100%;
height: 300rpx;
border-radius: 6rpx;
}
&_info {
display: flex;
flex-direction: column;
box-sizing: border-box;
position: relative;
&-title {
width: calc(100% - 120rpx);
font-size: 28rpx;
font-weight: bold;
margin-top: 8rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #333;
}
&-desc {
margin-top: 6rpx;
font-size: 24rpx;
color: #616161;
line-height: 1.8;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
&-link {
position: absolute;
right: 0;
top: 6rpx;
display: inline-flex;
box-sizing: border-box;
border-radius: 6rpx;
padding: 4rpx 10rpx;
border: 2rpx solid #03a9f4;
color: #03a9f4;
font-size: 24rpx;
transform: scale(0.93);
// animation: adLinkAni 0.8s ease-in-out infinite;
}
}
}
@keyframes adLinkAni {
0% {
transform: scale(1);
}
50% {
transform: scale(1.02);
}
100% {
transform: scale(1);
}
}
+12 -7
View File
@@ -12,7 +12,7 @@
</view> </view>
<view class="right"> <view class="right">
<view class="title"> <view class="title">
<text class="is-top" v-if="article.topped">置顶</text> <text class="is-top bg-gradient-blue-accent" v-if="article.topped">置顶</text>
<text class="title-text text-overflow">{{ article.title }}</text> <text class="title-text text-overflow">{{ article.title }}</text>
</view> </view>
<view class="content text-overflow-2">{{ article.summary }}</view> <view class="content text-overflow-2">{{ article.summary }}</view>
@@ -33,8 +33,10 @@
</template> </template>
<script> <script>
import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue';
export default { export default {
name: 'article-card', name: 'article-card',
components: { tmTags },
props: { props: {
from: { from: {
type: String, type: String,
@@ -157,10 +159,10 @@ export default {
} }
&.tb_image_text { &.tb_image_text {
flex-direction: column; flex-direction: column;
padding: 0; padding: 24rpx;
.left { .left {
width: 100%; width: 100%;
height: 300rpx; height: 340rpx;
.thumbnail { .thumbnail {
::v-deep uni-image { ::v-deep uni-image {
border-radius: 6rpx 6rpx 0 0 !important; border-radius: 6rpx 6rpx 0 0 !important;
@@ -169,7 +171,8 @@ export default {
} }
.right { .right {
padding-left: 0; padding-left: 0;
padding: 24rpx; padding: 24rpx 0;
padding-bottom: 0;
width: 100%; width: 100%;
.foot { .foot {
justify-content: flex-start; justify-content: flex-start;
@@ -188,7 +191,7 @@ export default {
flex-direction: column; flex-direction: column;
.left { .left {
width: 100%; width: 100%;
height: 260rpx; height: 340rpx;
order: 2; order: 2;
margin-top: 24rpx; margin-top: 24rpx;
} }
@@ -252,6 +255,7 @@ export default {
box-sizing: border-box; box-sizing: border-box;
.title { .title {
display: flex; display: flex;
align-items: center;
font-size: 30rpx; font-size: 30rpx;
color: var(--main-text-color); color: var(--main-text-color);
.is-top { .is-top {
@@ -263,8 +267,9 @@ export default {
white-space: nowrap; white-space: nowrap;
vertical-align: 4rpx; vertical-align: 4rpx;
color: #fff; color: #fff;
background-image: -webkit-linear-gradient(0deg, #3ca5f6 0, #a86af9 100%); // background-image: -webkit-linear-gradient(0deg, #3ca5f6 0, #a86af9 100%);
border-radius: 4rpx 12rpx; border-radius: 6rpx 12rpx;
box-shadow: none !important;
} }
&-text { &-text {
color: #303133; color: #303133;
@@ -56,7 +56,7 @@ export default {
margin: 12rpx 24rpx; margin: 12rpx 24rpx;
margin-bottom: 24rpx; margin-bottom: 24rpx;
padding: 16rpx; padding: 16rpx;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.05); box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.03);
&.lr_image_text { &.lr_image_text {
} }
@@ -1,15 +1,11 @@
<template> <template>
<view style="overflow: hidden;position: fixed;width: 100%;height: 100%;pointer-events: none; top: 0;"> <view class="barrage-wrap" :class="[type]">
<view class="danmu-li" v-for="(item, index) in listData" :class="item.type" :style="item.style" :key="index"> <view class="danmu-li" v-for="(item, index) in listData" :class="[type, item.type]" :style="[item.style]" :key="index">
<view class="danmu-inner"> <view class="danmu-inner">
<view class="user-box"> <view class="user-box">
<view class="user-img"> <view class="user-img"><image class="avatar" :src="item.item.avatar"></image></view>
<view class="img-box"> <view class="user-text cl1">{{ item.item.author }}</view>
<image :src="item.avatar || 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=317894666,3379114684&fm=26&gp=0.jpg'"></image> <view class="user-status cl1">{{ item.item.content }}</view>
</view>
</view>
<view class="user-text cl1">{{ item.nickName }}</view>
<view class="user-status cl1">{{ item.text }}</view>
</view> </view>
</view> </view>
</view> </view>
@@ -18,11 +14,17 @@
<script> <script>
export default { export default {
props: { props: {
//rightToLeft leftToRight leftBottom // rightToLeft leftToRight leftBottom
type: { type: {
type: String, type: String,
default: 'rightToLeft' default: 'rightToLeft'
}, },
list: {
type: Array,
default() {
return [];
}
},
minTime: { minTime: {
type: Number, type: Number,
default: 4 default: 4
@@ -43,34 +45,34 @@ export default {
// //
type: Number, type: Number,
default: 40 default: 40
},
noStacked: {
//()
type: Array,
default() {
return [];
}
} }
}, },
data() { data() {
return { return {
closeTimer: null,
listData: [] listData: []
}; };
}, },
mounted() { mounted() {
this.hrackNum = Math.floor((this.maxTop - this.minTop) / this.hrackH); //leftBottom 使
if (this.type === 'leftBottom') {
this.hrackNum = Math.floor(this.maxTop / this.hrackH);
}
}, },
methods: { methods: {
add(obj) { add(obj) {
this.isShow = true;
this.showFlag = true;
let data = { let data = {
item: obj.item, ...obj,
id: Date.parse(new Date()), id: Date.parse(new Date()),
time: Math.ceil(Math.floor(Math.random() * (this.maxTime - this.minTime + 1) + this.minTime)), time: Math.ceil(Math.floor(Math.random() * (this.maxTime - this.minTime + 1) + this.minTime)),
type: this.type type: this.type
}; };
if (this.type === 'leftBottom') { if (this.type === 'leftBottom') {
let objData = { let objData = {
item: data.item, item: data,
type: 'leftBottomEnter', type: 'leftBottomEnter',
style: { style: {
transition: `all 0.5s`, transition: `all 0.5s`,
@@ -88,7 +90,7 @@ export default {
} else if (this.listData[i].status === 'reset') { } else if (this.listData[i].status === 'reset') {
// //
this.listData[i].style.transition = 'none'; this.listData[i].style.transition = 'none';
this.listData[i].style.bottom = 0; this.listData[i].style.bottom = '6px';
this.listData[i].status = 'reuse'; this.listData[i].status = 'reuse';
} else if (this.listData[i].status === 'recycle') { } else if (this.listData[i].status === 'recycle') {
// //
@@ -105,8 +107,16 @@ export default {
if (listLen < hrackNum + 2) { if (listLen < hrackNum + 2) {
this.listData.push(objData); this.listData.push(objData);
} }
} else if (this.type === 'rightToLeft' || this.type === 'leftToRight') { } else if (this.type === 'rightToLeft') {
let objData = this.horStacked(data); let objData = {
item: data,
type: 'rightToLeft',
style: {
animationDuration: `${data.time}s`,
top: `${Math.ceil(Math.random() * (this.maxTop - this.minTop + 1) + this.minTop)}px`
},
delTime: Date.parse(new Date()) + data.time * 1200
};
for (let i in this.listData) { for (let i in this.listData) {
if (this.listData[i].delTime <= Date.parse(new Date())) { if (this.listData[i].delTime <= Date.parse(new Date())) {
this.repaint(i, objData.type); this.repaint(i, objData.type);
@@ -118,16 +128,50 @@ export default {
this.listData.push(objData); this.listData.push(objData);
} }
}, },
horStacked(data) { async remove(options = {}) {
return { if (this.type == 'rightToLeft') {
item: data.item, if (this.listData.length != 0) {
type: this.type, const last = this.listData[this.listData.length - 1];
style: { setTimeout(() => {
animationDuration: `${data.time}s`, this.listData = [];
top: `${Math.ceil(Math.random() * (this.maxTop - this.minTop + 1) + this.minTop)}px` }, last.item.time * 1200 + 1000);
}
return;
}
options = Object.assign(
{},
{
duration: 5000, //
speed: 1000 //
}, },
delTime: Date.parse(new Date()) + data.time * 1200 options
);
const _fnHandleRemove = item => {
return new Promise(resolve => {
setTimeout(() => {
// item['type'] = 'leftBottomExitLeft';
item['type'] = 'is-hide';
resolve();
}, options.speed);
});
}; };
const _fnHandleLoop = item => {
return new Promise(resolve => {
setTimeout(async () => {
for (var i = 0; i < this.listData.length; i++) {
await _fnHandleRemove(this.listData[i]);
}
resolve();
}, options.duration);
});
};
await _fnHandleLoop();
setTimeout(() => {
this.listData = [];
}, options.duration + 200);
}, },
repaint(index, type) { repaint(index, type) {
setTimeout(() => { setTimeout(() => {
@@ -137,8 +181,8 @@ export default {
} }
}; };
</script> </script>
<style></style>
<style lang="scss"> <style lang="scss" scoped>
@keyframes leftBottomEnter { @keyframes leftBottomEnter {
0% { 0% {
transform: translateY(100%); transform: translateY(100%);
@@ -163,6 +207,20 @@ export default {
} }
} }
@keyframes leftBottomExitLeft {
0% {
transform: translateX(0%);
opacity: 1;
}
50% {
transform: translateX(-50%);
opacity: 1;
}
100% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes leftToRight { @keyframes leftToRight {
0% { 0% {
transform: translateX(-100%); transform: translateX(-100%);
@@ -182,13 +240,38 @@ export default {
transform: translateX(-100%); transform: translateX(-100%);
} }
} }
.barrage-wrap {
position: fixed;
width: 100%;
height: 100%;
pointer-events: none;
top: 0;
z-index: 99;
transition: all 1s ease-in-out;
&.leftBottom {
top: initial;
/* #ifdef H5 */
bottom: 130rpx;
/* #endif */
/* #ifndef H5 */
bottom: 36rpx;
/* #endif */
}
}
.danmu-li { .danmu-li {
position: absolute; position: absolute;
width: 100%; width: 100%;
transform: translateX(100%); transform: translateX(100%);
animation-timing-function: linear; animation-timing-function: linear;
transition: all 0.5s ease-in-out;
opacity: 1;
&.is-hide {
opacity: 0;
// transform: translateX(-100%) !important;
}
&.leftBottom {
left: 24rpx;
}
&.leftBottomEnter { &.leftBottomEnter {
animation-name: leftBottomEnter; animation-name: leftBottomEnter;
} }
@@ -196,53 +279,59 @@ export default {
animation-name: leftBottomExit; animation-name: leftBottomExit;
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
&.leftBottomExitLeft {
animation-name: leftBottomExitLeft;
animation-fill-mode: forwards;
}
&.rightToLeft { &.rightToLeft {
animation-name: rightToLeft; animation-name: rightToLeft;
} }
&.leftToRight { &.leftToRight {
animation-name: leftToRight; animation-name: rightToLeft;
} }
.danmu-inner { .danmu-inner {
display: inline-block; display: inline-block;
font-size: 24rpx;
.user-box { .user-box {
display: flex; display: flex;
padding: 3rpx 40rpx 3rpx 10rpx; padding: 6rpx 40rpx 6rpx 10rpx;
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
border-radius: 32rpx; border-radius: 32rpx;
align-items: center; align-items: center;
.user-img { .user-img {
.img-box { display: flex;
display: flex; align-items: center;
justify-content: center;
image { .avatar {
width: 58rpx; width: 42rpx;
height: 58rpx; height: 42rpx;
background: rgba(55, 55, 55, 1); background: rgba(55, 55, 55, 1);
border-radius: 50%; border-radius: 50%;
}
} }
} }
.user-status { .user-status {
margin-left: 10rpx; margin-left: 10rpx;
white-space: nowrap; white-space: nowrap;
font-size: 28rpx;
font-weight: 400; font-weight: 400;
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
max-width: 320rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
} }
.user-text { .user-text {
max-width: 100rpx;
margin-left: 10rpx; margin-left: 10rpx;
// white-space: nowrap;
font-size: 28rpx;
font-weight: 400; font-weight: 400;
width: 80rpx;
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
} }
} }
} }
+6 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<view class=""> <view class="cache-image-wrap">
<view v-if="loadStatus == 'loading'" class="img-loading" :style="[imgStyle, loadStyle]"> <view v-if="loadStatus == 'loading'" class="img-loading" :style="[imgStyle, loadStyle]">
<!-- <text class="img-load-icon iconfont icon-loading"></text> <!-- <text class="img-load-icon iconfont icon-loading"></text>
<text class="img-load-text">{{ loadText }}</text> --> <text class="img-load-text">{{ loadText }}</text> -->
@@ -108,6 +108,7 @@ export default {
} }
}, },
created() { created() {
console.log('cache-image', this.url);
this.imgStyle = { this.imgStyle = {
width: this.width, width: this.width,
height: this.height, height: this.height,
@@ -144,6 +145,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.cache-image-wrap {
width: 100%;
height: 100%;
}
.img-loading, .img-loading,
.img-error { .img-error {
display: flex; display: flex;
@@ -1,6 +1,5 @@
<template> <template>
<view class="category-mini-card"> <view class="category-mini-card">
<!-- <image class="img" lazy-load :src="$utils.checkThumbnailUrl(category.thumbnail)" mode="aspectFill"></image> -->
<cache-image <cache-image
class="img" class="img"
height="120rpx" height="120rpx"
@@ -35,12 +34,13 @@ export default {
border-radius: 12rpx; border-radius: 12rpx;
background-color: #fff; background-color: #fff;
overflow: hidden; overflow: hidden;
// border: 2rpx solid #f7f7f7;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.03); box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.03);
position: relative;
.img { .img {
width: 100%; width: 100%;
height: 120rpx; height: 120rpx;
border: 6rpx 6rpx 0 0; border: 6rpx 6rpx 0 0;
overflow: hidden;
} }
.label { .label {
position: absolute; position: absolute;
@@ -55,9 +55,13 @@ export default {
padding-right: 24rpx; padding-right: 24rpx;
} }
.name { .name {
position: absolute;
bottom: 16rpx;
left: 0;
right: 0;
font-size: 24rpx; font-size: 24rpx;
text-align: center; text-align: center;
color: var(--main-text-color); color: #333;
} }
} }
</style> </style>
+28 -8
View File
@@ -1,8 +1,22 @@
<template> <template>
<view class=" comment-item flex flex-col mt-30 pt-24" :class="{ 'child-comment-item': isChild, 'no-solid': !useSolid, classItem }"> <view class=" comment-item flex flex-col mt-30 pt-24" :class="{ 'child-comment-item': isChild, 'no-solid': !useSolid, classItem }">
<view class="comment-item_user flex"> <view class="comment-item_user flex">
<image v-if="comment.isAdmin" class="user-avatar" :src="bloggerInfo.avatar" mode="aspectFill" @error="fnOnImageError(comment)"></image> <image
<image v-else class="user-avatar" :src="comment.avatar" mode="aspectFill" @error="fnOnImageError(comment)"></image> v-if="comment.isAdmin"
class="user-avatar"
:class="{ 'is-radius': globalAppSettings.isAvatarRadius }"
:src="bloggerInfo.avatar"
mode="aspectFill"
@error="fnOnImageError(comment)"
></image>
<image
v-else
class="user-avatar"
:class="{ 'is-radius': globalAppSettings.isAvatarRadius }"
:src="comment.avatar"
mode="aspectFill"
@error="fnOnImageError(comment)"
></image>
<view class="user-info pl-14"> <view class="user-info pl-14">
<view class="author"> <view class="author">
<text class="mr-6 text-grey-darken-1 text-size-m">{{ comment.author }}</text> <text class="mr-6 text-grey-darken-1 text-size-m">{{ comment.author }}</text>
@@ -11,7 +25,7 @@
<tm-tags v-else :dense="true" color="bg-gradient-light-blue-lighten " size="xs" model="fill">游客</tm-tags> <tm-tags v-else :dense="true" color="bg-gradient-light-blue-lighten " size="xs" model="fill">游客</tm-tags>
</view> </view>
<view class="flex mt-4"> <view class="flex mt-4">
<view v-if="false" class="text-size-s text-grey mr-12">IP属地浙江省杭州市</view> <view v-if="false" class="text-size-s text-grey mr-12">IP属地暂无信息</view>
<view class="time text-size-xs text-grey"> <view class="time text-size-xs text-grey">
<text class="">{{ $tm.dayjs(comment.createTime).format('YYYY年MM月DD日') }}</text> <text class="">{{ $tm.dayjs(comment.createTime).format('YYYY年MM月DD日') }}</text>
<text class="ml-12">{{ $tm.dayjs(comment.createTime).fromNow(true) }}</text> <text class="ml-12">{{ $tm.dayjs(comment.createTime).fromNow(true) }}</text>
@@ -19,13 +33,12 @@
</view> </view>
</view> </view>
<view v-if="useActions" class=""> <view v-if="useActions" class="">
<tm-button size="s" text theme="blue" @click="$emit('on-comment', { type: 'user', comment: comment })">回复</tm-button> <tm-button v-if="!disallowComment" size="s" text theme="blue" @click="$emit('on-comment', { type: 'user', comment: comment })">回复</tm-button>
<tm-button size="s" text theme="grey" @click="$emit('on-copy', comment.content)">复制</tm-button> <tm-button size="s" text theme="grey" @click="$emit('on-copy', comment.content)">复制</tm-button>
</view> </view>
</view> </view>
<view class="comment-item_content mt-12" :class="{ 'has-bg': useContentBg, 'not-ml': isChild }" @click="$emit('on-detail', comment)" v-html="comment.content"></view> <view class="comment-item_content mt-12" :class="{ 'has-bg': useContentBg, 'not-ml': isChild }" @click="$emit('on-detail', comment)" v-html="comment.content"></view>
<!-- <view v-if="useActions" class="comment-item_info text-size-s text-grey"> <!-- <view v-if="useActions" class="comment-item_info text-size-s text-grey">
<text v-if="false" @click="$emit('on-todo')">点赞</text> <text v-if="false" @click="$emit('on-todo')">点赞</text>
<text @click="$emit('on-comment', { type: 'user', comment: comment })">回复</text> <text @click="$emit('on-comment', { type: 'user', comment: comment })">回复</text>
@@ -46,6 +59,10 @@ export default {
type: Array, type: Array,
default: () => [] default: () => []
}, },
disallowComment: {
type: Boolean,
default: false
},
useActions: { useActions: {
type: Boolean, type: Boolean,
default: true default: true
@@ -74,7 +91,7 @@ export default {
computed: { computed: {
// 获取博主信息 // 获取博主信息
bloggerInfo() { bloggerInfo() {
let blogger = this.$tm.vx.getters().blogger.getBlogger; let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true); blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger; return blogger;
} }
@@ -111,10 +128,13 @@ export default {
.user-avatar { .user-avatar {
width: 70rpx; width: 70rpx;
height: 70rpx; height: 70rpx;
border-radius: 50%;
box-sizing: border-box; box-sizing: border-box;
border: 4rpx solid #ffffff;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.05); box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.05);
border: 4rpx solid #ffffff;
border-radius: 12rpx;
&.is-radius {
border-radius: 50%;
}
} }
.user-info { .user-info {
width: 0; width: 0;
+22 -6
View File
@@ -12,7 +12,6 @@
<!-- <text class="filter-item">全部</text> --> <!-- <text class="filter-item">全部</text> -->
</view> </view>
</view> </view>
<!-- <view v-if="disallowComment" class="disallow-comment"><tm-empty icon="icon-shiliangzhinengduixiang-" label="文章已开启禁止评论"></tm-empty></view> -->
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="comment-list_content"> <view class="comment-list_content">
<view v-if="loading != 'success'" class="loading-wrap flex"> <view v-if="loading != 'success'" class="loading-wrap flex">
@@ -27,9 +26,21 @@
</view> </view>
</view> </view>
<block v-else> <block v-else>
<tm-alerts
v-if="disallowComment && dataList.length !== 0"
color="red"
text
:margin="[0, 0]"
:shadow="0"
label="Ծ‸Ծ博主已设置该文章禁止评论!"
:round="3"
></tm-alerts>
<view class="empty pt-50" v-if="dataList.length == 0"> <view class="empty pt-50" v-if="dataList.length == 0">
<tm-empty icon="icon-shiliangzhinengduixiang-" label="暂无评论"> <tm-empty v-if="disallowComment" icon="icon-shiliangzhinengduixiang-" label="暂无评论">
<tm-button theme="bg-gradient-light-blue-accent" size="m" v-if="!disallowComment" @click="fnToComment(null)">抢沙发</tm-button> <text class="text-red text-size-s">- 文章已开启禁止评论 -</text>
</tm-empty>
<tm-empty v-else icon="icon-shiliangzhinengduixiang-" label="暂无评论">
<tm-button theme="light-blue" :dense="true" :shadow="0" size="m" @click="fnToComment(null)">抢沙发</tm-button>
</tm-empty> </tm-empty>
</view> </view>
<block v-else> <block v-else>
@@ -40,6 +51,7 @@
:isChild="false" :isChild="false"
:comment="comment" :comment="comment"
:postId="postId" :postId="postId"
:disallowComment="disallowComment"
@on-copy="fnCopyContent" @on-copy="fnCopyContent"
@on-comment="fnToComment" @on-comment="fnToComment"
@on-todo="fnToDo" @on-todo="fnToDo"
@@ -54,6 +66,7 @@
:isChild="true" :isChild="true"
:comment="childComment" :comment="childComment"
:postId="postId" :postId="postId"
:disallowComment="disallowComment"
@on-copy="fnCopyContent" @on-copy="fnCopyContent"
@on-comment="fnToComment" @on-comment="fnToComment"
@on-todo="fnToDo" @on-todo="fnToDo"
@@ -74,9 +87,11 @@
<script> <script>
import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue'; import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue'; import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
import tmAlerts from '@/tm-vuetify/components/tm-alerts/tm-alerts.vue';
export default { export default {
name: 'comment-list', name: 'comment-list',
components: { tmEmpty, tmButton }, components: { tmEmpty, tmButton, tmAlerts },
props: { props: {
// 是否禁用评论 // 是否禁用评论
disallowComment: { disallowComment: {
@@ -127,6 +142,7 @@ export default {
this.result = res.data; this.result = res.data;
this.dataList = res.data.content; this.dataList = res.data.content;
this.loading = 'success'; this.loading = 'success';
this.$emit('on-loaded', this.dataList);
} else { } else {
this.loading = 'error'; this.loading = 'error';
} }
@@ -200,7 +216,7 @@ export default {
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
padding-left: 24rpx; padding-left: 24rpx;
font-size: 34rpx; font-size: 30rpx;
font-weight: bold; font-weight: bold;
&:before { &:before {
@@ -209,7 +225,7 @@ export default {
left: 0rpx; left: 0rpx;
top: 8rpx; top: 8rpx;
width: 8rpx; width: 8rpx;
height: 30rpx; height: 26rpx;
background-color: rgb(3, 174, 252); background-color: rgb(3, 174, 252);
border-radius: 6rpx; border-radius: 6rpx;
} }
+1 -1
View File
@@ -96,7 +96,7 @@ export default {
computed: { computed: {
// 获取博主信息 // 获取博主信息
bloggerInfo() { bloggerInfo() {
let blogger = this.$tm.vx.getters().blogger.getBlogger; let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true); blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger; return blogger;
} }
-15
View File
@@ -1,15 +0,0 @@
#如何使用
###js
```javascript
import lffBarrage from '@/components/lff-barrage/lff-barrage.vue'
components:{lffBarrage},
methods:{
colrdo(){ //插入一条弹幕
this.$refs.lffBarrage.add({item:'你好呀小伙子'});
}
}
```
###HTML
```html
<lff-barrage ref="lffBarrage"></lff-barrage>
```
+85
View File
@@ -0,0 +1,85 @@
<template>
<view class="scroll-btn" :style="{ bottom: bottom }" @click.stop="fnScroll()">
<text v-if="_scrollTop >= 180" class="iconfont icon-long-arrow-up"></text>
<text v-else class="iconfont icon-long-arrow-down"></text>
</view>
</template>
<script>
import throttle from '@/utils/throttle.js';
export default {
name: 'scroll-btn',
props: {
bottom: {
type: String,
default: '180rpx'
},
scrollTop: {
type: Number,
default: 0
}
},
data() {
return { timer: null, _scrollTop: 0 };
},
watch: {
scrollTop(val) {
this._scrollTop = val;
this.$forceUpdate();
}
},
created() {
this._scrollTop = this.scrollTop;
},
methods: {
fnScroll() {
throttle(() => {
this.$emit('on-status', false);
const isTop = this._scrollTop >= 180;
this._scrollTop = isTop ? 0 : 999999999999;
uni.pageScrollTo({
duration: 500,
scrollTop: this._scrollTop,
success: () => {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.$emit('on-status', true);
}, 500);
}
});
this.$emit('update:scrollTop', this._scrollTop);
});
}
}
};
</script>
<style scoped lang="scss">
.scroll-btn {
position: fixed;
// bottom: 200rpx;
// right: -90rpx;
right: 52rpx;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
border-radius: 50%;
border: 4rpx solid #ffffff;
background-color: #bfe9ef;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.1);
z-index: 99;
transition: right 0.5s ease-in-out;
&.is-show {
right: 52rpx;
}
.iconfont {
font-size: 36rpx;
color: #555;
}
}
</style>
+11 -1
View File
@@ -15,6 +15,16 @@ export default {
}, },
// 文章详情广告 // 文章详情广告
articleDetail: { articleDetail: {
use: false, // 是否启用 // 微信广告/dclound申请的广告
use: true,
// 自定义广告
custom: {
use: true,
cover: 'https://b.925i.cn/uni_halo/uni_halo_ad_cover.png',
title: 'uni-halo 正式开源啦,欢迎来使用和体验!',
content: '基于 uni-app + halo1.x API 实现一款现代化的开源博客 / CMS 系统API开发的多端应用。功能包括:前台博客系统 和 后台管理系统,同时满足浏览和管理两端合一的需求,真正实现一个应用实现博客浏览和后台管理。',
url: 'https://uni-halo.925i.cn'
}
} }
} }
+36 -11
View File
@@ -14,19 +14,43 @@ export default {
showAbout: true, // 显示关于项目入口 showAbout: true, // 显示关于项目入口
uni_halo_logo: 'https://b.925i.cn/uni_halo/uni_halo_logo.png', // uni-halo的logo uni_halo_logo: 'https://b.925i.cn/uni_halo/uni_halo_logo.png', // uni-halo的logo
apiUrl: '', // Api基础域名(您的halo博客基础域名或者是Halo后台管理系统api地址) apiUrl: '', // Api基础域名 [必填] :你的Halo博客基础域名
apiAuthorization: '', // Halo中-系统-博客设置-切换到高级选项-API设置-Access key apiAuthorization: '', // Api认证key [必填] Halo中-系统-博客设置-切换到高级选项-API设置-Access key
title: '', // 博客标题 title: '', // 博客标题 [建议必填]:在某些页面没有设置具体的页面名称时候,使用该值显示
indexImageUrl: '', // 开屏首页图片 miniCodeImageUrl: '', // 小程序的太阳码/二维码的图片地址 [建议必填]:主要用于文章详情页面的生成海报的功能
miniCodeImageUrl: '', // 小程序码地址 aboutProfileImageUrl: '', // 关于页面中的资料卡背景图 [建议必填]
author: { // 启动页面的配置(页面地址`/pagesA/start/start`
name: '', // 昵称 start: {
avatar: '', // 头像地址 use: true, // 是否使用首次启动页:用户第一次使用你的应用会显示否则不显示
motto: '', // 格言 title: 'uni-halo', // 启动页面中的文字标题
bg: '', // 留空则使用默认 开屏首页背景,可以是颜色值或者图片图片地址
logo: 'https://b.925i.cn/uni_halo/uni_halo_logo.png', // logo
desc1: '全新UI,准备出发', // 描述信息1
desc2: '新触动 新感受 新体验', // 描述信息2
btnText: '全新触发' // 按钮文字
}, },
// 博主信息
author: {
use: true, // 是否启用这里配置的信息,不启用则获取PC端博客设置的信息
nickname: '', // 昵称
avatar: '', // 头像
email: '', // 邮箱
description: '', // 介绍
},
// 版权信息(用于文章详情)
copyright: {
use: true, // 是否使用版权描述
author: '', // 版权归属说明
description: '', // 版权描述
violation: '', // 侵权处理说明
},
// 社交信息(将会在`/pagesA/contact/contact`页面中展示)
// 具体的某个参数值留空则不展示
social: { social: {
qq: "", // qq号 qq: "", // qq号
wechat: "", // 微信号 wechat: "", // 微信号
@@ -41,6 +65,7 @@ export default {
}, },
defaultThumbnailUrl: '', // 默认封面图地址 defaultThumbnailUrl: '', // 默认封面图地址
defaultStaticThumbnailUrl: '', // 静态默认封面图(不可以是随机图地址)
defaultImageUrl: '', // 默认图片地址 defaultImageUrl: '', // 默认图片地址
defaultAvatarUrl: '', // 默认头像地址 defaultAvatarUrl: '', // 默认头像地址
@@ -97,8 +122,8 @@ export default {
title: '', // 小程序分享标题[非必填] title: '', // 小程序分享标题[非必填]
desc: '', // 小程序分享描述[非必填] desc: '', // 小程序分享描述[非必填]
imageUrl: '', // 小程序分享时候图片地址[非必填] imageUrl: '', // 小程序分享时候图片地址[非必填]
path: '/pages/start/start', // 分享路径[非必填] - 基本不需要修改 path: '/pages/index/index', // 分享路径[非必填] - 基本不需要修改
copyLink: '/pages/start/start', // 复制链接[非必填] - 基本不需要修改 copyLink: '/pages/index/index', // 复制链接[非必填] - 基本不需要修改
query: {}, // 分享参数[非必填] - 基本不需要填写 query: {}, // 分享参数[非必填] - 基本不需要填写
}, },
+148
View File
@@ -0,0 +1,148 @@
/**
* 恋爱日记配置
*/
export default {
waveImageUrl: 'https://b.925i.cn/uni_halo/uni_halo_about_wave.gif', // 波浪图片地址
bgImageUrl: 'https://b.925i.cn/uni_halo_love/love_bg1.png', // 背景图片
loveImageUrl: 'https://b.925i.cn/uni_halo_love/like.png', // 爱心图片
boy: {
name: '未知男主',
avatar: 'https://b.925i.cn/uni_halo_love/love_boy.png',
birthday: '2022-09-25', // 生日
},
girl: {
name: '未知女主',
avatar: 'https://b.925i.cn/uni_halo_love/love_girl.png',
birthday: '2022-04-19', // 生日
},
timeTitle: '这是我们一起走过的',
loveStartDate: '2022-04-10 13:14:20', // 恋爱开始时间
nav: [{
key: 'journey',
use: true,
iconImageUrl: 'https://b.925i.cn/uni_halo_love/diandian.png',
title: '关于我们',
desc: '我们一起度过的那些经历'
},
{
key: 'album',
use: true,
iconImageUrl: 'https://b.925i.cn/uni_halo_love/diandian.png',
title: '恋爱相册',
desc: '定格了我们的那些小美好'
},
{
key: 'list',
use: true,
iconImageUrl: 'https://b.925i.cn/uni_halo_love/diandian.png',
title: '恋爱清单',
desc: '你我之间的约定我们都在努力实现'
},
],
// 关于我们:支持富文本内容
journey: `
准备晚安啦,睡觉前讲个故事吧~<p>槐树庄的村口有一棵大槐树,树下的村口第一家就是猫奶奶的家。</p><p>猫奶奶是一位孤寡老人,因为她经常收留和救治周围的流浪猫,所以村民就都管她叫“猫奶奶”。</p><p>一个月圆之夜,猫奶奶走到院门口,忽然发现门口石级上放着一个红毯子,里面包着一个啼(tí)哭的女婴。</p><p>猫奶奶找不到女婴的父母,只好收留了她,并给她起了个名字叫樱红。</p><p>猫奶奶辛苦地抚育着樱红成长,转眼之间,樱红已经九岁,上小学三年级了。</p><p>从樱红懂事起,猫奶奶就爱给她讲一个睡前故事,那是当地一个古老的传说。</p><p>在浓郁的树影深处有一个百花园,百花园里生长着奇花异草,还住了一个会唱歌的花仙子。花仙子的歌声美丽动人,能治百病。但是那里有一条奇怪的规矩,寻找花仙子的人在进入百花园后,见到花仙子之前,都不能发出一点声音,不然花仙子就不会出来见他。</p><p>受这个故事的影响,樱红特别喜欢唱歌。</p><p>这天晚上,樱红放学回家,家家户户炊烟袅(niǎo)袅,而自家烟囱却连一丝一缕(lǚ)的炊烟都没有。</p><p>樱红一惊,冲进院门一看,果然出事了!只见猫奶奶呻吟着倒在灶台前,双目紧闭,两只小脚也在不停地抽搐(chù)。</p><p>樱红慌了,好在有邻居的帮助,猫奶奶被送到了医院。经过抢救,猫奶奶总算醒过来,但是却半身不遂(suí),说话也不利落了。</p><p>猫奶奶不能下地行走做家务,小小的樱红,一夜之间就挑起了家庭的重担。</p><p>樱红一面求助于村委会,四处寻医问药,让猫奶奶获得进一步的治疗;一面在课余学做家务,悉心照顾猫奶奶,端水喂饭,不辞辛苦。</p><p>自从猫奶奶病倒以后,樱红每天早晨推开院门就会看见门前放着一朵小花,有时还会有一两尾鲜活的鲑(guī)鱼。</p><p>这样过了三个月,好奇的樱红在一个夜晚悄悄躲在院门的后面,想看看到底是谁。</p><p>到了午夜十二点,只见一只花猫衔着一棵风铃草来到院门前,把风铃草放下,转身就走。(浪漫童话小故事)樱红认出这只小花猫曾经被猫奶奶救助过,于是,她悄悄地尾随小花猫往前走。</p><p>不一会儿,她就发现自己进入了一个从未见过的世界:蔚蓝的天空飘着七色的云,阳光千丝万缕地落下来,鲜花盛开,彩蝶飞舞,百鸟齐鸣。</p><p>这到底是什么地方?她忽然想起了那个传说,这该不会就是花仙子住的百花园吧?</p><p>樱红几乎惊叫起来,但她立即想起了那条在见到花仙子之前,不能发出一点声音的规矩。于是她捂紧了嘴巴。</p><p>这时,她发现百花园里除了自己还有一个面色苍白的男孩子,闭着眼睛,右手攥着一根竹竿摸索着前行,应该是眼睛看不见了。</p><p>只见男孩子慢慢地偏离了路径,马上就要掉进路边的水沟里了。</p><p>樱红下意识地大声呼喊:“站住,小心脚底下!”一张口,樱红才想起来,自己已经坏了规矩!</p><p>此时,“轰隆”一声巨响后,眼前的一切都消失了,樱红仍然站在自家院门前的大槐树下。</p><p>真遗憾啊!樱红深深叹了口气,可为了救人,她并不觉得后悔。</p><p>第二天早上,樱红被一种美妙的歌声唤醒。</p><p>唱歌的人就是美丽的花仙子,她乘坐着奇花异草编成的花篮,飘进了她家的院子里。</p><p>奇迹发生了,只见猫奶奶起身下床,像健康人一样走出房门。</p><p>猫奶奶看到了花仙子,不敢相信地揉着眼睛说:“你就是传说中的花仙子吗?是你治好了我的病?”</p><p>花仙子说:“是的!是这个小女孩的善良打动了我,连我那不能出声的规矩都要为她破例了。”</p><p>樱红高兴地看着猫奶奶。从此,她和猫奶奶继续幸福地生活着。</p>
`,
// 恋爱相册
albumKeyName: '恋爱相册', // 对应后台的图库分组名称
// 恋爱清单
loveList: {
useApi: false, // 是否启用api接口
api: '', // api 接口(如果使用api接口的方式,则下方的data可以留空,但是api接口必须按照对应的数据格式返回)
data: [{
index: 0, // 序号
finish: true, // 是否已完成
title: '偷偷记录对方熟睡的模样', // 事件名称
desc: '偷偷观察对方熟睡的模样,记录下来', // 事件描述
detail: {
start: '2022年05月20日', // 计划开始时间
desc: '偷偷观察对方熟睡的模样,记录下来', // 事件详细描述
end: '每天', // 完成时间,
moment: '', // 完成瞬间的记录
other: '', // 其他说明
}
}, {
index: 1,
finish: false,
title: '陪对方过生日',
desc: '陪对方一起过生日',
detail: {
start: '2023年05月20日',
desc: '陪对方一起过生日,他和我的生日',
end: '',
moment: '',
other: '他 生日5月20日 我生日9月25日',
}
},
{
index: 2,
finish: false,
title: '一起去旅行',
desc: '一起来一场说走就走的旅行,希望去的是大理',
detail: {
start: '',
desc: '',
end: '',
moment: '一起来一场说走就走的旅行,希望去的是大理',
other: '',
}
},
{
index: 3,
finish: false,
title: '一起穿情侣装逛街',
desc: '一起穿情侣装逛街',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '',
}
},
{
index: 4,
finish: false,
title: '一起看日出',
desc: '一起看日出',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '',
}
},
{
index: 5,
finish: false,
title: '一起看日落',
desc: '一起看日落',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '', // 其他说明
}
},
{
index: 6,
finish: false,
title: '一起买菜、做饭、刷碗',
desc: '一起买菜、做饭、刷碗',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '',
}
}
],
}
}
+150
View File
@@ -0,0 +1,150 @@
/**
* 恋爱日记配置
*/
export default {
waveImageUrl: 'https://b.925i.cn/uni_halo/uni_halo_about_wave.gif', // 波浪图片地址
bgImageUrl: 'https://b.925i.cn/uni_halo_love/love_bg1.png', // 背景图片
loveImageUrl: 'https://b.925i.cn/uni_halo_love/like.png', // 爱心图片
boy: {
name: '未知男主',
avatar: 'https://b.925i.cn/uni_halo_love/love_boy.png',
birthday: '2022-09-25', // 生日
},
girl: {
name: '未知女主',
avatar: 'https://b.925i.cn/uni_halo_love/love_girl.png',
birthday: '2022-07-25', // 生日
},
timeTitle: '这是我们一起走过的', // 恋爱时间标题
loveStartDate: '2022-05-20 13:14:20', // 恋爱开始时间
// 恋爱日记首页导航(除了 key 以外都可以修改)
nav: [{
key: 'journey',
use: true,
iconImageUrl: 'https://b.925i.cn/uni_halo_love/diandian.png',
title: '关于我们',
desc: '我们一起度过的那些经历'
},
{
key: 'album',
use: true,
iconImageUrl: 'https://b.925i.cn/uni_halo_love/diandian.png',
title: '恋爱相册',
desc: '定格了我们的那些小美好'
},
{
key: 'list',
use: true,
iconImageUrl: 'https://b.925i.cn/uni_halo_love/diandian.png',
title: '恋爱清单',
desc: '你我之间的约定我们都在努力实现'
},
],
// 关于我们:支持富文本内容
journey: `
<p>有一只马,它的邻居是一只驴。</p><p>有一天,马和驴都被主人牵到外面晒太阳,马和驴聊起了天。</p><p>马说:“我叫马,你呢?”</p><p>驴说:“我叫驴。(哄小宝贝睡觉的甜甜睡前故事)”</p><p>马说:“为什么我俩的名字不一样呢?”</p><p>驴说:“因为我和你不一样。”</p><p>马说:“我们俩什么地方不一样呢?”</p><p>驴说:“我身材小巧,而你却比较粗壮,不如我耐看。”马看了看比自已矮小很多的驴,认为驴说的话有点道理。</p><p>马说:“我们俩除了身材不一样,还有什么不同呢?”</p><p>驴说:“我们俩的声音不一样,我的声音多动听呀!”说着驴伸长脖子叫了两声。“不信,你也叫两声试试。”马也伸长脖子嘶鸣了两声,的确和驴的声音有点不同,马不好意思地低下了头。</p><p>过了一会儿,马又说:“我们俩除了身材和声音不一样外,还有什么不同呢?”</p><p>驴说:“我的步伐多么优雅呀。”说着,驴迈开蹄子走了两步,“而你呢,却昂首阔步,一点儿也不优雅,(如何哄女朋友睡觉的睡前故事爱情浪漫)不信你走两步试试。”</p><p>马听驴这么一说,就高昂着头走了两步,旋即,马飞奔了起来,转了一圈回来后,驴得意地说:“怎么样,我没说错罢,你就是急性子,和优雅不沾边。”马听了驴的话,有点感到惭愧。</p><p>最后,马又鼓起勇气说:“我们俩还有什么不同呢?”</p><p>驴说:“我的家庭意识比你强,主人抽我一鞭子,我就跟着主人回家,而你呢?恐怕不会吧……”</p><p>马还没有来得及回答,马和驴的主人同时来到了马和驴的身边。只见驴的主人抽了驴一鞭子后,驴乖乖地跟着主人回家了。马把这一切都看在了眼里,它为自已和驴的诸多不同而感到惭愧,只见马的主人也抽了马一鞭子,马犹豫了一下,终于象驴一样乖乖地跟着主人回了家。</p><p>一个伯乐站在远处看到了这一幕后,叹口气离开了。</p>
`,
// 恋爱相册
albumKeyName: '恋爱相册', // 对应后台的图库分组名称
// 恋爱清单
loveList: {
useApi: false, // 是否启用api接口
api: '', // api 接口(如果使用api接口的方式,则下方的data可以留空,但是api接口必须按照对应的数据格式返回)
data: [{
index: 0, // 序号
finish: true, // 是否已完成
title: '偷偷记录对方熟睡的模样', // 事件名称
desc: '偷偷观察对方熟睡的模样,记录下来', // 事件描述
detail: {
start: '2022年05月20日', // 计划开始时间
desc: '偷偷观察对方熟睡的模样,记录下来', // 事件详细描述
end: '每天', // 完成时间,
moment: '', // 完成瞬间的记录
other: '', // 其他说明
}
}, {
index: 1,
finish: false,
title: '陪对方过生日',
desc: '陪对方一起过生日',
detail: {
start: '2023年05月20日',
desc: '陪对方一起过生日,他和我的生日',
end: '',
moment: '',
other: '他 生日5月20日 我生日9月25日',
}
},
{
index: 2,
finish: false,
title: '一起去旅行',
desc: '一起来一场说走就走的旅行,希望去的是大理',
detail: {
start: '',
desc: '',
end: '',
moment: '一起来一场说走就走的旅行,希望去的是大理',
other: '',
}
},
{
index: 3,
finish: false,
title: '一起穿情侣装逛街',
desc: '一起穿情侣装逛街',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '',
}
},
{
index: 4,
finish: false,
title: '一起看日出',
desc: '一起看日出',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '',
}
},
{
index: 5,
finish: false,
title: '一起看日落',
desc: '一起看日落',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '', // 其他说明
}
},
{
index: 6,
finish: false,
title: '一起买菜、做饭、刷碗',
desc: '一起买菜、做饭、刷碗',
detail: {
start: '',
desc: '',
end: '',
moment: '',
other: '',
}
}
],
}
}
+160 -157
View File
@@ -1,159 +1,162 @@
{ {
"name": "uni-halo", "name" : "uni-halo",
"appid": "__UNI__5748B6E", "appid" : "__UNI__5748B6E",
"description": "uni-halo博客:基于halo开源博客系统API开发的多端博客。", "description" : "uni-halo博客:基于halo开源博客系统API开发的多端博客。",
"versionName": "1.0.0", "versionName" : "1.0.0",
"versionCode": 100, "versionCode" : 100,
"transformPx": false, "transformPx" : false,
/* 5+App */ /* 5+App */
"app-plus": { "app-plus" : {
"usingComponents": true, "usingComponents" : true,
"nvueStyleCompiler": "uni-app", "nvueStyleCompiler" : "uni-app",
"compilerVersion": 3, "compilerVersion" : 3,
"splashscreen": { "splashscreen" : {
"alwaysShowBeforeRender": true, "alwaysShowBeforeRender" : true,
"waiting": true, "waiting" : true,
"autoclose": true, "autoclose" : true,
"delay": 0 "delay" : 0
}, },
/* */ /* */
"modules": { "modules" : {
"OAuth": {}, "OAuth" : {},
"Share": {} "Share" : {}
}, },
/* */ /* */
"distribute": { "distribute" : {
/* android */ /* android */
"android": { "android" : {
"permissions": [ "permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CAPTURE_VIDEO_OUTPUT\"/>", "<uses-permission android:name=\"android.permission.CAPTURE_VIDEO_OUTPUT\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>", "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
] ]
}, },
/* ios */ /* ios */
"ios": { "ios" : {
"dSYMs": false, "dSYMs" : false,
"capabilities": { "capabilities" : {
"entitlements": { "entitlements" : {
"com.apple.developer.associated-domains": [ "com.apple.developer.associated-domains" : [ "applinks:static-699a26a5-a6cd-4b54-b603-5155b312a5f5.bspapp.com" ]
"applinks:static-699a26a5-a6cd-4b54-b603-5155b312a5f5.bspapp.com" }
] }
} },
} /* SDK */
}, "sdkConfigs" : {
/* SDK */ "ad" : {
"sdkConfigs": { "gdt" : {},
"ad": { "csj" : {},
"gdt": {}, "360" : {},
"csj": {}, "ks" : {},
"360": {}, "sigmob" : {},
"ks": {}, "hw" : {},
"sigmob": {}, "bd" : {}
"hw": {}, },
"bd": {} "oauth" : {
}, "weixin" : {
"oauth": { "appid" : "wxd971954762ec4744",
"weixin": { "UniversalLinks" : "https://static-699a26a5-a6cd-4b54-b603-5155b312a5f5.bspapp.com/uni-universallinks/__UNI__5748B6E/"
"appid": "wxd971954762ec4744", }
"UniversalLinks": "https://static-699a26a5-a6cd-4b54-b603-5155b312a5f5.bspapp.com/uni-universallinks/__UNI__5748B6E/" },
} "share" : {
}, "weixin" : {
"share": { "appid" : "wxd971954762ec4744",
"weixin": { "UniversalLinks" : "https://static-699a26a5-a6cd-4b54-b603-5155b312a5f5.bspapp.com/uni-universallinks/__UNI__5748B6E/"
"appid": "wxd971954762ec4744", }
"UniversalLinks": "https://static-699a26a5-a6cd-4b54-b603-5155b312a5f5.bspapp.com/uni-universallinks/__UNI__5748B6E/" }
} },
} "icons" : {
}, "android" : {
"icons": { "hdpi" : "unpackage/res/icons/72x72.png",
"android": { "xhdpi" : "unpackage/res/icons/96x96.png",
"hdpi": "unpackage/res/icons/72x72.png", "xxhdpi" : "unpackage/res/icons/144x144.png",
"xhdpi": "unpackage/res/icons/96x96.png", "xxxhdpi" : "unpackage/res/icons/192x192.png"
"xxhdpi": "unpackage/res/icons/144x144.png", },
"xxxhdpi": "unpackage/res/icons/192x192.png" "ios" : {
}, "appstore" : "unpackage/res/icons/1024x1024.png",
"ios": { "ipad" : {
"appstore": "unpackage/res/icons/1024x1024.png", "app" : "unpackage/res/icons/76x76.png",
"ipad": { "app@2x" : "unpackage/res/icons/152x152.png",
"app": "unpackage/res/icons/76x76.png", "notification" : "unpackage/res/icons/20x20.png",
"app@2x": "unpackage/res/icons/152x152.png", "notification@2x" : "unpackage/res/icons/40x40.png",
"notification": "unpackage/res/icons/20x20.png", "proapp@2x" : "unpackage/res/icons/167x167.png",
"notification@2x": "unpackage/res/icons/40x40.png", "settings" : "unpackage/res/icons/29x29.png",
"proapp@2x": "unpackage/res/icons/167x167.png", "settings@2x" : "unpackage/res/icons/58x58.png",
"settings": "unpackage/res/icons/29x29.png", "spotlight" : "unpackage/res/icons/40x40.png",
"settings@2x": "unpackage/res/icons/58x58.png", "spotlight@2x" : "unpackage/res/icons/80x80.png"
"spotlight": "unpackage/res/icons/40x40.png", },
"spotlight@2x": "unpackage/res/icons/80x80.png" "iphone" : {
}, "app@2x" : "unpackage/res/icons/120x120.png",
"iphone": { "app@3x" : "unpackage/res/icons/180x180.png",
"app@2x": "unpackage/res/icons/120x120.png", "notification@2x" : "unpackage/res/icons/40x40.png",
"app@3x": "unpackage/res/icons/180x180.png", "notification@3x" : "unpackage/res/icons/60x60.png",
"notification@2x": "unpackage/res/icons/40x40.png", "settings@2x" : "unpackage/res/icons/58x58.png",
"notification@3x": "unpackage/res/icons/60x60.png", "settings@3x" : "unpackage/res/icons/87x87.png",
"settings@2x": "unpackage/res/icons/58x58.png", "spotlight@2x" : "unpackage/res/icons/80x80.png",
"settings@3x": "unpackage/res/icons/87x87.png", "spotlight@3x" : "unpackage/res/icons/120x120.png"
"spotlight@2x": "unpackage/res/icons/80x80.png", }
"spotlight@3x": "unpackage/res/icons/120x120.png" }
} }
} }
} },
} /* */
}, "quickapp" : {},
/* */ /* */
"quickapp": {}, "mp-weixin" : {
/* */ "appid" : "wx1bb161867082c72f",
"mp-weixin": { "setting" : {
"appid": "wx1bb161867082c72f", "urlCheck" : false,
"setting": { "minified" : true
"urlCheck": false, },
"minified": true "usingComponents" : true
}, },
"usingComponents": true "mp-alipay" : {
}, "usingComponents" : true
"mp-alipay": { },
"usingComponents": true "mp-baidu" : {
}, "usingComponents" : true
"mp-baidu": { },
"usingComponents": true "mp-toutiao" : {
}, "usingComponents" : true
"mp-toutiao": { },
"usingComponents": true "uniStatistics" : {
}, "enable" : false
"uniStatistics": { },
"enable": false "vueVersion" : "2",
}, "h5" : {
"vueVersion": "2", "title" : "uni-halo",
"h5": { "devServer" : {
"title": "uni-halo", "disableHostCheck" : true,
"devServer": { "proxy" : {
"https": false, "/api" : {
"disableHostCheck": true, "target" : "https://b.925i.cn",
"proxy": { "changeOrigin" : true,
"/api": { "secure" : false,
"target": "https://b.925i.cn", "pathRewrite" : {
"changeOrigin": true, "^/api" : ""
"secure": false, }
"pathRewrite": { }
"^/api": "" }
} },
} "optimization" : {
} "preload" : true,
} "treeShaking" : {
}, "enable" : true
"_spaceID": "699a26a5-a6cd-4b54-b603-5155b312a5f5" }
}
},
"_spaceID" : "699a26a5-a6cd-4b54-b603-5155b312a5f5"
} }
+21 -7
View File
@@ -1,9 +1,23 @@
{ {
"devDependencies": { "name": "uni-halo",
"vue-i18n": "^9.1.10" "version": "1.0.0",
}, "description": "<p align=\"center\">\r <img alt=\"logo\" src=\"https://b.925i.cn/uni_halo/uni_halo_logo.png\" width=\"120\" height=\"120\" style=\"margin-bottom: 10px;\">\r </p>\r <h3 align=\"center\" style=\"margin: 30px 0 30px;font-weight: bold;font-size:40px;\">uni-halo</h3>\r <h3 align=\"center\">uni-halo 基于Halo一款现代化的开源博客/CMS系统API开发的可多端编译应用</h3>",
"dependencies": { "repository": {
"uni-read-pages": "^1.0.5", "type": "git",
"uni-simple-router": "^2.0.8-beta.4" "url": "git+https://gitee.com/ialley-workshop-open/uni-halo.git"
} },
"keywords": ["uni-halo", "小莫唐尼", "巷子工坊"],
"author": "巷子工坊丨小莫唐尼",
"license": "AGPL-3.0",
"bugs": {
"url": "https://gitee.com/ialley-workshop-open/uni-halo/issues"
},
"homepage": "https://uni-halo.925i.cn",
"devDependencies": {
"vue-i18n": "^9.1.10"
},
"dependencies": {
"uni-read-pages": "^1.0.5",
"uni-simple-router": "^2.0.8-beta.4"
}
} }
+48 -5
View File
@@ -110,7 +110,28 @@
}, { }, {
"path": "love/love", "path": "love/love",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "恋爱日记",
"navigationStyle": "custom",
"enablePullDownRefresh": false,
"app-plus": {
"pullToRefresh": {
"color": "#03a9f4",
"style": "circle"
}
}
}
}, {
"path": "love/list",
"style": {
"navigationBarTitleText": "恋爱清单",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
}, {
"path": "love/album",
"style": {
"navigationBarTitleText": "恋爱相册",
"enablePullDownRefresh": true, "enablePullDownRefresh": true,
"app-plus": { "app-plus": {
"pullToRefresh": { "pullToRefresh": {
@@ -119,7 +140,13 @@
} }
} }
} }
}, {
"path": "love/journey",
"style": {
"navigationBarTitleText": "我们的故事",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
}, { }, {
"path": "archives/archives", "path": "archives/archives",
"style": { "style": {
@@ -201,8 +228,7 @@
"path": "contact/contact", "path": "contact/contact",
"style": { "style": {
"navigationBarTitleText": "联系博主", "navigationBarTitleText": "联系博主",
"enablePullDownRefresh": false, "enablePullDownRefresh": false
"navigationStyle": "custom"
} }
}, { }, {
"path": "about/about", "path": "about/about",
@@ -216,7 +242,24 @@
"navigationBarTitleText": "设置", "navigationBarTitleText": "设置",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, {
"path": "tags/tags",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "tag-detail/tag-detail",
"style": {
"navigationBarTitleText": "标签详情",
"enablePullDownRefresh": true,
"app-plus": {
"pullToRefresh": {
"color": "#03a9f4",
"style": "circle"
}
}
}
}] }]
}, },
{ {
+9 -3
View File
@@ -5,11 +5,17 @@
<script> <script>
export default { export default {
onLoad() { onLoad() {
this.fnCheckHadStarted(); this.fnCheckShowStarted();
}, },
methods: { methods: {
// 检查是否已经启动 // 检查是否需要跳转到启动
fnCheckHadStarted() { fnCheckShowStarted() {
if (!getApp().globalData.start.use) {
uni.switchTab({
url: '/pages/tabbar/home/home'
});
return;
}
if (uni.getStorageSync('APP_HAS_STARTED')) { if (uni.getStorageSync('APP_HAS_STARTED')) {
uni.switchTab({ uni.switchTab({
url: '/pages/tabbar/home/home' url: '/pages/tabbar/home/home'
+104 -22
View File
@@ -1,11 +1,13 @@
<template> <template>
<view class="app-page pb-24"> <view class="app-page pb-24">
<!-- 博主信息 --> <!-- 博主信息 -->
<view class="blogger-info"> <view class="blogger-info" :style="[calcProfileStyle]">
<image class="avatar" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill" @click="miniProfileCard.show = true"></image> <image class="avatar" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill"></image>
<view class="profile"> <view class="profile">
<view class="author mt-24 text-size-g text-weight-b">{{ bloggerInfo.nickname }}</view> <view class="author mt-24 text-size-g text-weight-b">{{ bloggerInfo.nickname }}</view>
<view class="desc mt-24 text-size-m">{{ bloggerInfo.description || '一个爱凑热闹的、喜欢捣鼓前端的博主。' }}</view> <view class="desc mt-24 text-size-m">
{{ bloggerInfo.description || '这个博主很懒,竟然没写介绍~' }}
</view>
</view> </view>
<image v-if="calcWaveUrl" :src="calcWaveUrl" mode="scaleToFill" class="gif-wave"></image> <image v-if="calcWaveUrl" :src="calcWaveUrl" mode="scaleToFill" class="gif-wave"></image>
</view> </view>
@@ -17,19 +19,34 @@
<view class="statistics flex pt-24 pb-24" :class="{ 'has-solid': statisticsShowMore }"> <view class="statistics flex pt-24 pb-24" :class="{ 'has-solid': statisticsShowMore }">
<view class="item flex-1 text-align-center"> <view class="item flex-1 text-align-center">
<view class="number text-size-xl text-bg-gradient-orange-accent"> <view class="number text-size-xl text-bg-gradient-orange-accent">
<tm-flop :startVal="0" :decimals="0" :endVal="statistics.postCount" :duration="3000"></tm-flop> <tm-flop
:startVal="0"
:decimals="0"
:endVal="statistics.postCount"
:duration="3000"
></tm-flop>
</view> </view>
<view class="mt-6 text-align-center text-size-s text-grey-darken-1">文章总数</view> <view class="mt-6 text-align-center text-size-s text-grey-darken-1">文章总数</view>
</view> </view>
<view class="item flex-1 text-align-center"> <view class="item flex-1 text-align-center">
<view class="number text-size-xl text-bg-gradient-blue-accent"> <view class="number text-size-xl text-bg-gradient-blue-accent">
<tm-flop :startVal="0" :decimals="0" :endVal="statistics.categoryCount" :duration="3000"></tm-flop> <tm-flop
:startVal="0"
:decimals="0"
:endVal="statistics.categoryCount"
:duration="3000"
></tm-flop>
</view> </view>
<view class="mt-6 text-align-center text-size-s text-grey-darken-1">分类总数</view> <view class="mt-6 text-align-center text-size-s text-grey-darken-1">分类总数</view>
</view> </view>
<view class="item flex-1 text-align-center"> <view class="item flex-1 text-align-center">
<view class="number text-size-xl text-bg-gradient-green-accent"> <view class="number text-size-xl text-bg-gradient-green-accent">
<tm-flop :startVal="0" :decimals="0" :endVal="statistics.tagCount" :duration="3000"></tm-flop> <tm-flop
:startVal="0"
:decimals="0"
:endVal="statistics.tagCount"
:duration="3000"
></tm-flop>
</view> </view>
<view class="mt-6 text-size-s text-grey-darken-1">标签总数</view> <view class="mt-6 text-size-s text-grey-darken-1">标签总数</view>
</view> </view>
@@ -37,19 +54,34 @@
<view class="statistics solid-top has-solid flex pt-24 pb-24"> <view class="statistics solid-top has-solid flex pt-24 pb-24">
<view class="item flex-1 text-align-center"> <view class="item flex-1 text-align-center">
<view class="number text-size-xl text-bg-gradient-orange-accent"> <view class="number text-size-xl text-bg-gradient-orange-accent">
<tm-flop :startVal="0" :decimals="0" :endVal="statistics.commentCount" :duration="3000"></tm-flop> <tm-flop
:startVal="0"
:decimals="0"
:endVal="statistics.commentCount"
:duration="3000"
></tm-flop>
</view> </view>
<view class="mt-6 text-align-center text-size-s text-grey-darken-1">评论数量</view> <view class="mt-6 text-align-center text-size-s text-grey-darken-1">评论数量</view>
</view> </view>
<view class="item flex-1 text-align-center"> <view class="item flex-1 text-align-center">
<view class="number text-size-xl text-bg-gradient-blue-accent"> <view class="number text-size-xl text-bg-gradient-blue-accent">
<tm-flop :startVal="0" :decimals="0" :endVal="statistics.linkCount" :duration="3000"></tm-flop> <tm-flop
:startVal="0"
:decimals="0"
:endVal="statistics.linkCount"
:duration="3000"
></tm-flop>
</view> </view>
<view class="mt-6 text-align-center text-size-s text-grey-darken-1">点赞数量</view> <view class="mt-6 text-align-center text-size-s text-grey-darken-1">点赞数量</view>
</view> </view>
<view class="item flex-1 text-align-center"> <view class="item flex-1 text-align-center">
<view class="number text-size-xl text-bg-gradient-green-accent"> <view class="number text-size-xl text-bg-gradient-green-accent">
<tm-flop :startVal="0" :decimals="0" :endVal="statistics.visitCount" :duration="3000"></tm-flop> <tm-flop
:startVal="0"
:decimals="0"
:endVal="statistics.visitCount"
:duration="3000"
></tm-flop>
</view> </view>
<view class="mt-6 text-size-s text-grey-darken-1">访客数量</view> <view class="mt-6 text-size-s text-grey-darken-1">访客数量</view>
</view> </view>
@@ -60,7 +92,12 @@
<!-- 快捷导航 --> <!-- 快捷导航 -->
<view v-if="useQuickNav" class="quick-nav flex flex-between round-3 ma-24 pa-24 pl-40 pr-40"> <view v-if="useQuickNav" class="quick-nav flex flex-between round-3 ma-24 pa-24 pl-40 pr-40">
<view class="quick-nav-item flex flex-col flex-center" v-for="(nav, index) in quickNavList" :key="index" @click="fnToNavPage(nav)"> <view
class="quick-nav-item flex flex-col flex-center"
v-for="(nav, index) in quickNavList"
:key="index"
@click="fnToNavPage(nav)"
>
<view class="icon round-24 halocoloricon" :class="[nav.icon]"></view> <view class="icon round-24 halocoloricon" :class="[nav.icon]"></view>
<view class="name text-size-s mt-8">{{ nav.text }}</view> <view class="name text-size-s mt-8">{{ nav.text }}</view>
</view> </view>
@@ -80,7 +117,9 @@
@click="fnOnNav(nav)" @click="fnOnNav(nav)"
> >
<template slot="rightValue"> <template slot="rightValue">
<button class="right-value-btn" v-if="nav.openType" :open-type="nav.openType">{{ nav.rightText }}</button> <button class="right-value-btn" v-if="nav.openType" :open-type="nav.openType">
{{ nav.rightText }}
</button>
<text v-else>{{ nav.rightText }}</text> <text v-else>{{ nav.rightText }}</text>
</template> </template>
</tm-listitem> </tm-listitem>
@@ -88,7 +127,9 @@
</tm-grouplist> </tm-grouplist>
</view> </view>
<!-- 版权 --> <!-- 版权 -->
<view v-if="showCopyright" class="copyright mt-40 text-size-xs text-align-center"><view class=""> 2022 uni-halo 开源项目@小莫唐尼 </view></view> <view v-if="showCopyright" class="copyright mt-40 text-size-xs text-align-center">
<view class=""> 2022 uni-halo 开源项目@小莫唐尼 </view>
</view>
<!-- 名片 --> <!-- 名片 -->
<tm-poup v-model="miniProfileCard.show" width="94vw" height="auto" :round="3" position="center"> <tm-poup v-model="miniProfileCard.show" width="94vw" height="auto" :round="3" position="center">
@@ -97,17 +138,35 @@
<view class="left flex flex-col flex-center"> <view class="left flex flex-col flex-center">
<image class="avatar" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill"></image> <image class="avatar" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill"></image>
<view class="name mt-10 text-size-m text-weight-b">{{ bloggerInfo.nickname }}</view> <view class="name mt-10 text-size-m text-weight-b">{{ bloggerInfo.nickname }}</view>
<view class="mt-10 round-a-1 pa-2 pl-12 pr-12 text-size-s bg-gradient-light-blue-accent">前端摸鱼大师</view> <view class="mt-10 round-a-1 pa-2 pl-12 pr-12 text-size-s bg-gradient-light-blue-accent">
<view class="mt-6 text-size-xs text-align-center text-grey-darken-2">一个爱凑热闹的喜欢捣鼓前端的博主</view> 前端摸鱼大师
</view>
<view class="mt-6 text-size-xs text-align-center text-grey-darken-2">
一个爱凑热闹的喜欢捣鼓前端的博主
</view>
</view> </view>
<view class="right flex flex-col pl-12"> <view class="right flex flex-col pl-12">
<view class="label text-size-s text-weight-b">爱好摸鱼打游戏听音乐逛B站</view> <view class="label text-size-s text-weight-b">爱好摸鱼打游戏听音乐逛B站</view>
<view class="motto mt-12 text-size-s text-grey-darken-1">如果不是在空闲着的时候就能挣到钱那就不算摸鱼</view> <view class="motto mt-12 text-size-s text-grey-darken-1">
如果不是在空闲着的时候就能挣到钱那就不算摸鱼
</view>
<view class="mt-12 text-size-m text-weight-b text-grey-darken-2">精选图片</view> <view class="mt-12 text-size-m text-weight-b text-grey-darken-2">精选图片</view>
<view class="photos mt-6 flex "> <view class="photos mt-6 flex ">
<image class="photos-img round-2" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill"></image> <image
<image class="photos-img round-2" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill"></image> class="photos-img round-2"
<image class="photos-img round-2" :src="$utils.checkAvatarUrl(bloggerInfo.avatar)" mode="aspectFill"></image> :src="$utils.checkAvatarUrl(bloggerInfo.avatar)"
mode="aspectFill"
></image>
<image
class="photos-img round-2"
:src="$utils.checkAvatarUrl(bloggerInfo.avatar)"
mode="aspectFill"
></image>
<image
class="photos-img round-2"
:src="$utils.checkAvatarUrl(bloggerInfo.avatar)"
mode="aspectFill"
></image>
</view> </view>
</view> </view>
</view> </view>
@@ -168,7 +227,19 @@ export default {
}, },
computed: { computed: {
bloggerInfo() { bloggerInfo() {
return this.$tm.vx.getters().blogger.getBlogger; return this.$tm.vx.getters().getBlogger;
},
calcProfileStyle() {
let _imgUrlOr = getApp().globalData.aboutProfileImageUrl;
if (this.$utils.checkIsUrl(_imgUrlOr)) {
return {
backgroundImage: `url(${_imgUrlOr})`
};
} else {
return {
background: _imgUrlOr
};
}
}, },
calcWaveUrl() { calcWaveUrl() {
return getApp().globalData.waveImageUrl; return getApp().globalData.waveImageUrl;
@@ -374,7 +445,8 @@ export default {
}) })
.then(res => { .then(res => {
uni.clearStorageSync(); uni.clearStorageSync();
this.navList.find(x => x.key == 'cache').rightText = uni.getStorageInfoSync().currentSize + 'KB'; this.navList.find(x => x.key == 'cache').rightText =
uni.getStorageInfoSync().currentSize + 'KB';
}) })
.catch(err => {}); .catch(err => {});
break; break;
@@ -405,6 +477,18 @@ export default {
// 快捷导航页面跳转 // 快捷导航页面跳转
fnToNavPage(item) { fnToNavPage(item) {
// 判断是内置页面还是网页
if (this.$utils.checkIsUrl(item.path)) {
uni.navigateTo({
url:
'/pagesC/website/website?data=' +
JSON.stringify({
title: item.text || this.$haloConfig.title,
url: item.path
})
});
return;
}
switch (item.type) { switch (item.type) {
case 'tabbar': case 'tabbar':
uni.switchTab({ uni.switchTab({
@@ -437,10 +521,8 @@ export default {
position: relative; position: relative;
width: 100%; width: 100%;
height: 600rpx; height: 600rpx;
background-image: url('@/static/summer.jpg');
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;
// box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.05);
&:before { &:before {
content: ''; content: '';
width: 100%; width: 100%;
+19 -4
View File
@@ -11,7 +11,7 @@
<tm-empty icon="icon-shiliangzhinengduixiang-" label="博主还没有文章分类~"></tm-empty> <tm-empty icon="icon-shiliangzhinengduixiang-" label="博主还没有文章分类~"></tm-empty>
</view> </view>
<block v-else> <block v-else>
<tm-sliderNav :list="categoryList" color="light-blue" rang-key="name" @change="fnOnCategoryChange"></tm-sliderNav> <tm-sliderNav :list="categoryList" bg-color="white" color="light-blue" rang-key="name" @change="fnOnCategoryChange"></tm-sliderNav>
<scroll-view <scroll-view
class="right-content pt-12 pb-12" class="right-content pt-12 pb-12"
:scroll-y="true" :scroll-y="true"
@@ -20,9 +20,14 @@
:refresher-enabled="true" :refresher-enabled="true"
:refresher-triggered="triggered" :refresher-triggered="triggered"
:refresher-threshold="60" :refresher-threshold="60"
refresher-background="#fafafa"
@refresherrefresh="fnGetData(true)" @refresherrefresh="fnGetData(true)"
@scrolltolower="fnGetData(false)" @scrolltolower="fnGetData(false)"
@scroll="fnOnScroll" @scroll="fnOnScroll"
@touchmove.stop
@touchstart="fnOnTouchStart"
@touchend="fnOnTouchEnd"
@touchcancel="fnOnTouchEnd"
> >
<view v-if="dataList.length == 0" class="article-empty flex flex-center"> <view v-if="dataList.length == 0" class="article-empty flex flex-center">
<tm-empty icon="icon-shiliangzhinengduixiang-" label="该分类下暂无文章~"></tm-empty> <tm-empty icon="icon-shiliangzhinengduixiang-" label="该分类下暂无文章~"></tm-empty>
@@ -78,6 +83,8 @@ export default {
isLoadMore: false, isLoadMore: false,
loadMoreText: '', loadMoreText: '',
scrollTop: 0, scrollTop: 0,
tempScrollTop: 0,
scrollTimeout: null,
triggered: false triggered: false
}; };
}, },
@@ -181,9 +188,7 @@ export default {
}); });
}, },
fnOnScroll(e) { fnOnScroll(e) {
throttle(() => { this.tempScrollTop = e.detail.scrollTop;
this.scrollTop = e.detail.scrollTop;
}, 1000);
}, },
fnToTopScroll() { fnToTopScroll() {
uni.pageScrollTo({ uni.pageScrollTo({
@@ -191,6 +196,15 @@ export default {
duration: 500 duration: 500
}); });
this.scrollTop = 0; this.scrollTop = 0;
this.tempScrollTop = 0;
},
fnOnTouchStart() {
clearTimeout(this.scrollTimeout);
},
fnOnTouchEnd() {
this.scrollTimeout = setTimeout(() => {
this.scrollTop = this.tempScrollTop;
}, 500);
} }
} }
}; };
@@ -222,6 +236,7 @@ export default {
height: 100vh; height: 100vh;
background-color: #fff; background-color: #fff;
white-space: nowrap; white-space: nowrap;
background-color: #fafafa;
} }
.loading-wrap { .loading-wrap {
padding: 24rpx; padding: 24rpx;
+43 -33
View File
@@ -1,5 +1,5 @@
<template> <template>
<view class="app-page" :class="{ 'is-balck grey-darken-6': isBlackTheme }"> <view class="app-page">
<!-- 顶部切换 --> <!-- 顶部切换 -->
<view class="e-fixed" v-if="category.list.length > 2"> <view class="e-fixed" v-if="category.list.length > 2">
<tm-tabs color="light-blue" v-model="category.activeIndex" :list="category.list" align="left" @change="fnOnCategoryChange"></tm-tabs> <tm-tabs color="light-blue" v-model="category.activeIndex" :list="category.list" align="left" @change="fnOnCategoryChange"></tm-tabs>
@@ -9,24 +9,22 @@
<!-- 加载区域 --> <!-- 加载区域 -->
<view v-if="loading != 'success'" class="loading-wrap"> <view v-if="loading != 'success'" class="loading-wrap">
<tm-skeleton model="card"></tm-skeleton> <tm-skeleton model="card"></tm-skeleton>
<tm-skeleton model="cardActions"></tm-skeleton> <tm-skeleton model="card"></tm-skeleton>
<tm-skeleton model="list"></tm-skeleton> <tm-skeleton model="card"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton> <tm-skeleton model="card"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton>
</view> </view>
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="content" v-else> <view class="content" v-else>
<view v-if="dataList.length == 0" class="content-empty"> <view v-if="dataList.length == 0" class="content-empty">
<!-- 空布局 --> <!-- 空布局 -->
<tm-empty icon="icon-shiliangzhinengduixiang-" label="该分类下暂无数据"></tm-empty> <tm-empty icon="icon-shiliangzhinengduixiang-" label="博主还没有分享图片~"></tm-empty>
</view> </view>
<block v-else> <block v-else>
<tm-flowLayout v-if="globalAppSettings.gallery.useWaterfull" @click="fnOnClick" ref="wafll"> <tm-flowLayout v-if="globalAppSettings.gallery.useWaterfull" @click="fnOnClick" ref="wafll">
<template v-slot:left="{ hdata }"> <template v-slot:left="{ hdata }">
<tm-translate animation-name="fadeUp"> <tm-translate animation-name="fadeUp">
<view class="round-3 shadow-2 overflow white"> <view class="card round-3 overflow white">
<tm-images :previmage="true" :src="hdata.item.image"></tm-images> <tm-images :previmage="false" :src="hdata.item.image" @click="fnPreview(hdata.item)"></tm-images>
<view class="pa-10 text-size-s"> <view class="pa-10 text-size-s">
<view class="text-overflow-2"> <view class="text-overflow-2">
<tm-tags color="bg-gradient-amber-accent" :shadow="0" :dense="true" size="s" model="fill">{{ hdata.item.team }}</tm-tags> <tm-tags color="bg-gradient-amber-accent" :shadow="0" :dense="true" size="s" model="fill">{{ hdata.item.team }}</tm-tags>
@@ -50,8 +48,8 @@
</template> </template>
<template v-slot:right="{ hdata }"> <template v-slot:right="{ hdata }">
<tm-translate animation-name="fadeUp"> <tm-translate animation-name="fadeUp">
<view class="round-3 shadow-2 overflow white"> <view class="card round-3 overflow white">
<tm-images :previmage="true" :src="hdata.item.image"></tm-images> <tm-images :previmage="false" :src="hdata.item.image" @click="fnPreview(hdata.item)"></tm-images>
<view class="pa-10 text-size-s"> <view class="pa-10 text-size-s">
<view class="text-overflow-2"> <view class="text-overflow-2">
<tm-tags :shadow="0" :dense="true" color="bg-gradient-amber-accent" size="s" model="fill">{{ hdata.item.team }}</tm-tags> <tm-tags :shadow="0" :dense="true" color="bg-gradient-amber-accent" size="s" model="fill">{{ hdata.item.team }}</tm-tags>
@@ -78,7 +76,7 @@
<block v-for="(item, index) in dataList" :key="index"> <block v-for="(item, index) in dataList" :key="index">
<tm-translate animation-name="fadeUp" :wait="(index + 1) * 50"> <tm-translate animation-name="fadeUp" :wait="(index + 1) * 50">
<view class="round-3 shadow-2 overflow white mb-24"> <view class="round-3 shadow-2 overflow white mb-24">
<tm-images :previmage="false" :src="item.image" @click="fnPreview(item, index)"></tm-images> <tm-images :previmage="false" :src="item.image" @click="fnPreview(item)"></tm-images>
<view class="pa-24 text-size-m"> <view class="pa-24 text-size-m">
<view class="text-overflow-2"> <view class="text-overflow-2">
<tm-tags :shadow="0" :dense="true" color="bg-gradient-amber-accent" size="s" model="fill">{{ item.team }}</tm-tags> <tm-tags :shadow="0" :dense="true" color="bg-gradient-amber-accent" size="s" model="fill">{{ item.team }}</tm-tags>
@@ -227,26 +225,32 @@ export default {
this.$httpApi this.$httpApi
.getPhotoListByPage(this.queryParams) .getPhotoListByPage(this.queryParams)
.then(res => { .then(res => {
this.loading = 'success'; if (res.status == 200) {
this.result = res.data; this.loading = 'success';
if (res.data.content.length != 0) { this.result = res.data;
const _list = res.data.content.map((item, index) => { if (res.data.content.length != 0) {
item['image'] = this.$utils.checkImageUrl(item.thumbnail); const _list = res.data.content.map((item, index) => {
item['model'] = 'text'; item['image'] = this.$utils.checkImageUrl(item.thumbnail);
item['takeTime'] = this.$tm.dayjs(item['takeTime']).format('DD/MM/YYYY'); item['model'] = 'text';
return item; item['takeTime'] = this.$tm.dayjs(item['takeTime']).format('DD/MM/YYYY');
}); return item;
this.fnCacheDataList(_list);
if (this.globalAppSettings.gallery.useWaterfull) {
this.dataList = _list;
this.$nextTick(() => {
this.$refs.wafll.pushData(_list);
}); });
} else { this.fnCacheDataList(_list);
this.dataList = this.dataList.concat(_list); if (this.globalAppSettings.gallery.useWaterfull) {
this.dataList = _list;
this.$nextTick(() => {
this.$refs.wafll.pushData(_list);
});
} else {
this.dataList = this.dataList.concat(_list);
}
} }
this.loadMoreText = res.data.hasNext ? '上拉加载更多' : '呜呜,没有更多数据啦~';
} else {
this.loading = 'error';
this.waterfall.loading = 'finish';
this.loadMoreText = '';
} }
this.loadMoreText = res.data.hasNext ? '上拉加载更多' : '呜呜,没有更多数据啦~';
}) })
.catch(err => { .catch(err => {
console.error(err); console.error(err);
@@ -275,10 +279,11 @@ export default {
console.log('点击数据', data); console.log('点击数据', data);
}, },
// 预览 // 预览
fnPreview(item, index) { fnPreview(item) {
const index = this.cache.dataList.findIndex(x => x.id == item.id);
uni.previewImage({ uni.previewImage({
current: index, current: index,
urls: this.dataList.map(x => x.image), urls: this.cache.dataList.map(x => x.image),
indicator: 'number', indicator: 'number',
loop: true loop: true
}); });
@@ -287,20 +292,21 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.app-page { .app-page {
width: 100vw; width: 100vw;
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-bottom: 24rpx; padding-bottom: 24rpx;
background-color: #fafafd; background-color: #fafafa;
&.is-balck { &.is-balck {
background-color: #212121; background-color: #212121;
} }
} }
.content { .content {
box-sizing: border-box;
padding: 0 24rpx; padding: 0 24rpx;
padding-top: 24rpx; padding-top: 24rpx;
@@ -312,6 +318,10 @@ export default {
} }
} }
.loading-wrap { .loading-wrap {
box-sizing: border-box;
padding: 24rpx; padding: 24rpx;
} }
.card {
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03);
}
</style> </style>
+12 -14
View File
@@ -136,9 +136,8 @@ export default {
}, },
computed: { computed: {
// 获取博主信息
bloggerInfo() { bloggerInfo() {
let blogger = this.$tm.vx.getters().blogger.getBlogger; let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true); blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger; return blogger;
} }
@@ -150,13 +149,6 @@ export default {
created() { created() {
this.fnQuery(); this.fnQuery();
this.$httpApi
.getOptionList()
.then(result => {
console.log('配置列表:');
console.log(result);
})
.catch(err => {});
}, },
onPullDownRefresh() { onPullDownRefresh() {
this.isLoadMore = false; this.isLoadMore = false;
@@ -177,7 +169,6 @@ export default {
} }
}, },
methods: { methods: {
// 查询数据
fnQuery() { fnQuery() {
this.fnGetBanner(); this.fnGetBanner();
this.fnGetArticleList(); this.fnGetArticleList();
@@ -196,7 +187,10 @@ export default {
this.$httpApi this.$httpApi
.getCategoryList({ more: true }) .getCategoryList({ more: true })
.then(res => { .then(res => {
this.categoryList = res.data; this.categoryList = res.data.sort((a, b) => {
return b.postCount - a.postCount;
});
setTimeout(() => { setTimeout(() => {
this.loading = 'success'; this.loading = 'success';
}, 500); }, 500);
@@ -216,12 +210,16 @@ export default {
fnGetBanner() { fnGetBanner() {
const _this = this; const _this = this;
const _format = function(list, type) { const _format = function(list, type) {
return list.map(item => { return list.map((item, index) => {
switch (type) { switch (type) {
case 'list': case 'list':
return { return {
id: '', id: index,
src: item nickname: _this.bloggerInfo.nickname,
avatar: _this.bloggerInfo.avatar,
address: item.href || '',
title: item.title,
image: _this.$utils.checkImageUrl(item.thumbnail)
}; };
case 'article': case 'article':
return { return {
+89 -58
View File
@@ -7,65 +7,94 @@
<tm-skeleton model="listAvatr"></tm-skeleton> <tm-skeleton model="listAvatr"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton> <tm-skeleton model="listAvatr"></tm-skeleton>
</view> </view>
<block v-else> <view v-else class="content" :class="{ 'bg-white': result.length !== 0 }">
<!-- 空数据 --> <!-- 空数据 -->
<view v-if="result.length == 0" class="empty flex flex-center"><tm-empty icon="icon-shiliangzhinengduixiang-" label="啊偶,博主还没有朋友呢~"></tm-empty></view> <view v-if="result.length == 0" class="content-empty flex flex-center"><tm-empty icon="icon-shiliangzhinengduixiang-" label="啊偶,博主还没有朋友呢~"></tm-empty></view>
<!-- 如果只有一个分组使用列表的形式 result.length == 1 --> <!-- 如果只有一个分组使用列表的形式 result.length == 1 -->
<view v-else-if="result.length == 1" class="flex flex-col pb-24"> <view v-else-if="result.length == 1" class="flex flex-col pb-24">
<block v-for="(item, index) in result[0].children" :key="index"> <block v-for="(link, index) in result[0].children" :key="index">
<tm-translate animation-name="fadeUp" :wait="(index + 1) * 50"> <tm-translate animation-name="fadeUp" :wait="(index + 1) * 50">
<view class="link-card one round-a-6 flex ma-24 mb-0 pa-24" @click="fnOnLinkEvent(item)"> <!-- 色彩版本 -->
<cache-image class="logo shadow-2" radius="12rpx" width="80rpx" height="80rpx" :url="item.logo" :fileMd5="item.logo" mode="aspectFill"></cache-image> <view
v-if="!globalAppSettings.links.useSimple"
class="info flex pt-24 pb-24 pl-12 pr-12 border-b-1"
:class="{ 'border-b-1': index != team.children.length - 1 }"
@click="fnOnLinkEvent(link)"
>
<view class="link-logo"><cache-image class="link-logo_img" radius="12rpx" :url="link.logo" :fileMd5="link.logo" mode="aspectFill"></cache-image></view>
<view class="flex flex-col pl-30 info-detail">
<view class="link-card_name text-size-l text-weight-b text-red">{{ link.name }}</view>
<view class="poup-tag ml--10 mt-6">
<tm-tags color="bg-gradient-amber-accent" :shadow="0" size="s" model="fill">ID{{ link.id }}</tm-tags>
<tm-tags color=" bg-gradient-light-blue-lighten" :shadow="0" size="s" model="fill">{{ link.team || '暂未分组' }}</tm-tags>
</view>
<view class="link-card_desc text-overflow text-size-s mt-4">博客简介{{ link.description || '这个博主很懒,没写简介~' }}</view>
</view>
</view>
<!-- 简洁版本 -->
<view v-else class="link-card flex ml-24 mr-24 pt-24 pb-24" @click="fnOnLinkEvent(link)">
<image class="logo shadow-6" :src="link.logo" mode="aspectFill"></image>
<view class="info pl-24"> <view class="info pl-24">
<view class="name text-size-g">{{ item.name }}</view> <view class="name text-size-g">{{ link.name }}</view>
<view class="desc mt-12 text-size-s text-grey-darken-1">{{ item.description }}</view> <view class="desc mt-12 text-size-s text-grey-darken-1">{{ link.description }}</view>
<view class="link mt-12 text-size-m text-grey-darken-1"> <view v-if="false" class="link mt-12 text-size-m text-grey-darken-1">
<text class="iconfont icon-link mr-6 text-size-s"></text> <text class="iconfont icon-link mr-6 text-size-s"></text>
{{ item.url }} {{ link.url }}
</view> </view>
</view> </view>
</view> </view>
</tm-translate> </tm-translate>
</block> </block>
<!-- 返回顶部 -->
<tm-flotbutton @click="fnToTopPage" size="m" icon="icon-angle-up"></tm-flotbutton>
</view> </view>
<!-- 如果大于一个分组使用联系人的索引形式 result.length > 1 --> <!-- 如果大于一个分组使用联系人的索引形式 result.length > 1 -->
<block v-else-if="result.length > 1"> <block v-else>
<tm-quickIndex :list="result"> <block v-for="(team, index) in result" :key="index">
<template #cell="{ data }"> <tm-translate animation-name="fadeUp" :wait="(index + 1) * 50">
<!-- 艳丽版本 --> <view class="grey-lighten-4 text text-size-s text-weight-b px-32 py-12">{{ team.title }}</view>
<view v-if="!globalAppSettings.links.useSimple" class="info flex pa-36 border-b-1" @click="fnOnLinkEvent(data.item)"> <block v-for="(link, linkIndex) in team.children" :key="link.id">
<view class="link-logo"> <tm-translate animation-name="fadeUp" :wait="(linkIndex + 1) * 50">
<cache-image class="link-logo_img" radius="12rpx" :url="data.item.logo" :fileMd5="data.item.logo" mode="aspectFill"></cache-image> <!-- 色彩版本 -->
</view> <view
<view class="flex flex-col pl-30 info-detail"> v-if="!globalAppSettings.links.useSimple"
<view class="link-card_name text-size-l text-weight-b text-red">{{ data.item.name }}</view> class="info flex pt-24 pb-24 pl-12 pr-12"
<view class="poup-tag ml--10 mt-6"> :class="{ 'border-b-1': linkIndex != team.children.length - 1 || index == result.length - 1 }"
<tm-tags color="bg-gradient-amber-accent" :shadow="0" size="s" model="fill">ID{{ data.item.id }}</tm-tags> @click="fnOnLinkEvent(link)"
<tm-tags color=" bg-gradient-light-blue-lighten" :shadow="0" size="s" model="fill">{{ data.item.team }}</tm-tags> >
<view class="link-logo">
<cache-image class="link-logo_img" radius="12rpx" :url="link.logo" :fileMd5="link.logo" mode="aspectFill"></cache-image>
</view>
<view class="flex flex-col pl-30 info-detail">
<view class="link-card_name text-size-l text-weight-b text-red">{{ link.name }}</view>
<view class="poup-tag ml--10 mt-6">
<tm-tags color="bg-gradient-amber-accent" :shadow="0" size="s" model="fill">ID{{ link.id }}</tm-tags>
<tm-tags color=" bg-gradient-light-blue-lighten" :shadow="0" size="s" model="fill">{{ link.team || '暂未分组' }}</tm-tags>
</view>
<view class="link-card_desc text-overflow text-size-s mt-4">博客简介{{ link.description || '这个博主很懒,没写简介~' }}</view>
</view>
</view> </view>
<view class="link-card_desc text-overflow text-size-s mt-4">博客简介{{ data.item.description || '这个博主很懒,没写简介~' }}</view> <!-- 简洁版本 -->
</view> <view v-else class="link-card flex ml-24 mr-24 pt-24 pb-24" @click="fnOnLinkEvent(link)">
</view> <image class="logo shadow-6" :src="link.logo" mode="aspectFill"></image>
<!-- 简洁版本 --> <view class="info pl-24">
<view v-else class="link-card flex ml-24 mr-24 pt-24 pb-24" @click="fnOnLinkEvent(data.item)"> <view class="name text-size-g">{{ link.name }}</view>
<image class="logo shadow-6" :src="data.item.logo" mode="aspectFill"></image> <view class="desc mt-12 text-size-s text-grey-darken-1">{{ link.description }}</view>
<view class="info pl-24"> <view v-if="false" class="link mt-12 text-size-m text-grey-darken-1">
<view class="name text-size-g">{{ data.item.name }}</view> <text class="iconfont icon-link mr-6 text-size-s"></text>
<view class="desc mt-12 text-size-s text-grey-darken-1">{{ data.item.description }}</view> {{ link.url }}
<view v-if="false" class="link mt-12 text-size-m text-grey-darken-1"> </view>
<text class="iconfont icon-link mr-6 text-size-s"></text> </view>
{{ data.item.url }}
</view> </view>
</view> </tm-translate>
</view> </block>
</template> </tm-translate>
</tm-quickIndex> </block>
</block> </block>
<!-- 返回顶部 -->
<tm-flotbutton v-if="linkTotal > 10" color="light-blue" @click="fnToTopPage" size="m" icon="icon-angle-up"></tm-flotbutton>
<!-- 详情弹窗 --> <!-- 详情弹窗 -->
<tm-poup v-model="detail.show" :width="640" height="auto" position="center" :round="6"> <tm-poup v-model="detail.show" :width="640" height="auto" position="center" :round="6">
<view class="poup pa-36"> <view class="poup pa-36">
@@ -75,7 +104,7 @@
<view class="poup-name text-size-lg text-weight-b">{{ detail.data.name }}</view> <view class="poup-name text-size-lg text-weight-b">{{ detail.data.name }}</view>
<view class="poup-tag ml--10"> <view class="poup-tag ml--10">
<tm-tags color="bg-gradient-amber-accent" size="n" model="fill">ID{{ detail.data.id }}</tm-tags> <tm-tags color="bg-gradient-amber-accent" size="n" model="fill">ID{{ detail.data.id }}</tm-tags>
<tm-tags color="bg-gradient-light-blue-lighten" size="n" model="fill">{{ detail.data.team }}</tm-tags> <tm-tags color="bg-gradient-light-blue-lighten" size="n" model="fill">{{ detail.data.team || '暂未分组' }}</tm-tags>
</view> </view>
<view class="poup-link text-size-m" @click="fnCopyLink(detail.data)"> <view class="poup-link text-size-m" @click="fnCopyLink(detail.data)">
<text class="text-orange">{{ detail.data.url }}</text> <text class="text-orange">{{ detail.data.url }}</text>
@@ -90,7 +119,7 @@
<view class="mt-24"><tm-images :width="568" :round="2" :src="caclSiteThumbnail(detail.data.url)" mode="aspectFill"></tm-images></view> <view class="mt-24"><tm-images :width="568" :round="2" :src="caclSiteThumbnail(detail.data.url)" mode="aspectFill"></tm-images></view>
</view> </view>
</tm-poup> </tm-poup>
</block> </view>
</view> </view>
</template> </template>
@@ -101,11 +130,9 @@ import tmFlotbutton from '@/tm-vuetify/components/tm-flotbutton/tm-flotbutton.vu
import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue'; import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue';
import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue'; import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
import tmImages from '@/tm-vuetify/components/tm-images/tm-images.vue'; import tmImages from '@/tm-vuetify/components/tm-images/tm-images.vue';
import tmQuickIndex from '@/tm-vuetify/components/tm-quickIndex/tm-quickIndex.vue';
import tmPoup from '@/tm-vuetify/components/tm-poup/tm-poup.vue'; import tmPoup from '@/tm-vuetify/components/tm-poup/tm-poup.vue';
import { GetRandomNumberByRange } from '@/utils/random.js'; import { GetRandomNumberByRange } from '@/utils/random.js';
import findCnChart from '@/tm-vuetify/tool/function/findCnChart.js';
export default { export default {
components: { components: {
tmSkeleton, tmSkeleton,
@@ -114,7 +141,6 @@ export default {
tmTags, tmTags,
tmEmpty, tmEmpty,
tmImages, tmImages,
tmQuickIndex,
tmPoup tmPoup
}, },
data() { data() {
@@ -129,7 +155,8 @@ export default {
detail: { detail: {
show: false, show: false,
data: {} data: {}
} },
linkTotal: 0
}; };
}, },
computed: { computed: {
@@ -158,6 +185,7 @@ export default {
return this.$haloConfig.colors[_r]; return this.$haloConfig.colors[_r];
}, },
fnGetData() { fnGetData() {
this.linkTotal = 0;
this.loading = 'loading'; this.loading = 'loading';
uni.showLoading({ uni.showLoading({
mask: true, mask: true,
@@ -169,18 +197,16 @@ export default {
if (res.status == 200) { if (res.status == 200) {
console.log('请求结果:'); console.log('请求结果:');
console.log(res); console.log(res);
let resData = res.data;
// 处理数据 // 处理数据
const _result = resData.map(item => { const _result = res.data.map(item => {
const _team = item.team || '未分组'; const _team = item.team || '未分组';
const _firstChart = _team ? _team.substring(0, 1) : '';
const _links = item.links.map(link => { const _links = item.links.map(link => {
this.linkTotal += 1;
link.logo = this.$utils.checkAvatarUrl(link.logo); link.logo = this.$utils.checkAvatarUrl(link.logo);
return link; return link;
}); });
return { return {
title: _team, title: _team,
index: findCnChart(_firstChart),
children: _links children: _links
}; };
}); });
@@ -190,9 +216,7 @@ export default {
this.loading = 'success'; this.loading = 'success';
}, 500); }, 500);
} else { } else {
setTimeout(() => { this.loading = 'error';
this.loading = 'error';
}, 500);
} }
}) })
.catch(err => { .catch(err => {
@@ -240,17 +264,24 @@ export default {
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: #fafafd;
} }
.loading-wrap { .loading-wrap {
padding: 24rpx; padding: 24rpx;
min-height: 100vh; min-height: 100vh;
} }
.empty { .content {
width: 100vw; padding: 0 24rpx;
height: 60vh; padding-top: 24rpx;
}
.content-empty {
height: 60vh;
display: flex;
align-items: center;
justify-content: center;
}
}
.link-card { .link-card {
border-bottom: 2rpx solid #f5f5f5; border-bottom: 2rpx solid #f5f5f5;
background-color: #ffffff; background-color: #ffffff;
@@ -266,7 +297,7 @@ export default {
// height: 126rpx; // height: 126rpx;
width: 80rpx; width: 80rpx;
height: 80rpx; height: 80rpx;
border-radius: 50%; border-radius: 12rpx;
border: 6rpx solid #ffffff; border: 6rpx solid #ffffff;
box-shadow: none; box-shadow: none;
} }
+1 -1
View File
@@ -26,7 +26,7 @@
</tm-grouplist> </tm-grouplist>
</view> </view>
<view class="copyright bg-white text-size-xs text-align-center text-grey-darken-1 pa-36"> <view class="copyright bg-white text-size-xs text-align-center text-grey-darken-1 pa-36">
<view class="">根据 MIT 许可证发布</view> <view class="">根据 AGPL-3.0 协议开源</view>
<view class="mt-8"> 2022 uni-halo 开源项目丨巷子工坊@小莫唐尼 </view> <view class="mt-8"> 2022 uni-halo 开源项目丨巷子工坊@小莫唐尼 </view>
</view> </view>
</view> </view>
+241 -46
View File
@@ -11,14 +11,15 @@
<view class="title">{{ result.title }}</view> <view class="title">{{ result.title }}</view>
<view class="detail"> <view class="detail">
<view class="author"> <view class="author">
<text class="author-name">{{ author.name }}</text> <text class="author-name">博主{{ author.nickname }}</text>
<text class="author-time">发布于{{ { d: result.createTime, f: 'yyyy年MM月dd日 星期w' } | formatTime }}</text> <text class="author-time">
时间{{ { d: result.createTime, f: 'yyyy年MM月dd日 星期w' } | formatTime }}
</text>
</view> </view>
<view class="cover" v-if="result.thumbnail"><image class="cover-img" mode="aspectFill" :src="calcUrl(result.thumbnail)"></image></view> <view class="cover" v-if="result.thumbnail">
<!-- <view class="mt-24"> <image class="cover-img" mode="aspectFill" :src="calcUrl(result.thumbnail)"></image>
<text class="category-tag" v-for="(item, index) in result.tags" :key="index">{{ item.name }}</text> </view>
</view> -->
<view class="count" :class="{ 'no-thumbnail': !result.thumbnail }"> <view class="count" :class="{ 'no-thumbnail': !result.thumbnail }">
<view class="count-item"> <view class="count-item">
<text class="value">{{ result.visits }}</text> <text class="value">{{ result.visits }}</text>
@@ -41,13 +42,34 @@
</view> </view>
<!-- 分类 --> <!-- 分类 -->
<view class="category"> <view class="category">
<view class=""> <view class="category-type">
分类 <text class="text-weight-b">分类</text>
<text class="category-tag" v-for="(item, index) in result.categories" :key="index">{{ item.name }}</text> <text v-if="result.categories.length == 0" class="category-tag is-empty">未选择分类</text>
<block v-else>
<text
class="category-tag"
v-for="(item, index) in result.categories"
:key="index"
@click="fnToCate(item)"
>
{{ item.name }}
</text>
</block>
</view> </view>
<view class="mt-18"> <view class="mt-18 category-type">
标签 <text class="text-weight-b">标签</text>
<text class="category-tag" v-for="(item, index) in result.tags" :key="index">{{ item.name }}</text> <text v-if="result.tags.length == 0" class="category-tag is-empty">未选择标签</text>
<block v-else>
<text
class="category-tag"
:style="{ backgroundColor: item.color }"
v-for="(item, index) in result.tags"
:key="index"
@click="fnToTag(item)"
>
{{ item.name }}
</text>
</block>
</view> </view>
</view> </view>
<!-- 广告区域 --> <!-- 广告区域 -->
@@ -71,14 +93,14 @@
:selectable="true" :selectable="true"
:tag-style="markdownConfig.tagStyle" :tag-style="markdownConfig.tagStyle"
:container-style="markdownConfig.containStyle" :container-style="markdownConfig.containStyle"
:content="result.content" :content="result.content || result.formatContent"
:markdown="true" :markdown="true"
:showLineNumber="true" :showLineNumber="true"
:showLanguageName="true" :showLanguageName="true"
:copyByLongPress="true" :copyByLongPress="true"
/> />
<!-- 广告区域 --> <!-- 广告区域微信/decloud申请 -->
<view v-if="haloAdConfig.articleDetail.use" class="ad-wrap mt-24 mb-24 "> <view v-if="haloAdConfig.articleDetail.use" class="ad-wrap mt-24 mb-24 ">
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
<ad v-if="haloAdConfig.unitId" :unit-id="haloAdConfig.unitId"></ad> <ad v-if="haloAdConfig.unitId" :unit-id="haloAdConfig.unitId"></ad>
@@ -88,15 +110,73 @@
<!-- #endif --> <!-- #endif -->
</view> </view>
<!-- 免责声明todo --> <!-- 广告区域自定义广告位 -->
<view class="ad-card" v-if="haloAdConfig.articleDetail.custom.use">
<text class="ad-card_tip">广告</text>
<image
class="ad-card_cover"
:src="haloAdConfig.articleDetail.custom.cover"
mode="scaleToFill"
></image>
<view class="ad-card_info">
<view class="ad-card_info-title">{{ haloAdConfig.articleDetail.custom.title }}</view>
<view class="ad-card_info-desc">{{ haloAdConfig.articleDetail.custom.content }}</view>
<view
v-if="haloAdConfig.articleDetail.custom.url"
class="ad-card_info-link"
@click="fnToWebview(haloAdConfig.articleDetail.custom)"
>
立即查看
</view>
</view>
</view>
<!-- 版权声明 -->
<view v-if="copyright.use" class="copyright-wrap bg-white mt-24 pa-24 round-4">
<view class="copyright-title text-weight-b">版权声明</view>
<view
class="copyright-content mt-12 grey-lighten-5 text-grey-darken-2 round-4 pt-12 pb-12 pl-24 pr-24 "
>
<view v-if="copyright.author" class="copyright-text text-size-s ">
版权归属{{ copyright.author }}
</view>
<view v-if="copyright.description" class="copyright-text text-size-s mt-12">
版权说明{{ copyright.description }}
</view>
<view v-if="copyright.violation" class="copyright-text text-size-s mt-12 text-red">
侵权处理{{ copyright.violation }}
</view>
</view>
</view>
<!-- 评论展示区域 --> <!-- 评论展示区域 -->
<view class="comment-wrap mt-24 pa-24 round-4"><commentList :postId="result.id" :post="result" @on-comment-detail="fnOnShowCommentDetail"></commentList></view> <view class="comment-wrap bg-white mt-24 pa-24 round-4">
<commentList
:disallowComment="result.disallowComment"
:postId="result.id"
:post="result"
@on-comment-detail="fnOnShowCommentDetail"
@on-loaded="fnOnCommentLoaded"
></commentList>
</view>
</view> </view>
<!-- 弹幕效果 -->
<barrage ref="barrage" :maxTop="240" :type="globalAppSettings.barrage.type"></barrage>
<!-- 返回顶部 --> <!-- 返回顶部 -->
<tm-flotbutton :offset="[16, 80]" icon="icon-angle-up" color="bg-gradient-light-blue-accent" @click="fnToTopPage()"></tm-flotbutton> <tm-flotbutton
<tm-flotbutton :actions="btnOption.actions" actions-pos="left" :show-text="true" color="bg-gradient-orange-accent" @change="fnOnFlotButtonChange"></tm-flotbutton> :offset="[16, 80]"
icon="icon-angle-up"
color="bg-gradient-light-blue-accent"
@click="fnToTopPage()"
></tm-flotbutton>
<tm-flotbutton
:actions="btnOption.actions"
actions-pos="left"
:show-text="true"
color="bg-gradient-orange-accent"
@change="fnOnFlotButtonChange"
></tm-flotbutton>
</block> </block>
<!-- 评论详情 --> <!-- 评论详情 -->
@@ -104,7 +184,13 @@
<view class="pa-24"> <view class="pa-24">
<view class="poup-head pb-24"> <view class="poup-head pb-24">
<view class="poup-title text-align-center text-size-g text-weight-b mb-32">评论详情</view> <view class="poup-title text-align-center text-size-g text-weight-b mb-32">评论详情</view>
<comment-item :useContentBg="false" :useActions="false" :isChild="false" :comment="commentDetail.comment" :postId="result.id"></comment-item> <comment-item
:useContentBg="false"
:useActions="false"
:isChild="false"
:comment="commentDetail.comment"
:postId="result.id"
></comment-item>
</view> </view>
<scroll-view :scroll-y="true" class="poup-body"> <scroll-view :scroll-y="true" class="poup-body">
@@ -115,7 +201,14 @@
</view> </view>
<view v-else-if="commentDetail.loading == 'error'" class="error"> <view v-else-if="commentDetail.loading == 'error'" class="error">
<tm-empty icon="icon-wind-cry" label="加载失败"> <tm-empty icon="icon-wind-cry" label="加载失败">
<tm-button theme="bg-gradient-light-blue-accent" size="m" v-if="!disallowComment" @click="fnGetChildComments()">刷新试试</tm-button> <tm-button
theme="bg-gradient-light-blue-accent"
size="m"
v-if="!disallowComment"
@click="fnGetChildComments()"
>
刷新试试
</tm-button>
</tm-empty> </tm-empty>
</view> </view>
</view> </view>
@@ -151,9 +244,15 @@
<block v-if="poster.showCanvas"> <block v-if="poster.showCanvas">
<r-canvas ref="rCanvas"></r-canvas> <r-canvas ref="rCanvas"></r-canvas>
<view class="poster-save ma-24 mt-0 pt-20 flex flex-center"> <view class="poster-save ma-24 mt-0 pt-20 flex flex-center">
<tm-button theme="bg-gradient-light-blue-accent" size="m" @click="fnSavePoster()">保存到相册</tm-button> <tm-button theme="bg-gradient-light-blue-accent" size="m" @click="fnSavePoster()">
<tm-button v-if="false" theme="bg-gradient-orange-accent" size="m" @click="fnShareTo()">分享给好友</tm-button> 保存到相册
<tm-button theme="bg-gradient-blue-grey-accent" size="m" @click="fnOnPosterClose()"> </tm-button> </tm-button>
<tm-button v-if="false" theme="bg-gradient-orange-accent" size="m" @click="fnShareTo()">
分享给好友
</tm-button>
<tm-button theme="bg-gradient-blue-grey-accent" size="m" @click="fnOnPosterClose()">
</tm-button>
</view> </view>
</block> </block>
</view> </view>
@@ -175,6 +274,9 @@ import commentList from '@/components/comment-list/comment-list.vue';
import commentItem from '@/components/comment-item/comment-item.vue'; import commentItem from '@/components/comment-item/comment-item.vue';
import rCanvas from '@/components/r-canvas/r-canvas.vue'; import rCanvas from '@/components/r-canvas/r-canvas.vue';
import barrage from '@/components/barrage/barrage.vue';
import { haloWxShareMixin } from '@/common/mixins/wxshare.mixin.js';
export default { export default {
components: { components: {
tmSkeleton, tmSkeleton,
@@ -185,8 +287,10 @@ export default {
mpHtml, mpHtml,
commentList, commentList,
commentItem, commentItem,
rCanvas rCanvas,
barrage
}, },
mixins: [haloWxShareMixin],
data() { data() {
return { return {
loading: 'loading', loading: 'loading',
@@ -228,6 +332,9 @@ export default {
}; };
}, },
computed: { computed: {
copyright() {
return getApp().globalData.copyright;
},
calcUrl() { calcUrl() {
return url => { return url => {
if (this.$utils.checkIsUrl(url)) { if (this.$utils.checkIsUrl(url)) {
@@ -238,7 +345,7 @@ export default {
}, },
// 获取博主信息 // 获取博主信息
bloggerInfo() { bloggerInfo() {
let blogger = this.$tm.vx.getters().blogger.getBlogger; let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true); blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger; return blogger;
} }
@@ -265,7 +372,14 @@ export default {
this.result = res.data; this.result = res.data;
this.fnSetPageTitle('文章详情'); this.fnSetPageTitle('文章详情');
this.loading = 'success'; this.loading = 'success';
this.fnSetWxShareInfo(); this.fnSetWxShareConfig({
title: this.result.title,
desc: this.result.summary,
imageUrl: this.$utils.checkThumbnailUrl(this.result.thumbnail),
path: `/pagesA/article-detail/article-detail?articleId=${this.queryParams.articleId}`,
copyLink: this.$haloConfig.apiUrl,
query: {}
});
}) })
.catch(err => { .catch(err => {
this.loading = 'error'; this.loading = 'error';
@@ -275,19 +389,7 @@ export default {
uni.stopPullDownRefresh(); uni.stopPullDownRefresh();
}); });
}, },
fnSetWxShareInfo() {
// #ifdef MP-WEIXIN
uni.$tm.vx.commit('setWxShare', {
title: this.result.title,
desc: this.result.summary,
// imageUrl: this.poster.res.tempFilePath,
imageUrl: this.$utils.checkThumbnailUrl(this.result.thumbnail),
path: `/pagesA/article-detail/article-detail?articleId=${this.queryParams.articleId}`,
copyLink: this.$haloConfig.apiUrl,
query: {}
});
// #endif
},
// 浮动按钮点击 // 浮动按钮点击
fnOnFlotButtonChange(index) { fnOnFlotButtonChange(index) {
switch (index) { switch (index) {
@@ -304,6 +406,9 @@ export default {
}, },
fnToComment() { fnToComment() {
if (this.result.disallowComment) {
return uni.$tm.toast('文章已开启禁止评论!');
}
this.$Router.push({ this.$Router.push({
path: '/pagesA/comment/comment', path: '/pagesA/comment/comment',
query: { query: {
@@ -361,6 +466,8 @@ export default {
fnCreatePoster(callback) { fnCreatePoster(callback) {
this.$nextTick(async () => { this.$nextTick(async () => {
const systemInfo = await uni.getSystemInfoSync(); const systemInfo = await uni.getSystemInfoSync();
const _bloggerAvatar = this.$utils.checkAvatarUrl(this.bloggerInfo.avatar, true);
const _articleCover = this.$utils.checkThumbnailUrl(this.result.thumbnail, true);
// 初始化 // 初始化
await this.$refs.rCanvas.init({ await this.$refs.rCanvas.init({
canvas_id: 'rCanvas', canvas_id: 'rCanvas',
@@ -385,11 +492,10 @@ export default {
icon: 'none' icon: 'none'
}); });
}); });
console.log(this.$utils.checkAvatarUrl(this.bloggerInfo.avatar, true));
// 博主信息 // 博主信息
await this.$refs.rCanvas await this.$refs.rCanvas
.drawImage({ .drawImage({
url: this.$utils.checkAvatarUrl(this.bloggerInfo.avatar, true), url: _bloggerAvatar,
x: 12, x: 12,
y: 12, y: 12,
w: 48, w: 48,
@@ -436,7 +542,7 @@ export default {
// 文章封面图 // 文章封面图
await this.$refs.rCanvas await this.$refs.rCanvas
.drawImage({ .drawImage({
url: this.$utils.checkThumbnailUrl(this.result.thumbnail), url: _articleCover,
x: 12, x: 12,
y: 75, y: 75,
w: 312, w: 312,
@@ -598,6 +704,70 @@ export default {
.catch(err => { .catch(err => {
this.commentDetail.loading = 'error'; this.commentDetail.loading = 'error';
}); });
},
fnToCate(category) {
uni.navigateTo({
url: `/pagesA/category-detail/category-detail?slug=${category.slug}&name=${category.name}`
});
},
fnToTag(tag) {
uni.navigateTo({
url: `/pagesA/tag-detail/tag-detail?id=${tag.id}&slug=${tag.slug}&name=${tag.name}`
});
},
async fnOnCommentLoaded(data) {
const _list = [];
const _handleData = list => {
return new Promise(resolve => {
if (list.length == 0) {
resolve();
} else {
list.forEach(item => {
_list.push(item);
if (item.children && item.children.length != 0) {
_handleData(item.children);
}
resolve();
});
}
});
};
await _handleData(data);
if (this.globalAppSettings.barrage.use) {
this.$nextTick(() => {
if (_list.length != 0) {
_handleAddBarrage();
}
});
}
const _handleRemove = () => {
this.$refs['barrage'].remove({
duration: 5000, // 延迟关闭的时间
speed: 600 // 弹幕消失的速度
});
};
let index = 0;
const _handleAddBarrage = () => {
setTimeout(() => {
this.$refs['barrage'].add(_list[index]);
index += 1;
if (index < _list.length - 1) {
_handleAddBarrage();
} else {
_handleRemove();
}
}, 1000);
};
},
fnToWebview(data) {
uni.navigateTo({
url:
'/pagesC/website/website?data=' +
JSON.stringify({
title: data.title,
url: data.url
})
});
} }
} }
}; };
@@ -646,7 +816,7 @@ export default {
&-name { &-name {
} }
&-time { &-time {
margin-left: 12rpx; margin-left: 36rpx;
} }
} }
@@ -711,12 +881,18 @@ export default {
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03); box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03);
// border: 2rpx solid #f8f8f8; // border: 2rpx solid #f8f8f8;
font-size: 28rpx; font-size: 28rpx;
&-type {
line-height: 55rpx;
}
&-tag { &-tag {
background-color: #5bb8fa; background-color: #5bb8fa;
color: #fff; color: #fff;
padding: 6rpx 12rpx; padding: 6rpx 12rpx;
border-radius: 6rpx; border-radius: 6rpx;
font-size: 24rpx; font-size: 24rpx;
&.is-empty {
background-color: #607d8b;
}
} }
} }
.category-tag + .category-tag { .category-tag + .category-tag {
@@ -725,11 +901,27 @@ export default {
.content { .content {
margin-top: 24rpx; margin-top: 24rpx;
} }
.ad-wrap { .evan-markdown,
.ad-wrap,
.copyright-wrap,
.comment-wrap {
box-shadow: 0rpx 0rpx 24rpx rgba(0, 0, 0, 0.03); box-shadow: 0rpx 0rpx 24rpx rgba(0, 0, 0, 0.03);
} }
.comment-wrap { .copyright-title {
background-color: #fff; position: relative;
box-sizing: border-box;
padding-left: 24rpx;
font-size: 30rpx;
&:before {
content: '';
position: absolute;
left: 0rpx;
top: 8rpx;
width: 8rpx;
height: 26rpx;
background-color: rgb(3, 174, 252);
border-radius: 6rpx;
}
} }
.poup-head { .poup-head {
border-bottom: 2rpx solid #f5f5f5; border-bottom: 2rpx solid #f5f5f5;
@@ -754,6 +946,9 @@ export default {
min-height: 60vh; min-height: 60vh;
overflow: hidden; overflow: hidden;
} }
.copyright-text {
line-height: 1.7;
}
.poster-loading { .poster-loading {
width: 100%; width: 100%;
position: absolute; position: absolute;
+2 -2
View File
@@ -16,7 +16,7 @@
<view class="load-text">{{ loadMoreText }}</view> <view class="load-text">{{ loadMoreText }}</view>
</block> </block>
<tm-flotbutton @click="fnToTopPage" size="m" icon="icon-angle-up"></tm-flotbutton> <tm-flotbutton @click="fnToTopPage" color="light-blue" size="m" icon="icon-angle-up"></tm-flotbutton>
</block> </block>
</view> </view>
</template> </template>
@@ -87,7 +87,7 @@ export default {
this.$httpApi this.$httpApi
.getCategoryPostList(this.slug, this.queryParams) .getCategoryPostList(this.slug, this.queryParams)
.then(res => { .then(res => {
this.fnSetPageTitle(this.pageTitle + ` (共${res.data.total}篇)`); this.fnSetPageTitle(`分类:${this.pageTitle} (共${res.data.total}篇)`);
this.result = res.data; this.result = res.data;
if (this.isLoadMore) { if (this.isLoadMore) {
this.dataList = this.dataList.concat(res.data.content); this.dataList = this.dataList.concat(res.data.content);
+1 -1
View File
@@ -67,7 +67,7 @@ export default {
computed: { computed: {
// 评论游客信息 // 评论游客信息
wxLoginVisitorUser() { wxLoginVisitorUser() {
return uni.$tm.vx.getters().user.getWxLoginInfo; return uni.$tm.vx.getters().getWxLoginInfo;
} }
}, },
onLoad() { onLoad() {
+5 -21
View File
@@ -2,12 +2,9 @@
<view class="app-page flex flex-col felx-center bg-white"> <view class="app-page flex flex-col felx-center bg-white">
<!-- 信息 --> <!-- 信息 -->
<view class="profile flex flex-col flex-center pa-36"> <view class="profile flex flex-col flex-center pa-36">
<view class="avatar"> <view class="avatar"><image class="avatar-img" :src="bloggerInfo.avatar" mode="aspectFill"></image></view>
<text v-if="false" class="icon flex flex-center"><text class="iconfont icon-check text-size-s"></text></text>
<image class="avatar-img" :src="bloggerInfo.avatar" mode="aspectFill"></image>
</view>
<view class="nickname mt-24 text-weight-b text-size-g">{{ bloggerInfo.nickname }}</view> <view class="nickname mt-24 text-weight-b text-size-g">{{ bloggerInfo.nickname }}</view>
<view class="desc mt-24 text-size-m text-grey-darken-3">{{ bloggerInfo.description }}</view> <view class="desc mt-24 text-size-m text-grey-darken-3">{{ bloggerInfo.description || '这个博主很懒,竟然没写介绍~' }}</view>
<!-- 联系图标 --> <!-- 联系图标 -->
<view class="mt-24 contact-icons"> <view class="mt-24 contact-icons">
<!-- 放全部似乎显得有点拥挤 --> <!-- 放全部似乎显得有点拥挤 -->
@@ -19,7 +16,7 @@
<text class="ml-12 halocoloricon halocoloricon-gitee"></text> <text class="ml-12 halocoloricon halocoloricon-gitee"></text>
<text class="ml-12 halocoloricon halocoloricon-ic_email_round"></text> <text class="ml-12 halocoloricon halocoloricon-ic_email_round"></text>
</view> </view>
<view class="mt-24 "> <view v-if="false" class="mt-24 ">
<tm-button theme="bg-gradient-light-blue-accent" size="m" openType="contact">在线客服联系</tm-button> <tm-button theme="bg-gradient-light-blue-accent" size="m" openType="contact">在线客服联系</tm-button>
<tm-button theme="bg-gradient-orange-accent" size="m" @click="fnOnToWeb">访问PC端博客</tm-button> <tm-button theme="bg-gradient-orange-accent" size="m" @click="fnOnToWeb">访问PC端博客</tm-button>
</view> </view>
@@ -123,13 +120,13 @@ export default {
computed: { computed: {
// 获取博主信息 // 获取博主信息
bloggerInfo() { bloggerInfo() {
let blogger = this.$tm.vx.getters().blogger.getBlogger; let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true); blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger; return blogger;
} }
}, },
onLoad() { onLoad() {
this.fnSetPageTitle(''); this.fnSetPageTitle('联系博主');
}, },
created() { created() {
this.fnGetData(); this.fnGetData();
@@ -185,19 +182,6 @@ export default {
border: 6rpx solid #fff; border: 6rpx solid #fff;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.07); box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.07);
overflow: hidden; overflow: hidden;
.icon {
width: 42rpx;
height: 42rpx;
position: absolute;
right: 6rpx;
bottom: 0rpx;
border-radius: 50%;
color: #fff;
box-sizing: border-box;
background-color: #03b0fd;
border: 4rpx solid #fff;
z-index: 2;
}
&-img { &-img {
width: 100%; width: 100%;
height: 100%; height: 100%;
+1 -1
View File
@@ -27,7 +27,7 @@
export default { export default {
computed: { computed: {
bloggerInfo() { bloggerInfo() {
return this.$tm.vx.getters().blogger.getBlogger; return this.$tm.vx.getters().getBlogger;
} }
} }
}; };
+12 -5
View File
@@ -6,10 +6,10 @@
<tm-skeleton model="listAvatr"></tm-skeleton> <tm-skeleton model="listAvatr"></tm-skeleton>
</view> </view>
<!-- 内容区域 --> <!-- 内容区域 -->
<view v-else class="app-page-content bg-white pa-24"> <view v-else class="app-page-content pa-24" :class="{ 'bg-white': dataList.length !== 0 }">
<view v-if="dataList.length == 0" class="content-empty flex flex-center"> <view v-if="dataList.length == 0" class="content-empty flex flex-center">
<!-- 空布局 --> <!-- 空布局 -->
<tm-empty icon="icon-shiliangzhinengduixiang-" label="该分类下暂无数据"></tm-empty> <tm-empty icon="icon-shiliangzhinengduixiang-" label="啊偶,博主还没有留言~"></tm-empty>
</view> </view>
<block v-else> <block v-else>
<block v-for="(item, index) in dataList" :key="index"> <block v-for="(item, index) in dataList" :key="index">
@@ -28,9 +28,9 @@
</tm-translate> </tm-translate>
</block> </block>
<tm-flotbutton :offset="[16, 80]" @click="fnToTopPage" size="m" color="light-blue" icon="icon-angle-up"></tm-flotbutton> <tm-flotbutton :offset="[16, 80]" @click="fnToTopPage" size="m" color="light-blue" icon="icon-angle-up"></tm-flotbutton>
<tm-flotbutton actions-pos="left" :show-text="true" color="bg-gradient-orange-accent" @click="fnToComment(null)"></tm-flotbutton>
<view class="load-text">{{ loadMoreText }}</view> <view class="load-text">{{ loadMoreText }}</view>
</block> </block>
<tm-flotbutton actions-pos="left" :show-text="true" color="bg-gradient-orange-accent" @click="fnToComment(null)"></tm-flotbutton>
</view> </view>
<!-- 评论详情 --> <!-- 评论详情 -->
@@ -77,7 +77,7 @@
</template> </template>
<script> <script>
import AppKeys from '@/config//keys.js'; import AppKeys from '@/config/keys.js';
import SheetConfig from '@/config/sheets.config.js'; import SheetConfig from '@/config/sheets.config.js';
import tmSkeleton from '@/tm-vuetify/components/tm-skeleton/tm-skeleton.vue'; import tmSkeleton from '@/tm-vuetify/components/tm-skeleton/tm-skeleton.vue';
@@ -164,6 +164,7 @@ export default {
.then(res => { .then(res => {
if (res.status == 200) { if (res.status == 200) {
this.loading = 'success'; this.loading = 'success';
// return;
this.loadMoreText = res.data.hasNext ? '上拉加载更多' : '呜呜,没有更多数据啦~'; this.loadMoreText = res.data.hasNext ? '上拉加载更多' : '呜呜,没有更多数据啦~';
// 处理数据 // 处理数据
this.result = res.data; this.result = res.data;
@@ -252,12 +253,18 @@ export default {
width: 100vw; width: 100vw;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: #fafafd;
} }
.app-page-content { .app-page-content {
box-sizing: border-box; box-sizing: border-box;
box-shadow: 0rpx 0rpx 24rpx rgba(0, 0, 0, 0.05); // box-shadow: 0rpx 0rpx 24rpx rgba(0, 0, 0, 0.05);
}
.content-empty {
width: 100%;
height: 60vh;
} }
.loading-wrap { .loading-wrap {
box-sizing: border-box;
padding: 24rpx; padding: 24rpx;
} }
</style> </style>
+377
View File
@@ -0,0 +1,377 @@
<template>
<view class="app-page">
<view v-if="loading != 'success'" class="loading-wrap">
<view v-if="loading == 'loading'" class="loading">
<view class="loading-icon flex flex-center"><text class="e-loading-icon iconfont icon-loading"></text></view>
<view class="loadig-text ">相册正在努力加载中啦~</view>
</view>
<tm-empty v-else icon="icon-shiliangzhinengduixiang-" color="red" label="啊偶,加载失败了呢~">
<tm-button theme="red" :shadow="0" size="m" @click="fnRefresh()">刷新试试</tm-button>
</tm-empty>
</view>
<!-- 内容区域 -->
<view v-else class="app-page-content">
<view v-if="dataList.length == 0" color="light-blue" class="content-empty flex flex-center">
<tm-empty icon="icon-shiliangzhinengduixiang-" label="相册暂时还没有数据~">
<tm-button :shadow="0" size="m" theme="light-blue" @click="fnRefresh()">刷新试试</tm-button>
</tm-empty>
</view>
<block v-else>
<swiper
class="swiper-album"
:current="swiperIndex"
:acceleration="true"
:circular="true"
:vertical="false"
:indicator-dots="false"
:autoplay="false"
@change="fnOnChange"
>
<block v-for="(item, index) in dataList" :key="index">
<swiper-item class="swiper-album-item">
<view class="scroll-wrap">
<view class="card">
<cache-image
class="card-image"
width="100%"
height="46vh"
radius="12rpx"
:url="item.image"
:fileMd5="item.image"
mode="aspectFill"
@on-click="fnOnPreview(item)"
></cache-image>
<view v-if="item.description" class="card-desc">{{ item.description }}</view>
<view v-else class="card-desc is-empty flex flex-col">
<view class="text-grey-darken-1">该照片没有记录任何信息</view>
<view class="text-size-m mt-24 text-grey-darken-1">记录一下拍照的瞬间会更精彩哟</view>
</view>
</view>
</view>
</swiper-item>
</block>
</swiper>
<view class="tabbar">
<view class="pre" @click="fnChange(false)">
<text class="icon"><text class="iconfont icon-arrow-left"></text></text>
<text class="text">上一张</text>
</view>
<view class="refresh" @click="fnRefresh()">
<text class="refresh-text">点击</text>
<text class="refresh-heart iconfont icon-diagnose"></text>
<text class="refresh-text">刷新</text>
</view>
<view class="next" @click="fnChange(true)">
<text class="text">下一张</text>
<text class="icon"><text class="iconfont icon-arrow-right"></text></text>
</view>
</view>
</block>
</view>
</view>
</template>
<script>
import LoveConfig from '@/config/love.config.js';
import throttle from '@/utils/throttle.js';
import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
import tmFlotbutton from '@/tm-vuetify/components/tm-flotbutton/tm-flotbutton.vue';
import tmTranslate from '@/tm-vuetify/components/tm-translate/tm-translate.vue';
import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
export default {
components: {
tmButton,
tmFlotbutton,
tmTranslate,
tmEmpty
},
data() {
return {
loading: 'loading',
loveConfig: LoveConfig,
queryParams: {
size: 99,
page: 0,
sort: 'takeTime',
team: LoveConfig.albumKeyName
},
result: {},
dataList: [],
cache: {
dataList: [],
total: 0
},
swiperIndex: 0,
tabbar: {
list: []
}
};
},
onLoad() {
this.fnSetPageTitle('恋爱相册');
},
created() {
this.fnGetData();
},
onPullDownRefresh() {
this.fnRefresh();
},
methods: {
fnRefresh() {
this.queryParams.page = 0;
this.fnGetData();
},
fnGetData() {
this.loading = 'loading';
this.$httpApi
.getPhotoListByPage(this.queryParams)
.then(res => {
if (res.status == 200) {
this.loading = 'success';
if (res.data.content.length != 0) {
const _list = res.data.content.map((item, index) => {
item['image'] = this.$utils.checkImageUrl(item.thumbnail);
item['takeTime'] = this.$tm.dayjs(item['takeTime']).format('DD/MM/YYYY');
return item;
});
this.dataList = _list;
this.swiperIndex = 0;
}
} else {
this.loading = 'error';
uni.$tm.toast('加载失败,请下拉刷新重试!');
}
})
.catch(err => {
console.error(err);
this.loading = 'error';
uni.$tm.toast('加载失败,请下拉刷新重试!');
})
.finally(() => {
setTimeout(() => {
uni.stopPullDownRefresh();
}, 200);
});
},
// 缓存数据
fnCacheDataList(dataList) {
if (this.queryParams.page == 0) {
this.cache.dataList = dataList;
} else {
this.cache.dataList = [...this.cache.dataList, ...dataList];
}
},
fnOnPreview(item) {
uni.previewImage({
current: item.image,
urls: this.dataList.map(x => x.image)
});
},
fnOnChange(e) {
this.swiperIndex = e.detail.current;
},
fnChange(isNext) {
throttle(() => {
if (isNext) {
if (this.swiperIndex == this.dataList.length - 1) {
this.swiperIndex = 0;
} else {
this.swiperIndex += 1;
}
} else {
if (this.swiperIndex == 0) {
this.swiperIndex = this.dataList.length - 1;
} else {
this.swiperIndex -= 1;
}
}
});
}
}
};
</script>
<style lang="scss" scoped>
.app-page {
width: 100vw;
min-height: 100vh;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 24rpx 0;
padding-bottom: 144rpx;
background: linear-gradient(
-135deg,
rgba(247, 149, 51, 0.1),
rgba(243, 112, 85, 0.1) 15%,
rgba(239, 78, 123, 0.1) 30%,
rgba(161, 102, 171, 0.1) 44%,
rgba(80, 115, 184, 0.1) 58%,
rgba(16, 152, 173, 0.1) 72%,
rgba(7, 179, 155, 0.1) 86%,
rgba(109, 186, 130, 0.1)
);
}
.app-page-content {
}
.loading-wrap {
width: 100vw;
height: 60vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 36rpx;
::v-deep {
.tm-icons {
margin-right: -20rpx;
}
}
}
.e-loading-icon {
font-size: 120rpx;
// color: #f88ca2;
color: #56bbf9;
}
.loadig-text {
margin-top: 28rpx;
font-size: 28rpx;
// color: #f88ca2;
color: #56bbf9;
}
.content-empty {
width: 100%;
height: 60vh;
}
.swiper-album {
width: 100vw;
height: calc(100vh - 24rpx - 144rpx);
}
.swiper-album-item {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 36rpx;
/* #ifdef H5 */
padding-bottom: 110rpx;
/* #endif */
/* #ifndef H5 */
padding-bottom: 60rpx;
/* #endif */
}
.scroll-wrap {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 36rpx;
background-color: #ffffff;
border-radius: 12rpx;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03);
}
.card {
display: flex;
flex-direction: column;
width: 100%;
// height: 65vh;
height: 100%;
max-height: 100%;
border-radius: 12rpx;
background-color: #ffffff;
box-sizing: border-box;
// box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03);
overflow: hidden;
overflow-y: auto;
::v-deep {
.cache-image {
height: initial !important;
}
}
&-image {
width: 100%;
height: initial !important;
border-radius: 12rpx;
}
&-desc {
margin-top: 24rpx;
line-height: 1.6;
font-size: 30rpx;
color: rgba(26, 26, 26, 0.9);
&.is-empty {
display: flex;
align-items: center;
justify-content: center;
flex-grow: 1;
font-size: 32rpx;
}
}
}
.tabbar {
width: 90vw;
position: fixed;
left: 50%;
bottom: 40rpx;
transform: translateX(-50%);
border-radius: 25rpx;
box-sizing: border-box;
padding: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
// background-color: rgba(0, 0, 0, 0.5);
background-color: #ffffff;
color: #333;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.05);
.refresh {
animation: refreshAni 6s ease-in-out infinite;
color: #56bbf9;
&-heart {
font-size: 42rpx;
color: inherit;
margin: 0 6rpx;
}
&-text {
font-size: 24rpx;
}
}
.pre {
color: #56bbf9;
transition: transform 0.1s ease-in-out;
&:hover {
transform: scale(1.05);
}
.text {
padding-left: 12rpx;
}
}
.next {
color: #f88ca2;
transition: transform 0.1s ease-in-out;
&:hover {
transform: scale(1.03);
}
.text {
padding-right: 12rpx;
}
}
}
@keyframes refreshAni {
0% {
color: #f88ca2;
}
50% {
color: #56bbf9;
}
100% {
color: #f88ca2;
}
}
</style>
+92
View File
@@ -0,0 +1,92 @@
<template>
<view class="app-page">
<view class="page-title">我们的故事</view>
<view class="html-typed" v-html="html">内容渲染</view>
<scroll-btn bottom="160rpx" :scrollTop.sync="scrollTop"></scroll-btn>
</view>
</template>
<script>
import LoveConfig from '@/config/love.config.js';
import ScrollBtn from '@/components/scroll-btn/scroll-btn.vue';
export default {
components: { ScrollBtn },
data() {
return {
scrollTop: 0,
html: '',
timer: null
};
},
created() {
this.fnInit();
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
onBackPress() {
clearTimeout(this.timer);
},
methods: {
fnInit() {
clearTimeout(this.timer);
const _html = LoveConfig.journey;
let _index = 0;
const _typing = () => {
this.timer = setTimeout(() => {
if (_index >= _html.length) {
clearTimeout(this.timer);
} else {
this.html += _html.substring(_index, _index + 1);
_index += 1;
_typing();
}
}, 100);
};
_typing();
}
}
};
</script>
<style scoped lang="scss">
.app-page {
width: 100vw;
min-height: 100vh;
box-sizing: border-box;
padding: 36rpx;
/* #ifdef APP-PLUS */
padding-top: 100rpx;
/* #endif */
/* #ifdef H5 */
padding-top: 80rpx;
/* #endif */
/* #ifdef MP-WEIXIN */
padding-top: 120rpx;
/* #endif */
background: linear-gradient(
-45deg,
rgba(247, 149, 51, 0.1),
rgba(243, 112, 85, 0.1) 15%,
rgba(239, 78, 123, 0.1) 30%,
rgba(161, 102, 171, 0.1) 44%,
rgba(80, 115, 184, 0.1) 58%,
rgba(16, 152, 173, 0.1) 72%,
rgba(7, 179, 155, 0.1) 86%,
rgba(109, 186, 130, 0.1)
);
color: rgba(26, 26, 26, 1);
}
.page-title {
font-size: 42rpx;
font-weight: bold;
text-align: center;
text-shadow: 0rpx 4rpx 24rpx #bfe9ef;
}
.html-typed {
margin-top: 52rpx;
line-height: 1.8;
font-size: 30rpx;
}
</style>
+421
View File
@@ -0,0 +1,421 @@
<template>
<view class="app-page" @touchstart="fnOnTouchstart" @touchend="fnOnTouchend" @touchcancel="fnOnTouchend">
<view class="love-card" :class="{ ani: isDoAni }">
<view class="head">
<image class="avatar" :src="loveConfig.boy.avatar" mode="scaleToFill"></image>
<view class="love-days">
<view class="tip-text">相恋</view>
<view class="number">
<text class="boy">-</text>
<text class="days">{{ calcLoveDays }}</text>
<text class="girl">-</text>
</view>
<view class="tip-text"></view>
</view>
<image class="avatar" :src="loveConfig.girl.avatar" mode="scaleToFill"></image>
</view>
<view class="foot">
<view class="text" v-if="false">
我们已经相恋
<text class="number">- {{ calcLoveDays }} -</text>
天啦
</view>
看看我们的恋爱清单都完成了哪些吧
</view>
</view>
<view v-if="list.length == 0" class="list empty">
<view class="card">
<image class="empty-image" :src="loveConfig.loveImageUrl" mode="scaleToFill"></image>
<view class="empty-text">暂时还没有恋爱清单快去制定你们的恋爱清单吧~</view>
</view>
</view>
<view v-else class="list">
<block v-for="(item, index) in list" :key="index">
<view class="card" :class="{ ani: isDoAni }" :style="{ '--delay': calcCardDelay(index) }">
<view class="head">
<view class="status">
<view v-if="!item.finish" class="text">进行中</view>
<view v-else class="text finish">已完成</view>
</view>
<view class="title">
<view class="title-name">{{ item.title }}</view>
<view class="title-desc">{{ item.desc }}</view>
</view>
<view class="actions" @click="fnOnItemOpen(item)">
<text class="icon">{{ item.open ? '-' : '+' }}</text>
</view>
</view>
<view v-if="item.open" class="body">
<view class="desc">
<view class="desc-label">开始时间</view>
<view class="desc-value">{{ item.detail.start || '暂无计划' }}</view>
</view>
<view class="desc" v-if="item.detail.desc">
<view class="desc-label">事件描述</view>
<view class="desc-value">{{ item.detail.desc }}</view>
</view>
<view class="desc">
<view class="desc-label">完成时间</view>
<view class="desc-value">{{ item.detail.end || '未开始或正在进行中...' }}</view>
</view>
<view class="desc">
<view class="desc-label">完成打卡</view>
<view class="desc-value">{{ item.detail.moment || '未开始或正在进行中...' }}</view>
</view>
<view class="desc" v-if="item.detail.other">
<view class="desc-label">爱心备注</view>
<view class="desc-value">{{ item.detail.other }}</view>
</view>
</view>
</view>
</block>
</view>
<scroll-btn :scrollTop.sync="scrollTop" @on-status="fnOnScrollStatus"></scroll-btn>
</view>
</template>
<script>
import LoveConfig from '@/config/love.config.js';
import ScrollBtn from '@/components/scroll-btn/scroll-btn.vue';
export default {
components: { ScrollBtn },
data() {
return {
isDoAni: true,
scrollTop: 0,
loveConfig: LoveConfig,
list: []
};
},
computed: {
calcLoveDays() {
const formatStartDate = this.loveConfig.loveStartDate.replace(/-/g, '/');
const start = new Date(formatStartDate),
now = new Date();
const T = now.getTime() - start.getTime();
const i = 24 * 60 * 60 * 1000;
const d = T / i;
const D = Math.floor(d);
return D;
},
calcCardDelay() {
return index => {
return Math.random() * index + 1 + 's';
};
}
},
created() {
this.fnGetList();
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
methods: {
fnGetList() {
if (LoveConfig.loveList.useApi && LoveConfig.loveList.api) {
uni.request({
url: LoveConfig.loveList.api,
header: {
ContentType: 'application/json'
},
method: 'GET',
dataType: 'json',
success: res => {
if (res.statusCode == 200 && res.data.status == 200) {
this.list = res.data.data.map(item => {
item['open'] = false;
return item;
});
} else {
uni.$tm.toast('数据请求失败,请检查接口!');
}
},
fail: err => {
uni.$tm.toast('数据请求失败,请检查接口!');
}
});
} else {
this.list = LoveConfig.loveList.data.map(item => {
item['open'] = false;
return item;
});
}
},
fnOnItemOpen(item) {
item.open = !item.open;
this.$forceUpdate();
},
fnOnScrollStatus(isEnd) {
this.isDoAni = isEnd;
},
fnOnTouchstart() {
this.isDoAni = false;
},
fnOnTouchend() {
this.isDoAni = true;
}
}
};
</script>
<style scoped lang="scss">
.app-page {
width: 100vw;
min-height: 100vh;
box-sizing: border-box;
padding: 36rpx;
/* #ifdef H5 */
padding-top: 60rpx;
/* #endif */
/* #ifndef H5 */
padding-top: 180rpx;
/* #endif */
background: linear-gradient(
135deg,
rgba(247, 149, 51, 0.1),
rgba(243, 112, 85, 0.1) 15%,
rgba(239, 78, 123, 0.1) 30%,
rgba(161, 102, 171, 0.1) 44%,
rgba(80, 115, 184, 0.1) 58%,
rgba(16, 152, 173, 0.1) 72%,
rgba(7, 179, 155, 0.1) 86%,
rgba(109, 186, 130, 0.1)
);
}
.love-card {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
padding: 0 24rpx;
padding-top: 66rpx;
padding-bottom: 52rpx;
border-radius: 50rpx;
border: 4rpx solid rgba(96, 77, 68, 0.9);
border-color: #faf8eb;
background-color: rgba(255, 199, 184, 0.9);
margin-bottom: 52rpx;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.1);
&.ani {
animation: loveCardAni 3s ease-in-out infinite;
}
.head {
display: flex;
.avatar {
width: 150rpx;
height: 150rpx;
box-sizing: border-box;
border-radius: 50%;
border: 6rpx solid rgba(255, 255, 255, 0.7);
&.boy {
border-color: #56bbf9;
}
&.girl {
border-color: #f88ca2;
}
}
.love-days {
margin: 0 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 26rpx;
.tip-text {
color: #333;
}
.number {
font-size: 46rpx;
padding: 12rpx 0;
> .boy {
color: #56bbf9;
margin-right: 12rpx;
}
> .girl {
color: #f88ca2;
margin-left: 12rpx;
}
}
.days {
animation: daysAni 6s ease-in-out infinite;
font-weight: bold;
}
}
}
.foot {
display: none;
margin-top: 36rpx;
font-size: 24rpx;
}
}
@keyframes daysAni {
0% {
color: #f88ca2;
}
50% {
color: #56bbf9;
}
100% {
color: #f88ca2;
}
}
@keyframes loveCardAni {
0% {
transform: scale(1);
}
50% {
transform: scale(1.03);
}
100% {
transform: scale(1);
}
}
.list {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.empty {
height: calc(100vh - 180rpx - 280rpx - 36rpx);
.card {
height: 100%;
padding: 100rpx;
margin-bottom: 0;
text-align: center;
justify-content: center;
color: rgba(96, 77, 68, 0.9);
}
&-image {
width: 300rpx;
height: 300rpx;
}
&-text {
margin-top: 36rpx;
line-height: 50rpx;
}
}
.card {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
padding: 24rpx;
border-radius: 50rpx;
border: 4rpx solid rgba(96, 77, 68, 0.9);
border-color: #fff;
// background-color: #faf8eb;
background-color: #ffffff;
margin-bottom: 36rpx;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.05);
animation-delay: var(--delay);
&.ani {
animation: cardAni 3s ease-in-out infinite;
}
.head {
width: 100%;
display: flex;
align-items: center;
box-sizing: border-box;
.status {
width: 100rpx;
display: flex;
.text {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #ffc6ba;
font-size: 24rpx;
line-height: 100rpx;
text-align: center;
color: #55423b;
&.finish {
background-color: #bfe9ef;
}
}
}
.title {
width: 0;
flex-grow: 1;
box-sizing: border-box;
padding-left: 30rpx;
padding-right: 24rpx;
&-name {
font-weight: bold;
font-size: 30rpx;
color: #333;
}
&-desc {
margin-top: 8rpx;
font-size: 26rpx;
color: #555;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.actions {
width: 50rpx;
.icon {
display: inline-block;
width: 45rpx;
height: 45rpx;
background-color: rgba(96, 77, 68, 0.2);
border-radius: 50%;
text-align: center;
line-height: 45rpx;
font-size: 32rpx;
font-weight: bold;
}
}
}
.body {
margin-top: 24rpx;
width: 100%;
background-color: #ffffff;
// background-color: #faf8eb;
background-color: rgba(96, 77, 68, 0.05);
border-radius: 24rpx;
box-sizing: border-box;
padding: 24rpx;
padding-bottom: 12rpx;
font-size: 26rpx;
}
}
@keyframes cardAni {
0% {
transform: translateY(0rpx);
}
50% {
transform: translateY(-10rpx);
}
100% {
transform: translateY(0rpx);
}
}
.desc {
display: flex;
margin-bottom: 12rpx;
&-label {
color: #333;
width: 140rpx;
// font-weight: bold;
}
&-value {
width: 0;
flex-grow: 1;
line-height: 1.5;
color: #333;
}
}
</style>
+340 -4
View File
@@ -1,22 +1,358 @@
<template> <template>
<view class="app-page bg-white flex flex-center"><text class="text-bg-gradient-red-accent-b">祝有情人👩👨终成眷属</text></view> <view class="app-page bg-white">
<!-- 情侣信息 -->
<view class="lover-wrap" :style="[loveWrapStyle]">
<view class="lover-card">
<view class="boy">
<image class="avatar" :src="loveConfig.boy.avatar" mode="aspectFit"></image>
<view class="name">{{ loveConfig.boy.name }}</view>
</view>
<image class="like" :src="loveConfig.loveImageUrl" mode="scaleToFill"></image>
<view class="girl">
<image class="avatar" :src="loveConfig.girl.avatar" mode="aspectFit"></image>
<view class="name">{{ loveConfig.girl.name }}</view>
</view>
</view>
<image class="wave-image" :src="loveConfig.waveImageUrl" mode="scaleToFill"></image>
</view>
<!-- 恋爱记时 -->
<view class="love-time-wrap">
<view class="title">{{ loveConfig.timeTitle }}</view>
<view class="content">
<text class="text">
<text class="number">{{ loveDayCount.d }}</text>
</text>
<text class="text">
<text class="number">{{ loveDayCount.h }}</text>
小时
</text>
<text class="text">
<text class="number">{{ loveDayCount.m }}</text>
分钟
</text>
<text class="text">
<text class="number">{{ loveDayCount.s }}</text>
</text>
</view>
</view>
<!-- 功能导航 -->
<view class="list-wrap">
<block v-for="(nav, index) in loveConfig.nav" :key="index">
<view v-if="nav.use" class="list-item" @click="fnToPage(nav.key)">
<view class="left"><image class="icon" :src="nav.iconImageUrl" mode="aspectFit"></image></view>
<view class="right">
<view class="name">{{ nav.title }}</view>
<view class="desc">{{ nav.desc }}</view>
</view>
</view>
</block>
</view>
</view>
</template> </template>
<script> <script>
import LoveConfig from '@/config/love.config.js';
export default { export default {
data() { data() {
return {}; return {
loveConfig: LoveConfig,
loveDayTimer: null,
loveDayCount: {
d: 0,
h: 0,
m: 0,
s: 0
}
};
},
computed: {
loveWrapStyle() {
return {
backgroundImage: `url(${this.loveConfig.bgImageUrl})`
};
}
}, },
onLoad() { onLoad() {
this.fnSetPageTitle('恋爱日记'); this.fnSetPageTitle('恋爱日记');
this.fnInitLoveDayCount();
}, },
methods: {} methods: {
fnInitLoveDayCount() {
clearTimeout(this.loveDayTimer);
const _countDownFn = () => {
this.loveDayTimer = setTimeout(_countDownFn, 1000);
const formatStartDate = this.loveConfig.loveStartDate.replace(/-/g, '/');
const start = new Date(formatStartDate),
now = new Date();
const T = now.getTime() - start.getTime();
const i = 24 * 60 * 60 * 1000;
const d = T / i;
const D = Math.floor(d);
const h = (d - D) * 24;
const H = Math.floor(h);
const m = (h - H) * 60;
const M = Math.floor(m);
const s = (m - M) * 60;
const S = Math.floor(s);
this.loveDayCount = {
d: D,
h: H,
m: M,
s: S
};
};
_countDownFn();
},
fnToPage(pageName) {
uni.navigateTo({
url: `/pagesA/love/${pageName}`
});
}
}
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-page { .app-page {
width: 100vw; width: 100vw;
height: 100vh; min-height: 100vh;
background: linear-gradient(
-45deg,
rgba(247, 149, 51, 0.1),
rgba(243, 112, 85, 0.1) 15%,
rgba(239, 78, 123, 0.1) 30%,
rgba(161, 102, 171, 0.1) 44%,
rgba(80, 115, 184, 0.1) 58%,
rgba(16, 152, 173, 0.1) 72%,
rgba(7, 179, 155, 0.1) 86%,
rgba(109, 186, 130, 0.1)
);
}
.lover-wrap {
position: relative;
width: 100vw;
height: 50vh;
display: flex;
align-items: center;
justify-content: center;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
&::before {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
content: '';
background-color: rgba(255, 255, 255, 0.1);
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAKUlEQVQImU3IMREAIAgAwJfNkQCEsH8cijjpMf6vnXlQaIiJFx+omEBfmqIEZLe2jzcAAAAASUVORK5CYII=);
z-index: 0;
backdrop-filter: blur(4rpx);
overflow: hidden;
}
&::after {
content: '';
position: absolute;
left: 0;
bottom: -60rpx;
width: 100vw;
height: 60rpx;
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
.lover-card {
position: absolute;
left: 50%;
top: 58%;
transform: translate(-50%, -50%);
width: 90vw;
display: flex;
align-items: center;
justify-content: space-around;
border-radius: 12rpx;
z-index: 2;
.avatar {
width: 180rpx;
height: 180rpx;
border-radius: 50%;
box-sizing: border-box;
// border: 8rpx solid transparent;
// border: 8rpx solid rgba(255, 255, 255, 0.7) !important;
border: 8rpx solid rgba(255, 255, 255, 1) !important;
}
.name {
font-size: 32rpx;
font-weight: bold;
color: #ffffff;
text-align: center;
letter-spacing: 2rpx;
}
.boy {
color: #3ab8e4;
.avatar {
border-color: rgba(58, 184, 228, 0.7);
}
}
.girl {
color: #f57ab3;
.avatar {
border-color: rgba(245, 122, 179, 0.7);
}
}
.like {
width: 120rpx;
height: 120rpx;
animation: likeani 1s ease-in-out infinite;
}
}
.wave-image {
width: 100%;
height: 120rpx;
position: absolute;
left: 0;
bottom: 0;
mix-blend-mode: screen;
}
}
.love-time-wrap {
margin-top: 80rpx;
width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.title {
font-size: 46rpx;
letter-spacing: 4rpx;
// background-image: linear-gradient(270deg, #ff4500, #ffa500, #ffd700, #90ee90, #00ffff, #1e90ff, #9370db, #ff69b4, #ff4500);
// -webkit-background-clip: text;
// color: #000;
color: #333;
font-size: 42rpx;
font-weight: bold;
// animation: loveTimeTitleAni 80s linear infinite;
}
.content {
margin-top: 24rpx;
display: flex;
align-items: center;
justify-content: center;
.text {
font-size: 28rpx;
}
.number {
margin: 0 8rpx;
font-size: 46rpx;
// color: #ff69b4;
color: #f83856;
font-weight: bold;
}
}
}
.list-wrap {
margin-top: 75rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0 36rpx;
.list-item {
width: 100%;
display: flex;
align-items: center;
justify-content: space-around;
box-sizing: border-box;
padding: 28rpx 32rpx;
background-color: #ffffff;
border-radius: 50rpx;
margin-bottom: 32rpx;
box-shadow: 0rpx 4rpx 24rpx rgba(0, 0, 0, 0.03);
&:nth-child(1) {
animation: listItemAni1 3s ease-in-out infinite;
}
&:nth-child(2) {
animation: listItemAni1 3s ease-in-out infinite;
animation-delay: 1.5s;
}
&:nth-child(3) {
animation: listItemAni1 3s ease-in-out infinite;
animation-delay: 2s;
}
.left {
width: 120rpx;
height: 120rpx;
.icon {
width: 100%;
height: 100%;
}
}
.right {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
padding-left: 40rpx;
.name {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
.desc {
margin-top: 8px;
font-size: 26rpx;
color: #777777;
}
}
}
}
@keyframes likeani {
0% {
transform: scale(1);
}
25% {
transform: scale(1.2);
}
50% {
transform: scale(1.1);
}
75% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
@keyframes loveTimeTitleAni {
to {
background-position: -200rem;
}
}
@keyframes listItemAni1 {
0% {
transform: translateY(0rpx);
}
50% {
transform: translateY(-10rpx);
}
100% {
transform: translateY(0rpx);
}
} }
</style> </style>
+86 -26
View File
@@ -9,8 +9,8 @@
<view class="sheet-content">内容区域</view> <view class="sheet-content">内容区域</view>
</tm-sheet> --> </tm-sheet> -->
<tm-sheet :shadow="6" :padding="[12, 24]" :margin="[24, 24]"> <tm-sheet :shadow="6" :padding="[12, 24]" :margin="[24, 24]">
<view class="py-12 px-24 mx-12 round-3 border-b-1 grey text"> <view class="py-12 px-24 mx-12 round-3 grey text">
<text class="text-size-n text-weight-b ">布局</text> <text class="text-size-n text-weight-b text-grey-darken-3">布局</text>
<text class="text-grey text-size-xs px-10 ml-12">应用以及文章列表布局设置</text> <text class="text-grey text-size-xs px-10 ml-12">应用以及文章列表布局设置</text>
</view> </view>
<view class="sheet-content"> <view class="sheet-content">
@@ -25,9 +25,10 @@
<tm-input <tm-input
name="status" name="status"
required required
title="首页布局" title="首页文章布局"
placeholder="请选择首页布局" placeholder="请选择首页文章布局"
disabled disabled
align="right"
:value="homeLayout.selectLabel" :value="homeLayout.selectLabel"
right-icon="icon-angle-right" right-icon="icon-angle-right"
></tm-input> ></tm-input>
@@ -43,9 +44,10 @@
<tm-input <tm-input
name="status" name="status"
required required
title="卡片样式" title="文章卡片样式"
placeholder="请选择文章卡片样式" placeholder="请选择文章卡片样式"
disabled disabled
align="right"
:value="articleCardStyle.selectLabel" :value="articleCardStyle.selectLabel"
right-icon="icon-angle-right" right-icon="icon-angle-right"
></tm-input> ></tm-input>
@@ -54,7 +56,7 @@
</tm-sheet> </tm-sheet>
<tm-sheet v-if="false" :shadow="24" :padding="[12, 24]" :margin="[24, 24]"> <tm-sheet v-if="false" :shadow="24" :padding="[12, 24]" :margin="[24, 24]">
<view class="py-12 px-24 mx-12 round-3 border-b-1 grey text"> <view class="py-12 px-24 mx-12 round-3 grey text">
<text class="text-size-n text-weight-b ">外观</text> <text class="text-size-n text-weight-b ">外观</text>
<text class="text-grey text-size-xs px-10">设置应用主题色/暗黑模式等</text> <text class="text-grey text-size-xs px-10">设置应用主题色/暗黑模式等</text>
</view> </view>
@@ -65,19 +67,11 @@
</tm-sheet> </tm-sheet>
<tm-sheet :shadow="6" :padding="[12, 24]" :margin="[24, 24]"> <tm-sheet :shadow="6" :padding="[12, 24]" :margin="[24, 24]">
<view class="py-12 px-24 mx-12 round-3 border-b-1 grey text"> <view class="py-12 px-24 mx-12 round-3 grey text">
<text class="text-size-n text-weight-b ">功能</text> <text class="text-size-n text-weight-b text-grey-darken-3">功能</text>
<text class="text-grey text-size-xs px-10 ml-12">一些常用的功能性设置</text> <text class="text-grey text-size-xs px-10 ml-12">一些常用的功能性设置</text>
</view> </view>
<view class="sheet-content"> <view class="sheet-content">
<view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m">显示完整统计</text>
<tm-switch v-model="appSettings.about.showAllCount" color="light-blue" :text="['是', '否']"></tm-switch>
</view>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m ">链接直接打开</text>
<tm-switch v-model="appSettings.contact.isLinkCopy" color="light-blue" :text="['是', '否']"></tm-switch>
</view>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between"> <view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m ">图库瀑布流模式</text> <text class="text-size-m ">图库瀑布流模式</text>
<tm-switch v-model="appSettings.gallery.useWaterfull" color="light-blue" :text="['是', '否']"></tm-switch> <tm-switch v-model="appSettings.gallery.useWaterfull" color="light-blue" :text="['是', '否']"></tm-switch>
@@ -86,6 +80,33 @@
<text class="text-size-m ">友链简洁模式</text> <text class="text-size-m ">友链简洁模式</text>
<tm-switch v-model="appSettings.links.useSimple" color="light-blue" :text="['是', '否']"></tm-switch> <tm-switch v-model="appSettings.links.useSimple" color="light-blue" :text="['是', '否']"></tm-switch>
</view> </view>
<view class="mx-32 mt-24 mb-0 border-b-1 pb-24 flex-between">
<text class="text-size-m">启用评论弹幕</text>
<tm-switch v-model="appSettings.barrage.use" color="light-blue" :text="['是', '否']"></tm-switch>
</view>
<tm-pickers
v-if="appSettings.barrage.use"
title="评论弹幕位置"
btn-color="light-blue"
:default-value.sync="barrage.selectDefault"
rang-key="name"
:list="barrage.list"
@confirm="fnOnBarrageConfirm"
>
<tm-input
name="status"
title="评论弹幕位置"
placeholder="请选择评论弹幕位置"
disabled
align="right"
:value="barrage.selectLabel"
right-icon="icon-angle-right"
></tm-input>
</tm-pickers>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m">是否圆形头像</text>
<tm-switch v-model="appSettings.isAvatarRadius" color="light-blue" :text="['是', '否']"></tm-switch>
</view>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between"> <view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m ">轮播图指示器</text> <text class="text-size-m ">轮播图指示器</text>
<tm-switch v-model="appSettings.banner.useDot" color="light-blue" :text="['是', '否']"></tm-switch> <tm-switch v-model="appSettings.banner.useDot" color="light-blue" :text="['是', '否']"></tm-switch>
@@ -104,6 +125,15 @@
></tm-radio> ></tm-radio>
</tm-groupradio> </tm-groupradio>
</view> </view>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m">显示完整统计</text>
<tm-switch v-model="appSettings.about.showAllCount" color="light-blue" :text="['是', '否']"></tm-switch>
</view>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m ">链接直接打开</text>
<tm-switch v-model="appSettings.contact.isLinkCopy" color="light-blue" :text="['是', '否']"></tm-switch>
</view>
<view class="mx-32 my-24 border-b-1 pb-24 flex-between"> <view class="mx-32 my-24 border-b-1 pb-24 flex-between">
<text class="text-size-m ">显示后台入口</text> <text class="text-size-m ">显示后台入口</text>
<tm-switch v-model="appSettings.about.showAdmin" color="light-blue" :text="['是', '否']"></tm-switch> <tm-switch v-model="appSettings.about.showAdmin" color="light-blue" :text="['是', '否']"></tm-switch>
@@ -148,6 +178,8 @@ export default {
isBlackTheme: false, isBlackTheme: false,
loading: true, loading: true,
appSettings: {}, appSettings: {},
isSaved: true,
firstLoad: true,
homeLayout: { homeLayout: {
list: [{ name: '一行一列', value: 'h_row_col1' }, { name: '一行两列', value: 'h_row_col2' }], list: [{ name: '一行一列', value: 'h_row_col1' }, { name: '一行两列', value: 'h_row_col2' }],
selectDefault: ['一行一列'], selectDefault: ['一行一列'],
@@ -166,18 +198,26 @@ export default {
selectLabel: '左图右文', selectLabel: '左图右文',
selectValue: 'lr_image_text' selectValue: 'lr_image_text'
}, },
dotPositionList: [{ name: '右边', value: 'right', checked: true }, { name: '下边', value: 'bottom', checked: false }] dotPositionList: [{ name: '右边', value: 'right', checked: true }, { name: '下边', value: 'bottom', checked: false }],
barrage: {
list: [{ name: '顶部', value: 'rightToLeft' }, { name: '左下', value: 'leftBottom' }],
selectDefault: ['顶部'],
selectLabel: '顶部',
selectValue: 'rightToLeft'
}
}; };
}, },
computed: {
// 获取设置
_appSettings() {
return uni.$tm.vx.getters().setting.getSettings;
}
},
watch: { watch: {
_appSettings(val) { appSettings: {
this.appSettings = val; deep: true,
handler() {
if (this.firstLoad) {
this.firstLoad = false;
} else {
this.isSaved = false;
}
}
} }
}, },
@@ -185,7 +225,7 @@ export default {
this.fnSetPageTitle('应用设置'); this.fnSetPageTitle('应用设置');
}, },
created() { created() {
this.appSettings = this._appSettings; this.appSettings = Object.assign({}, _DefaultAppSettings, uni.$tm.vx.getters().getSettings);
this.fnHandleFormatSelect(); this.fnHandleFormatSelect();
uni.showLoading({ uni.showLoading({
title: '加载中...', title: '加载中...',
@@ -210,6 +250,11 @@ export default {
this.articleCardStyle.selectDefault = [_articleCardStyle.name]; this.articleCardStyle.selectDefault = [_articleCardStyle.name];
this.articleCardStyle.selectLabel = _articleCardStyle.name; this.articleCardStyle.selectLabel = _articleCardStyle.name;
this.articleCardStyle.selectValue = _articleCardStyle.value; this.articleCardStyle.selectValue = _articleCardStyle.value;
const _barrage = this.fnFindObjInList(this.barrage.list, 'value', this.appSettings.barrage.type);
this.barrage.selectDefault = [_barrage.name];
this.barrage.selectLabel = _barrage.name;
this.barrage.selectValue = _barrage.value;
}, },
// 在集合中找匹配的对象 // 在集合中找匹配的对象
fnFindObjInList(list, key, value) { fnFindObjInList(list, key, value) {
@@ -240,8 +285,17 @@ export default {
this.articleCardStyle.selectValue = _select.value; this.articleCardStyle.selectValue = _select.value;
this.appSettings.layout.cardType = _select.value; this.appSettings.layout.cardType = _select.value;
}, },
// 弹幕设置
fnOnBarrageConfirm(e) {
const _select = e[0].data;
this.barrage.selectDefault = [_select.name];
this.barrage.selectLabel = _select.name;
this.barrage.selectValue = _select.value;
this.appSettings.barrage.type = _select.value;
},
// 保存 // 保存
fnOnSave() { fnOnSave() {
this.isSaved = true;
this.$tm.vx.commit('setting/setSettings', this.appSettings); this.$tm.vx.commit('setting/setSettings', this.appSettings);
uni.$tm.toast('保存成功,部分设置在重启后生效!'); uni.$tm.toast('保存成功,部分设置在重启后生效!');
}, },
@@ -257,12 +311,17 @@ export default {
confirmColor: '#03a9f4' confirmColor: '#03a9f4'
}) })
.then(res => { .then(res => {
this.isSaved = true;
uni.$tm.vx.actions('setting/updateDefaultAppSettings'); uni.$tm.vx.actions('setting/updateDefaultAppSettings');
uni.$tm.toast('系统设置已恢复为默认配置,部分设置在重启后生效!'); uni.$tm.toast('系统设置已恢复为默认配置,部分设置在重启后生效!');
}) })
.catch(err => {}); .catch(err => {});
}, },
fnOnBack() { fnOnBack() {
if (this.isSaved) {
uni.navigateBack();
return;
}
uni.$eShowModal({ uni.$eShowModal({
title: '提示', title: '提示',
content: '您当前可能有未保存的数据,确定返回吗?', content: '您当前可能有未保存的数据,确定返回吗?',
@@ -274,6 +333,7 @@ export default {
}) })
.then(res => { .then(res => {
uni.navigateBack(); uni.navigateBack();
this.isSaved = true;
}) })
.catch(err => {}); .catch(err => {});
} }
+22 -8
View File
@@ -1,6 +1,5 @@
<template> <template>
<view class="app-page bg-gradient-blue-lighten-b"> <view class="app-page bg-gradient-blue-lighten-b" :style="pageStyle">
<!-- 流星-->
<view class="tn-satr"> <view class="tn-satr">
<view class="sky"></view> <view class="sky"></view>
<view class="stars"> <view class="stars">
@@ -41,18 +40,19 @@
</view> </view>
</view> </view>
<!-- 头像用户信息 -->
<view class="user-info__container flex flex-col flex-center"> <view class="user-info__container flex flex-col flex-center">
<image class="user-info__avatar" src="https://blog-oss.925i.cn/blog-files/d500acd35e8b6d24bbfa2dabd2a605e6.png" mode="aspectFill"></image> <image class="user-info__avatar" :src="startInfo.logo" mode="aspectFill"></image>
<view class="user-info__nick-name"> uni-halo </view> <view class="user-info__nick-name"> {{ startInfo.title }} </view>
</view> </view>
<view class="text-align-center text-white" style="padding: 60vh 0 0 0;"> <view class="text-align-center text-white" style="padding: 60vh 0 0 0;">
<view class="" style="font-size: 44rpx;">全新UI准备出发</view> <view class="" style="font-size: 44rpx;" v-if="startInfo.desc1">{{ startInfo.desc1 }}</view>
<view class="mt-30 text-size-m">新触动 新感受 新体验</view> <view class="mt-30 text-size-m" v-if="startInfo.desc2">{{ startInfo.desc2 }}</view>
</view> </view>
<view class="" style="padding: 120rpx 200rpx;z-index: 999;position: relative;"><view class="start-btn" @click="fnStart()">全新出发</view></view> <view class="" style="padding: 120rpx 200rpx;z-index: 999;position: relative;">
<view class="start-btn" @click="fnStart()">{{ startInfo.btnText || '开始体验' }}</view>
</view>
<!-- 波浪效果 --> <!-- 波浪效果 -->
<wave></wave> <wave></wave>
@@ -63,6 +63,20 @@
import wave from '@/components/wave/wave.vue'; import wave from '@/components/wave/wave.vue';
export default { export default {
components: { wave }, components: { wave },
computed: {
startInfo() {
return getApp().globalData.start;
},
pageStyle() {
if (this.startInfo.bg) {
const _bg = this.$utils.checkIsUrl(this.startInfo.bg) ? `url(${this.startInfo.bg})` : this.startInfo.bg;
return {
background: _bg + '!important'
};
}
return {};
}
},
methods: { methods: {
fnStart() { fnStart() {
uni.switchTab({ uni.switchTab({
+144
View File
@@ -0,0 +1,144 @@
<template>
<view class="app-page">
<view v-if="loading != 'success'" class="loading-wrap">
<tm-skeleton model="listAvatr"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton>
<tm-skeleton model="listAvatr"></tm-skeleton>
</view>
<block v-else>
<view class="empty" v-if="dataList.length == 0"><tm-empty icon="icon-shiliangzhinengduixiang-" label="该标签下暂无文章"></tm-empty></view>
<block v-else>
<block v-for="(article, index) in dataList" :key="article.createTime">
<!-- 文章卡片 -->
<tm-translate animation-name="fadeUp" :wait="(index + 1) * 50"><article-card :article="article" @on-click="fnToArticleDetail"></article-card></tm-translate>
</block>
<view class="load-text">{{ loadMoreText }}</view>
</block>
<tm-flotbutton @click="fnToTopPage" color="light-blue" size="m" icon="icon-angle-up"></tm-flotbutton>
</block>
</view>
</template>
<script>
import tmSkeleton from '@/tm-vuetify/components/tm-skeleton/tm-skeleton.vue';
import tmTranslate from '@/tm-vuetify/components/tm-translate/tm-translate.vue';
import tmFlotbutton from '@/tm-vuetify/components/tm-flotbutton/tm-flotbutton.vue';
import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
import ArticleCard from '@/components/article-card/article-card.vue';
export default {
components: {
tmSkeleton,
tmTranslate,
tmFlotbutton,
tmEmpty,
ArticleCard
},
data() {
return {
loading: 'loading',
queryParams: {
size: 10,
page: 0
},
slug: '',
pageTitle: '加载中...',
result: null,
dataList: [],
isLoadMore: false,
loadMoreText: ''
};
},
onLoad(e) {
this.slug = e.slug;
this.pageTitle = e.name;
this.fnGetData();
},
onPullDownRefresh() {
this.isLoadMore = false;
this.queryParams.page = 0;
this.fnGetData();
},
onReachBottom(e) {
if (this.result.hasNext) {
this.queryParams.page += 1;
this.isLoadMore = true;
this.fnGetData();
} else {
uni.showToast({
icon: 'none',
title: '没有更多数据了'
});
}
},
methods: {
fnGetData() {
uni.showLoading({
mask: true,
title: '加载中...'
});
// 设置状态为加载中
if (!this.isLoadMore) {
this.loading = 'loading';
}
this.loadMoreText = '加载中...';
this.$httpApi
.getTagPostsList(this.slug, this.queryParams)
.then(res => {
this.fnSetPageTitle(`标签:${this.pageTitle} (共${res.data.total}篇)`);
this.result = res.data;
if (this.isLoadMore) {
this.dataList = this.dataList.concat(res.data.content);
} else {
this.dataList = res.data.content;
}
this.loadMoreText = res.data.hasNext ? '上拉加载更多' : '呜呜,没有更多数据啦~';
setTimeout(() => {
this.loading = 'success';
}, 500);
})
.catch(err => {
console.error(err);
this.loading = 'error';
this.loadMoreText = '加载失败,请下拉刷新!';
})
.finally(() => {
setTimeout(() => {
uni.hideLoading();
uni.stopPullDownRefresh();
}, 500);
});
},
//跳转文章详情
fnToArticleDetail(article) {
uni.navigateTo({
url: '/pagesA/article-detail/article-detail?articleId=' + article.id,
animationType: 'slide-in-right'
});
}
}
};
</script>
<style lang="scss">
.app-page {
width: 100vw;
min-height: 100vh;
display: flex;
flex-direction: column;
padding: 24rpx 0;
background-color: #fafafd;
}
.loading-wrap {
padding: 0 24rpx;
min-height: 100vh;
}
.empty {
height: 60vh;
display: flex;
align-items: center;
justify-content: center;
}
</style>
+14
View File
@@ -0,0 +1,14 @@
<template>
<view>文章标签页面</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {}
};
</script>
<style></style>
+1 -2
View File
@@ -146,13 +146,12 @@ export default {
}, },
computed: { computed: {
bloggerInfo() { bloggerInfo() {
return this.$tm.vx.getters().blogger.getBlogger; return this.$tm.vx.getters().getBlogger;
} }
}, },
created() { created() {
// this.fnGetData(); // this.fnGetData();
this.fnSetPageTitle('欢迎登录工作台'); this.fnSetPageTitle('欢迎登录工作台');
console.log(this.bloggerInfo);
}, },
onPullDownRefresh() { onPullDownRefresh() {
uni.stopPullDownRefresh(); uni.stopPullDownRefresh();
+7 -5
View File
@@ -151,7 +151,8 @@ export default {
form: { form: {
content: '', content: '',
keepRaw: true, keepRaw: true,
sourceContent: '', originalContent: '',
formatContent: '',
type: 'PUBLIC' type: 'PUBLIC'
}, },
modal: null, modal: null,
@@ -532,16 +533,17 @@ export default {
return uni.$tm.toast('请输入内容!'); return uni.$tm.toast('请输入内容!');
} }
this.form.content = _content; this.form.content = _content;
this.form.sourceContent = this.$refs.markdown.getText(); this.form.formatContent = _content;
this.form.originalContent = this.$refs.markdown.getText();
uni.setStorageSync('posts-content', _content); uni.setStorageSync('posts-content', _content);
uni.setStorageSync('posts-content-source', this.form.sourceContent); uni.setStorageSync('posts-content-source', this.form.originalContent);
if (this.form.id) { if (this.form.id) {
this.$Router.push({ this.$Router.push({
path: '/pagesB/articles/article-setting', path: '/pagesB/articles/article-setting',
query: { postsId: this.form.id, postTitle: this.form.title, isEdit: true, from: 'edit' } query: { postsId: this.form.id, postTitle: this.form.title, isEdit: 1, from: 'edit' }
}); });
} else { } else {
this.$Router.push({ path: '/pagesB/articles/article-setting', query: { postsId: '', postTitle: '', isEdit: false, from: 'edit' } }); this.$Router.push({ path: '/pagesB/articles/article-setting', query: { postsId: '', postTitle: '', isEdit: 0, from: 'edit' } });
} }
return; return;
+26 -23
View File
@@ -60,9 +60,7 @@
<view> <view>
<tm-groupcheckbox name="categoryIds"> <tm-groupcheckbox name="categoryIds">
<tm-checkbox :dense="true" :name="item.id" v-for="(item, index) in categories" :key="index" v-model="item.checked"> <tm-checkbox :dense="true" :name="item.id" v-for="(item, index) in categories" :key="index" v-model="item.checked">
<template v-slot:default="{ checkData }"> <tm-button v-slot:default :flat="true" size="s" :theme="item.checked ? 'light-blue' : 'grey-lighten-4'" :plan="true">{{ item.name }}</tm-button>
<tm-button :flat="true" size="s" :theme="checkData.checked ? 'light-blue' : 'grey-lighten-4'" :plan="true">{{ item.name }}</tm-button>
</template>
</tm-checkbox> </tm-checkbox>
</tm-groupcheckbox> </tm-groupcheckbox>
</view> </view>
@@ -76,9 +74,7 @@
<view> <view>
<tm-groupcheckbox name="tagIds"> <tm-groupcheckbox name="tagIds">
<tm-checkbox :dense="true" :name="item.id" v-for="(item, index) in tags" :key="index" v-model="item.checked"> <tm-checkbox :dense="true" :name="item.id" v-for="(item, index) in tags" :key="index" v-model="item.checked">
<template v-slot:default="{ checkData }"> <tm-button v-slot:default :flat="true" size="s" :theme="item.checked ? 'light-blue' : 'grey-lighten-4'" :plan="true">{{ item.name }}</tm-button>
<tm-button :flat="true" size="s" :theme="checkData.checked ? 'light-blue' : 'grey-lighten-4'" :plan="true">{{ item.name }}</tm-button>
</template>
</tm-checkbox> </tm-checkbox>
</tm-groupcheckbox> </tm-groupcheckbox>
</view> </view>
@@ -151,7 +147,7 @@
<!-- 操作区域 --> <!-- 操作区域 -->
<view class="btn-bar flex flex-center bg-white"> <view class="btn-bar flex flex-center bg-white">
<tm-button theme="blue" :shadow="0" block :height="70" @click="fnOnSave(false, false)">立即保存</tm-button> <tm-button theme="blue" :shadow="0" block :height="70" @click="fnOnSave(false, false)">立即保存</tm-button>
<tm-button theme="light-blue" :shadow="0" block :height="70" @click="fnOnSave(false, true)">保存并返回</tm-button> <tm-button v-if="isEdit" theme="light-blue" :shadow="0" block :height="70" @click="fnOnSave(false, true)">保存并返回</tm-button>
<!-- <block v-if="from == 'edit' && isEdit"> <!-- <block v-if="from == 'edit' && isEdit">
<tm-button <tm-button
v-if="article.status == 'DRAFT' || article.status == 'INTIMATE' || article.status == 'RECYCLE'" v-if="article.status == 'DRAFT' || article.status == 'INTIMATE' || article.status == 'RECYCLE'"
@@ -357,10 +353,21 @@ export default {
list: ['常规', '高级', 'SEO'] list: ['常规', '高级', 'SEO']
}, },
article: { article: {
title: '',
slug: '',
status: '',
content: '', content: '',
keepRaw: true, keepRaw: true,
sourceContent: '', topPriority: 0,
type: 'PUBLIC' summary: '',
password: '',
originalContent: '',
metaDescription: '',
formatContent: '',
editorType: 'MARKDOWN',
createTime: '',
categoryIds: [],
tagIds: []
}, },
articleStatus: { articleStatus: {
list: [{ name: '发布', value: 'PUBLISHED' }, { name: '私有', value: 'INTIMATE' }, { name: '草稿', value: 'DRAFT' }, { name: '回收站', value: 'RECYCLE' }], list: [{ name: '发布', value: 'PUBLISHED' }, { name: '私有', value: 'INTIMATE' }, { name: '草稿', value: 'DRAFT' }, { name: '回收站', value: 'RECYCLE' }],
@@ -393,7 +400,7 @@ export default {
const from = this.$Route.query.from; const from = this.$Route.query.from;
this.postsId = postsId; this.postsId = postsId;
this.postTitle = postTitle || ''; this.postTitle = postTitle || '';
this.isEdit = isEdit; this.isEdit = isEdit == 1 ? true : false;
this.from = from; this.from = from;
this.createTime = uni.$tm.dayjs(new Date().getTime()).format('YYYY-MM-DD HH:mm:ss'); this.createTime = uni.$tm.dayjs(new Date().getTime()).format('YYYY-MM-DD HH:mm:ss');
this.fnGetSettings(); this.fnGetSettings();
@@ -533,7 +540,7 @@ export default {
} }
this.createTime = uni.$tm.dayjs(new Date(this.article.createTime).getTime()).format('YYYY-MM-DD HH:mm:ss'); this.createTime = uni.$tm.dayjs(new Date(this.article.createTime).getTime()).format('YYYY-MM-DD HH:mm:ss');
if (this.postTitle) { if (this.postTitle) {
this.article.title = this.postTitle; this.$set(this.article, 'title', this.postTitle);
} }
} }
const _cateRes = res[1]; const _cateRes = res[1];
@@ -626,7 +633,8 @@ export default {
// 设置文章内容 // 设置文章内容
if (this.from == 'edit') { if (this.from == 'edit') {
this.article.content = uni.getStorageSync('posts-content'); this.article.content = uni.getStorageSync('posts-content');
this.article.sourceContent = uni.getStorageSync('posts-content-source'); this.article.formatContent = uni.getStorageSync('posts-content');
this.article.originalContent = uni.getStorageSync('posts-content-source');
} }
if (this.articleStatus.selectValue != 'INTIMATE') { if (this.articleStatus.selectValue != 'INTIMATE') {
this.article.password = ''; this.article.password = '';
@@ -651,8 +659,7 @@ export default {
delta: 1 delta: 1
}); });
} }
// uni.$emit('refresh-article-list');
uni.$emit('refresh-article-list');
}, 1000); }, 1000);
} else { } else {
uni.$tm.toast('保存失败,请重试!'); uni.$tm.toast('保存失败,请重试!');
@@ -662,13 +669,12 @@ export default {
} }
}) })
.catch(err => { .catch(err => {
uni.$tm.toast('保存失败,请重试!'); uni.$tm.toast(`保存失败,${err.message}!`);
if (isChangeStatus) { if (isChangeStatus) {
this.article.status = this.article.status == 'DRAFT' ? 'PUBLISHED' : 'DRAFT'; this.article.status = this.article.status == 'DRAFT' ? 'PUBLISHED' : 'DRAFT';
} }
}); });
} else { } else {
this.article.content = this.article.sourceContent = uni.getStorageInfoSync();
this.$httpApi.admin this.$httpApi.admin
.createPosts(this.article) .createPosts(this.article)
.then(res => { .then(res => {
@@ -678,12 +684,9 @@ export default {
uni.setStorageSync('posts-content', ''); uni.setStorageSync('posts-content', '');
uni.setStorageSync('posts-content-source', ''); uni.setStorageSync('posts-content-source', '');
setTimeout(() => { setTimeout(() => {
if (isBack) { uni.navigateBack({
uni.navigateBack({ delta: 2
delta: 1 });
});
}
uni.$emit('refresh-article-list'); uni.$emit('refresh-article-list');
}, 1000); }, 1000);
} else { } else {
@@ -691,7 +694,7 @@ export default {
} }
}) })
.catch(err => { .catch(err => {
uni.$tm.toast('发布失败,请重试!'); uni.$tm.toast(`发布失败:${err.message}`);
}); });
} }
}, },
+1 -1
View File
@@ -306,7 +306,7 @@ export default {
}, },
// 设置文章信息 // 设置文章信息
fnOnSetArticle(article, index) { fnOnSetArticle(article, index) {
this.$Router.push({ path: '/pagesB/articles/article-setting', query: { postsId: article.id, postTitle: article.title, isEdit: true, from: 'list' } }); this.$Router.push({ path: '/pagesB/articles/article-setting', query: { postsId: article.id, postTitle: article.title, isEdit: 1, from: 'list' } });
}, },
// 删除文章 // 删除文章
fnOnDelArticle(article, index) { fnOnDelArticle(article, index) {
+1 -2
View File
@@ -185,7 +185,7 @@ export default {
computed: { computed: {
// 获取博主信息 // 获取博主信息
bloggerInfo() { bloggerInfo() {
return this.$tm.vx.getters().blogger.getBlogger; return this.$tm.vx.getters().getBlogger;
} }
}, },
onLoad() { onLoad() {
@@ -193,7 +193,6 @@ export default {
}, },
created() { created() {
this.fnGetData(); this.fnGetData();
console.log(this.bloggerInfo);
}, },
onPullDownRefresh() { onPullDownRefresh() {
this.isLoadMore = false; this.isLoadMore = false;
+1 -1
View File
@@ -177,7 +177,7 @@ export default {
}, },
computed: { computed: {
journalInfo() { journalInfo() {
return uni.$tm.vx.getters().journal.getJournalInfo; return uni.$tm.vx.getters().getJournalInfo;
} }
}, },
onLoad() { onLoad() {
+1 -1
View File
@@ -85,7 +85,7 @@ export default {
}, },
computed: { computed: {
bloggerInfo() { bloggerInfo() {
return this.$tm.vx.getters().blogger.getBlogger; return this.$tm.vx.getters().getBlogger;
}, },
showCopyright() { showCopyright() {
return getApp().globalData.showCopyright; return getApp().globalData.showCopyright;
+1 -1
View File
@@ -97,7 +97,7 @@ export default {
}, },
onLoad() { onLoad() {
this.fnSetPageTitle('我的个人信息'); this.fnSetPageTitle('个人资料');
}, },
created() { created() {
this.fnGetData(); this.fnGetData();
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

+12 -12
View File
@@ -10,6 +10,7 @@
* 修改时间: * 修改时间:
*/ */
import Blogger from '@/api/blogger.js' import Blogger from '@/api/blogger.js'
import HaloConfig from '@/config/halo.config.js';
export default { export default {
state: { state: {
blogger: {}, blogger: {},
@@ -25,18 +26,17 @@ export default {
}, },
}, },
actions: { actions: {
//通过actions提交更新数据 fnGetBlogger(context) {
fnGetBlogger({ if (HaloConfig.author.use) {
commit context.commit("setBlogger", HaloConfig.author);
}) { } else {
Blogger.getBloggerInfo().then((res) => { Blogger.getBloggerInfo().then((res) => {
console.log('获取博主信息成功:'); context.commit("setBlogger", res.data);
console.log(res); }).catch((err) => {
commit("setBlogger", res.data); // 如果失败,则加载默认配置信息
}).catch((err) => { context.commit("setBlogger", HaloConfig.author);
console.log('哈哈,获取博主信息失败啦!'); });
console.log(err); }
});
}, },
}, },
}; };
+2 -6
View File
@@ -24,17 +24,13 @@ export default {
mutations: { mutations: {
setSettings(state, data) { setSettings(state, data) {
state.settings = data; state.settings = data;
console.log('设置:', data);
setAppSettings(data) setAppSettings(data)
}, },
}, },
actions: { actions: {
// 设置默认的数据 // 设置默认的数据
updateDefaultAppSettings({ updateDefaultAppSettings(context) {
commit context.commit('setSettings', JSON.parse(JSON.stringify(_DefaultAppSettings)))
}) {
console.log(_DefaultAppSettings);
commit('setSettings', JSON.parse(JSON.stringify(_DefaultAppSettings)))
}, },
// 检查并设置默认的数据 // 检查并设置默认的数据
checkAndSetDefaultAppSettings(context) { checkAndSetDefaultAppSettings(context) {
+4 -10
View File
@@ -45,14 +45,11 @@ export default {
}, },
}, },
actions: { actions: {
// 登录 adminLogin(context, data) {
adminLogin({
commit
}, data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
User.login(data).then((res) => { User.login(data).then((res) => {
if (res.status == 200) { if (res.status == 200) {
commit("setAdminToken", res.data); context.commit("setAdminToken", res.data);
resolve(res) resolve(res)
} else { } else {
reject(err) reject(err)
@@ -72,11 +69,8 @@ export default {
}) })
} }
}, },
// 登出 adminLogout(context) {
adminLogout({ context.commit("setAdminToken", null);
commit
}) {
commit("setAdminToken", null);
} }
}, },
}; };
+20
View File
@@ -1,3 +1,23 @@
## 2.0.12022-12-8
* 修复 tm-icons在小程序下可能图标与文字无法对齐
* 优化 tm-album性能,修复可能在嵌套组件中,无法计算宽高信息.
* 优化 tm-dragList性能
* 优化 tm-row性能
* 优化 tm-segTabs性能
* 优化 tm-sheet性能
* 优化 tm-slider,tm-sliders性能
* 优化 tm-more性能
* 优化 tm-propress性能,修复可能在嵌套组件中,无法计算宽高信息.
* 优化 tm-dialogtm-poup,动效及样式
* 微调 tm-button
* 美化了tm-calendartm-calendar-view,选中改成圆形,范围改成椭圆形。
* 修复 tm-countdown 完成的时机逻辑有误,修改后默认为完成状态。
* 增强 tm-upload 新增showSort属性,用于上传的文件排序功能。
* 修复 tm-swiper圆角失效。
* 修复 tm-weekbar日期问题。
* 修复 tm-dragGrid 动态修改数据后的判断逻辑问题。
* 优化 tm-grouplist 渲染性能,现在已经是秒渲染。
* 修复$tm.vx.getters()下的属性丢失。
## 2.0.02022-6-7 ## 2.0.02022-6-7
* tm-card修复点击操作按钮时返回的参数非index,而是项目标题。修复动态配置一些属性不生效的问题。 * tm-card修复点击操作按钮时返回的参数非index,而是项目标题。修复动态配置一些属性不生效的问题。
* tm-dropDownMenu 优化,当重置项时,默认将使用你初始的选中数据来进行填充,默认选中。 * tm-dropDownMenu 优化,当重置项时,默认将使用你初始的选中数据来进行填充,默认选中。
+14 -15
View File
@@ -159,7 +159,10 @@
} }
}, },
async mounted() { async mounted() {
await this.setInits(); this.setInits();
},
updated() {
this.setInits();
}, },
methods: { methods: {
//处理数据,以标准化。 //处理数据,以标准化。
@@ -186,20 +189,16 @@
async setInits(){ async setInits(){
this.$nextTick(async function() { this.$nextTick(async function() {
let t = this; let t = this;
this.$tm.sleep(150).then(async function(){ let p = await t.$Querey('.tm-album',t,0).catch(e =>{});
let p = await t.$Querey('.tm-album',t).catch(e =>{}); if (!p[0]) return;
if (!p[0]) return; let grid = t.grid || 1;
let grid = t.grid || 1; let size = (p[0].width+t.gutter)/grid;
let size = (p[0].width+t.gutter)/grid; let gutter = t.gutter*2
let gutter = t.gutter*2 let ratio = 750/uni.upx2px(750);
let ratio = 750/uni.upx2px(750); let blv = size * ratio - gutter;
let blv = size * ratio - gutter; t.alb_body_size = size * ratio;
t.alb_body_size = size * ratio; t.alb_wk_body_size = p[0].width*ratio+t.gutter*2+(grid*2);
t.alb_wk_body_size = p[0].width*ratio+t.gutter*2+(grid*2); t.alb_size = blv;
t.alb_size = blv;
})
}); });
}, },
@@ -1,5 +1,5 @@
<template> <template>
<view class="tm-button " :class="[block ? 'd-block' : 'd-inline-block ']"> <view class="tm-button " :class="[block ? 'd-block' : 'd-inline-block ']" hover-class="opacity-6">
<view <view
class="flex-center tm-button-btn fulled-height" class="flex-center tm-button-btn fulled-height"
:class="[block ? '' : customDense_puted ? '' : 'ma-10', block ? 'd-block' : 'd-inline-block', black_tmeme ? 'bk' : '', customStyleTm]" :class="[block ? '' : customDense_puted ? '' : 'ma-10', block ? 'd-block' : 'd-inline-block', black_tmeme ? 'bk' : '', customStyleTm]"
@@ -54,7 +54,7 @@
<block v-if="vtype == true"> <block v-if="vtype == true">
<text <text
v-if="!fab && icon" v-if="!fab && icon"
:class="[`${prefx_computed} ${icon}`, fontColor ? `text-${colors.color}` : '', black_tmeme ? 'opacity-6' : '', 'px-12']" :class="[`${prefx_computed} ${icon}`, fontColor ? `text-${colors.color}` : '', black_tmeme ? 'opacity-6' : '', 'px-12','flex-shrink']"
:style="{ :style="{
fontSize: `${icon_size.px}px`, fontSize: `${icon_size.px}px`,
lineHeight:'normal' lineHeight:'normal'
@@ -62,7 +62,7 @@
></text> ></text>
<text <text
v-if="fab && icon && !loading && !titl" v-if="fab && icon && !loading && !titl"
:class="[`${prefx_computed} ${icon}`, fontColor ? `text-${colors.color}` : '', black_tmeme ? 'opacity-6' : '']" :class="[`${prefx_computed} ${icon}`, fontColor ? `text-${colors.color}` : '', black_tmeme ? 'opacity-6' : '','flex-shrink']"
:style="{ :style="{
fontSize: `${icon_size.px}px`, fontSize: `${icon_size.px}px`,
lineHeight:'normal' lineHeight:'normal'
@@ -70,7 +70,7 @@
></text> ></text>
<text <text
v-if="fab && icon && !loading && titl" v-if="fab && icon && !loading && titl"
:class="[`${prefx_computed} ${icon}`, fontColor ? `text-${color_tmeme}` : '', black_tmeme ? 'opacity-6' : '']" :class="[`${prefx_computed} ${icon}`, fontColor ? `text-${color_tmeme}` : '', black_tmeme ? 'opacity-6' : '','flex-shrink']"
:style="{ :style="{
fontSize: `${icon_size.px}px`, fontSize: `${icon_size.px}px`,
lineHeight:'normal' lineHeight:'normal'
@@ -80,7 +80,7 @@
<block v-if="vtype == false"><tm-icons :size="icon_size.upx" :name="icon"></tm-icons></block> <block v-if="vtype == false"><tm-icons :size="icon_size.upx" :name="icon"></tm-icons></block>
</slot> </slot>
<view v-if="!fab || showValue" class="d-inline-block tm-button-label flex-shrink" :style="{ fontSize: font_size }" :class="[fontColor ? `text-${colors.color}` : '']"> <view v-if="!fab || showValue" class="d-inline-block tm-button-label flex-shrink" :style="{ fontSize: font_size }" :class="[fontColor ? `text-${colors.color}` : '',vertical ? 'full ' : '',]">
<slot name="default" :data="label">{{ label }}</slot> <slot name="default" :data="label">{{ label }}</slot>
</view> </view>
</button> </button>
@@ -556,11 +556,13 @@ export default {
line-height: 88upx; line-height: 88upx;
height: 88upx; height: 88upx;
vertical-align: middle; vertical-align: middle;
// #ifdef H5 // #ifdef H5
transition: all 0.3s; transition: all 0.3s;
// #endif // #endif
.tm-button-label { .tm-button-label {
vertical-align: middle; vertical-align: middle;
} }
&::after { &::after {
border: none; border: none;
@@ -671,6 +673,7 @@ export default {
} }
&.showValue { &.showValue {
line-height: inherit !important; line-height: inherit !important;
padding: 0 !important;
} }
&.noGutter { &.noGutter {
@@ -54,13 +54,21 @@
:key="index+'_acv'"><text class="text-size-s py-16">{{item}}</text> :key="index+'_acv'"><text class="text-size-s py-16">{{item}}</text>
</tm-col> </tm-col>
<!-- #endif --> <!-- #endif -->
<tm-col :round="(item.start||item.end||item.checked)?4:0" @click="day_danxuanclick(item,index)" <tm-col
:color="item.beginEnd?(item.checked===true||item.start||item.end?color_tmeme+(black_tmeme?' bk ':''):(item.guocheng?color_tmeme+' text opacity-7 '+(black_tmeme?'bk':''):'')):''" @click="day_danxuanclick(item,index)"
color=""
:custom-class="isSelectedDateClass(item)" :custom-class="isSelectedDateClass(item)"
align="middle" width="14.28%" v-for="(item,index) in nowData" justify="center" width="14.28%"
:key="index"> v-for="(item,index) in nowData"
:key="index"
<view class="tm-calendar-col flex-center flex-col py-4" :class="[black_tmeme&&!item.beginEnd?' opacity-2 ':'']"> >
<view class="tm-calendar-col flex-center flex-col "
:style="[mode=='rang'?{width:'100%',height:'90rpx'}:{width:'90rpx',height:'90rpx',overflow: 'hidden','border-radius': '50% !important'}]"
:class="[
item.start?'round-l-24':'',
item.end?'round-r-24':'',
item.beginEnd?(item.checked===true||item.start||item.end?color_tmeme+(black_tmeme?' bk ':''):(item.guocheng?color_tmeme+' text opacity-7 '+(black_tmeme?'bk':''):'')):'',
black_tmeme&&!item.beginEnd?' opacity-2 ':'']">
<text class="text-size-n " <text class="text-size-n "
:class="[ :class="[
@@ -70,19 +78,14 @@
!item.beginEnd?'text-grey-lighten-3':'' !item.beginEnd?'text-grey-lighten-3':''
]" ]"
>{{item.day}}</text> >{{item.day}}</text>
<!--
!item.nowMonth&&!item.guocheng&&!item.checked&&!item.start&&!item.end?(black?'text-grey-darken-3':'text-grey-lighten-1'):'',
item.checked||item.start||item.end?'text-white':(item.guocheng?'':'text-grey-lighten-1'),
item.guocheng?'text-'+color:'',
!item.beginEnd?'text-grey-lighten-3':'',
-->
<view class="text-size-xs text_bl" <view class="text-size-xs text_bl"
> >
<block v-if="item.start"> <block v-if="item.start">
</block> </block>
<block v-if="item.end"> <block v-if="item.end">
结束 -止
</block> </block>
<block v-if="!item.start&&!item.end"> <block v-if="!item.start&&!item.end">
@@ -134,6 +137,11 @@
import tmRow from "@/tm-vuetify/components/tm-row/tm-row.vue" import tmRow from "@/tm-vuetify/components/tm-row/tm-row.vue"
import tmButton from "@/tm-vuetify/components/tm-button/tm-button.vue" import tmButton from "@/tm-vuetify/components/tm-button/tm-button.vue"
import tmPoup from "@/tm-vuetify/components/tm-poup/tm-poup.vue" import tmPoup from "@/tm-vuetify/components/tm-poup/tm-poup.vue"
import * as dayjs from "@/tm-vuetify/tool/function/dayjs/dayjs.min.js"
const calendar = require("@/tm-vuetify/tool/function/dayjs/calendar.js")
dayjs.extend(calendar)
const DayJs = dayjs.default
export default { export default {
components:{tmIcons,tmCol,tmRow,tmButton,tmPoup}, components:{tmIcons,tmCol,tmRow,tmButton,tmPoup},
name: "tm-calendar", name: "tm-calendar",
@@ -262,7 +270,7 @@
if(!this.cal) return; if(!this.cal) return;
// 自动更新默认的显示时间。 // 自动更新默认的显示时间。
if(this.mode=='day'){ if(this.mode=='day'){
let d = new Date().toLocaleDateString().replace(/\//g,'-'); let d = DayJs().format("YYYY/MM/DD HH:mm:ss");
if(this.defaultValue){ if(this.defaultValue){
d = this.defaultValue; d = this.defaultValue;
} }
@@ -343,10 +351,9 @@
}, },
methods: { methods: {
watchRangeTime(){ watchRangeTime(){
let d = DayJs().format("YYYY/MM/DD HH:mm:ss")
let d = new Date().toLocaleDateString().replace(/\//g,'-');
if(this.defaultValue){ if(this.defaultValue){
d = this.defaultValue; d = DayJs(this.defaultValue).format("YYYY/MM/DD HH:mm:ss");
} }
this.cal = new this.$tm.calendar({value:d,start:this.timeStart,end:this.timeEnd}) this.cal = new this.$tm.calendar({value:d,start:this.timeStart,end:this.timeEnd})
if(this.txt){ if(this.txt){
@@ -366,8 +373,8 @@
if(this.bingStart&&this.bingEnd){ if(this.bingStart&&this.bingEnd){
this.fanxuanxuanwuBydate( this.fanxuanxuanwuBydate(
new Date(this.bingStart.replace(/-/g,'/')), DayJs(this.bingStart),
new Date(this.bingEnd.replace(/-/g,'/')), DayJs(this.bingEnd),
) )
} }
} }
@@ -609,13 +616,14 @@
// 通过外围 时间默认的选中 // 通过外围 时间默认的选中
fanxuanxuanwuBydate(start,end){ fanxuanxuanwuBydate(start,end){
if(!start||!end) return; if(!start||!end) return;
// .format("YYYY/MM/DD HH:mm:ss")
this.$nextTick(function(){ this.$nextTick(function(){
if(start.getTime()>end.getTime()) return; if(start.valueOf()>end.valueOf()) return;
// 获取开始月份的数据。 // 获取开始月份的数据。
let sobj = new this.$tm.calendar({value:start.toLocaleDateString().replace(/\//g,'-')}); let sobj = new this.$tm.calendar({value:start.format("YYYY/MM/DD HH:mm:ss")});
// 获取结束月份的数据。 // 获取结束月份的数据。
let eobj = new this.$tm.calendar({value:end.toLocaleDateString().replace(/\//g,'-')}); let eobj = new this.$tm.calendar({value:end.format("YYYY/MM/DD HH:mm:ss")});
function findItemToindex_only(obj,type){ function findItemToindex_only(obj,type){
let item=null; let item=null;
for(let i=0;i<obj.length;i++){ for(let i=0;i<obj.length;i++){
@@ -657,7 +665,7 @@
this.start = start_obj this.start = start_obj
this.end = end_obj this.end = end_obj
// 如果结束和开始相等。 // 如果结束和开始相等。
if(start.getTime()==end.getTime()){ if(start.valueOf()==end.valueOf()){
this.start = {...this.start,start:true,end:true} this.start = {...this.start,start:true,end:true}
this.end = {...this.end,start:true,end:true} this.end = {...this.end,start:true,end:true}
} }
@@ -48,12 +48,21 @@
:key="index"><text class="text-size-s py-16">{{item}}</text> :key="index"><text class="text-size-s py-16">{{item}}</text>
</tm-col> </tm-col>
<!-- #endif --> <!-- #endif -->
<tm-col :round="(item.start||item.end||item.checked)?4:0" @click="day_danxuanclick(item,index)" <tm-col
:color="item.beginEnd?(item.checked===true||item.start||item.end?color_tmeme+(black_tmeme?' bk ':''):(item.guocheng?color_tmeme+' text opacity-7 '+(black_tmeme?'bk':''):'')):''" @click="day_danxuanclick(item,index)"
color=""
:custom-class="isSelectedDateClass(item)" :custom-class="isSelectedDateClass(item)"
align="middle" width="14.28%" v-for="(item,index) in nowData" justify="center" width="14.28%"
:key="index"> v-for="(item,index) in nowData"
<view class="tm-calendarView-col flex-center flex-col" :class="[black&&!item.beginEnd?' opacity-2 ':'']"> :key="index"
>
<view class="tm-calendar-col flex-center flex-col "
:style="[mode=='rang'?{width:'100%',height:'90rpx'}:{width:'90rpx',height:'90rpx',overflow: 'hidden','border-radius': '50% !important'}]"
:class="[
item.start?'round-l-24':'',
item.end?'round-r-24':'',
item.beginEnd?(item.checked===true||item.start||item.end?color_tmeme+(black_tmeme?' bk ':''):(item.guocheng?color_tmeme+' text opacity-7 '+(black_tmeme?'bk':''):'')):'',
black_tmeme&&!item.beginEnd?' opacity-2 ':'']">
<text class="text-size-n" <text class="text-size-n"
:class="[ :class="[
!item.nowMonth&&!item.guocheng&&!item.checked&&!item.start&&!item.end?(black_tmeme?'text-grey-darken-3':'text-grey-lighten-1'):'', !item.nowMonth&&!item.guocheng&&!item.checked&&!item.start&&!item.end?(black_tmeme?'text-grey-darken-3':'text-grey-lighten-1'):'',
@@ -65,10 +74,10 @@
<view class="text-size-xs text_bl" <view class="text-size-xs text_bl"
> >
<block v-if="item.start"> <block v-if="item.start">
</block> </block>
<block v-if="item.end"> <block v-if="item.end">
结束 -止
</block> </block>
<block v-if="!item.start&&!item.end"> <block v-if="!item.start&&!item.end">
@@ -53,7 +53,7 @@
return ps; return ps;
}, },
isfinish:function(){ isfinish:function(){
if(this.now == this.time) return true; if(this.now == this.time||this.now==0) return true;
return false; return false;
} }
}, },
@@ -302,19 +302,19 @@ export default {
.tm-dialog { .tm-dialog {
width: 100%; width: 100%;
z-index: 600; z-index: 600;
background-color: rgba(0, 0, 0, 0.35); background-color: rgba(0, 0, 0, 0.3);
left: 0; left: 0;
top: 0; top: 0;
backdrop-filter: blur(10px); backdrop-filter: blur(3px);
transition: all 0.35s; transition: all 0.24s;
.success { .success {
animation: success 0.35s linear; animation: success 0.24s ease;
// transform: scale(1); // transform: scale(1);
} }
.clickover { .clickover {
animation: clickover 0.35s linear; animation: clickover 0.24s ease;
} }
} }
@keyframes clickover { @keyframes clickover {
@@ -253,10 +253,10 @@
this.$emit('change',elList); this.$emit('change',elList);
}, },
inits() { inits() {
this.grid = this.list.length;
if(this.grid==0) return; if(this.grid==0) return;
this.$nextTick(async function() { this.$nextTick(async function() {
let p = await this.$Querey(".tm-dragGrid", this).catch(e => {}) let p = await this.$Querey(".tm-dragGrid", this).catch(e => {})
this.grid = this.list.length;
this.listData = []; this.listData = [];
//组件的宽度 //组件的宽度
this.w = uni.upx2px(this.width) || p[0].width || 300; this.w = uni.upx2px(this.width) || p[0].width || 300;
@@ -140,7 +140,6 @@
jishunTopData() { jishunTopData() {
this.$nextTick(async function() { this.$nextTick(async function() {
this.listData = []; this.listData = [];
let p = await this.$Querey(".tm-dragList", this).catch(e => {}) let p = await this.$Querey(".tm-dragList", this).catch(e => {})
this.w = uni.upx2px(this.width) || p[0].width; this.w = uni.upx2px(this.width) || p[0].width;
this.h = uni.upx2px(this.height) this.h = uni.upx2px(this.height)
@@ -20,6 +20,7 @@
@touchcancel="$emit('touchcancel', $event)" @touchcancel="$emit('touchcancel', $event)"
:open-type="openType" :open-type="openType"
@click="click" @click="click"
:padding="[0,0]"
:showValue="showText" vertical :label="label" :fontSize="fontSize" :showValue="showText" vertical :label="label" :fontSize="fontSize"
:iconSize="iconSize" :theme="color_tmeme" round="rouned" :font-color="fontColor" :bgcolor="bgcolor" :iconSize="iconSize" :theme="color_tmeme" round="rouned" :font-color="fontColor" :bgcolor="bgcolor"
:size="size" :width="width" :height="width" :icon="icon" fab> :size="size" :width="width" :height="width" :icon="icon" fab>
@@ -6,7 +6,7 @@
<view v-if="title&&title!='true'" class="px-32 py-16 text-weight-b " :class="[`text-size-${fontSize}`,titleTheme, black_tmeme ? 'bk' : '']"> <view v-if="title&&title!='true'" class="px-32 py-16 text-weight-b " :class="[`text-size-${fontSize}`,titleTheme, black_tmeme ? 'bk' : '']">
<slot name="title" :title="title">{{ title }}</slot> <slot name="title" :title="title">{{ title }}</slot>
</view> </view>
<view v-show="chuliWsok==true"> <view >
<slot></slot> <slot></slot>
</view> </view>
</view> </view>
@@ -77,6 +77,20 @@ export default {
return this.$tm.vx.state().tmVuetify.black; return this.$tm.vx.state().tmVuetify.black;
} }
}, },
provide(){
let t = this;
return {
GroupListStyles:()=>{
return {
margin: [0,0],
padding: [32,24],
shadow: 0,
round: 0,
borderBottom: true
}
}
}
},
data() { data() {
return { return {
targ:'tm-grouplist', targ:'tm-grouplist',
@@ -99,47 +113,7 @@ export default {
}, },
methods: { methods: {
inits(){ inits(){
let t = this;
this.$nextTick(function () {
let ch = this.$children;
// #ifdef H5
ch = [];
let cld = this.$children[0].$children
while(cld){
if(cld[0].$children.length>0){
let ods = cld[0].$children;
ch =ods[ods.length-1].$children;
break;
}else{
cld = cld[0]?.$children
}
}
// #endif
ch.forEach((item,index)=>{
if(item.$options.name==="tm-listitem"){
item.setConfig({
margin: [0,0],
padding: [32,24],
shadow: 0,
round: 0,
borderBottom: index===ch.length-1?false:t.borderBottom
})
}
})
// #ifndef H5
setTimeout(function() {
t.chuliWsok = true;
}, 30);
// #endif
})
}, },
// 事件一定是子项目tm-listitem为group模式时,才会触发。 // 事件一定是子项目tm-listitem为group模式时,才会触发。
change(vue_uid) { change(vue_uid) {
+160 -157
View File
@@ -1,187 +1,190 @@
<template> <template>
<!-- 图标 --> <!-- 图标 -->
<view @click="onclick" v-if="name" class="tm-icons vertical-align-top" style="display: inline-block;font-size: 0;" > <view @click="onclick" v-if="name" class="tm-icons " >
<view class="flex-center " :style="{ <view
width: sizes, class="tm-icons-item "
height: sizes, :style="{
lineHeight:sizes, width: sizes,
height: sizes,
}"> lineHeight: sizes
}"
>
<block v-if="vtype == false"> <block v-if="vtype == false">
<image :src="name" :style="{ <image
:src="name"
:style="{
width: sizes, width: sizes,
height: sizes height: sizes
}" mode="scaleToFill"></image> }"
mode="scaleToFill"
></image>
</block> </block>
<block v-if="vtype == true"> <block v-if="vtype == true">
<!-- #ifdef APP-NVUE --> <!-- #ifdef APP-NVUE -->
<text :style="{ <text
:style="{
fontSize: sizes, fontSize: sizes,
fontFamily:'iconfontTM' fontFamily: 'iconfontTM'
}" class="icons " }"
:class="[ black_tmeme ? colors+'-bk':colors, dense ? '' : 'pa-10', black ? 'opacity-6' : '']">{{iconName}}</text> class="icons "
:class="[black_tmeme ? colors + '-bk' : colors, dense ? '' : 'pa-10', black ? 'opacity-6' : '']"
>
{{ iconName }}
</text>
<!-- #endif --> <!-- #endif -->
<!-- #ifndef APP-NVUE -->
<!-- #ifdef MP --> <text
<text :style="{ :style="{
fontSize: sizes, fontSize: sizes,
}" class="icons mt--4"
:class="[prefx_computed, black_tmeme ? 'bk' : '', iconName, colorTheme ? colors : '', dense ? '' : 'pa-10', black ? 'opacity-6' : '']"></text> }"
class="icons "
:class="[prefx_computed, black_tmeme ? 'bk' : '', iconName, colorTheme ? colors : '', dense ? '' : 'pa-10', black ? 'opacity-6' : '']"
></text>
<!-- #endif --> <!-- #endif -->
<!-- #ifndef MP -->
<text :style="{
fontSize: sizes,
}" class="icons "
:class="[prefx_computed, black_tmeme ? 'bk' : '', iconName, colorTheme ? colors : '', dense ? '' : 'pa-10', black ? 'opacity-6' : '']"></text>
<!-- #endif -->
</block> </block>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
/** /**
* 图标组件 * 图标组件
* @property {Boolean} dense = [true|false] 默认false,是否去除边距 * @property {Boolean} dense = [true|false] 默认false,是否去除边距
* @property {String} prefx = [iconfont] 默认iconfont,默认图标的前缀,对自定义图标时有好处。 * @property {String} prefx = [iconfont] 默认iconfont,默认图标的前缀,对自定义图标时有好处。
* @property {String} name = [] 默认'',图标名称,注意不带前缀。 * @property {String} name = [] 默认'',图标名称,注意不带前缀。
* @property {String | Number} size = [] 默认28, 图标大小,单位是upx * @property {String | Number} size = [] 默认28, 图标大小,单位是upx
* @property {String} color = [primary] 默认primary, 图标主题颜色名 * @property {String} color = [primary] 默认primary, 图标主题颜色名
* @property {Function} click 图标点击事件。 * @property {Function} click 图标点击事件。
* @example <tm-icons name='icon-clear'></tm-icons> * @example <tm-icons name='icon-clear'></tm-icons>
*/ */
export default { export default {
props: { props: {
dense: { dense: {
//是否小边距 //是否小边距
type: Boolean, type: Boolean,
default: false default: false
}, },
black: { black: {
type: Boolean, type: Boolean,
default: null default: null
}, },
prefx: { prefx: {
type: String, //前缀 type: String, //前缀
default: 'iconfont' default: 'iconfont'
}, },
name: { name: {
type: String, //图标名称。 type: String, //图标名称。
default: '' default: ''
}, },
size: { size: {
type: String | Number, //图标名称。 type: String | Number, //图标名称。
default: 28 default: 28
}, },
color: { color: {
type: String, //颜色名称或者颜色值。 type: String|null, //颜色名称或者颜色值。
default: 'primary' default: 'primary'
}, },
//强制转换图标类型,不通过内置判定,解决自己引用图片svg图标时当作字体图标的错误。 //强制转换图标类型,不通过内置判定,解决自己引用图片svg图标时当作字体图标的错误。
iconType: { iconType: {
type: String, type: String,
default: '' //img|icon default: '' //img|icon
}, },
// 跟随主题色的改变而改变。 // 跟随主题色的改变而改变。
fllowTheme: { fllowTheme: {
type: Boolean | String, type: Boolean | String,
default: false default: false
}
},
computed: {
iconName: function() {
// #ifdef APP-NVUE || APP-PLUS-NVUE
let fontList = require('@/tm-vuetify/scss/iconfonts/iconfont.json');
let name = this.name.replace('icon-', '');
// fontList.glyphs
let itemIcon = fontList.glyphs.find((item, index) => {
return item.font_class == name;
});
return eval('"\\u' + itemIcon.unicode + '"');
// #endif
return this.name;
},
prefx_computed() {
let prefix = this.name.split('-')[0];
if (prefix == 'icon') return 'iconfont';
if (prefix == 'mdi') return 'mdi';
return prefix;
},
black_tmeme: function() {
return this.$tm.vx.state().tmVuetify.black;
},
vtype: function() {
if (this.name[0] == '.' || this.name[0] == '/' || this.name.substring(0, 4) == 'http' || this.name.substring(0, 5) == 'https' || this.name.substring(0, 3) == 'ftp') {
return false;
}
return true;
},
sizes: function() {
if (typeof this.size === 'string') {
if (/[rpx|upx|rem|em|vx|vh|px]$/.test(this.size)) {
return this.size;
}
return uni.upx2px(parseInt(this.size)) + 'px';
}
if (typeof this.size === 'number' && !isNaN(this.size)) {
return uni.upx2px(this.size) + 'px';
} }
}, },
computed: { color_tmeme: function() {
iconName: function() { if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this.fllowTheme) {
// #ifdef APP-NVUE || APP-PLUS-NVUE return this.$tm.vx.state().tmVuetify.color;
let fontList = require('@/tm-vuetify/scss/iconfonts/iconfont.json');
let name = this.name.replace('icon-', '');
// fontList.glyphs
let itemIcon = fontList.glyphs.find((item, index) => {
return item.font_class == name;
})
return eval('"\\u' + itemIcon.unicode + '"');
// #endif
return this.name;
},
prefx_computed(){
let prefix = this.name.split('-')[0];
if(prefix=='icon') return 'iconfont';
if(prefix=='mdi') return 'mdi';
return prefix;
},
black_tmeme: function() {
return this.$tm.vx.state().tmVuetify.black;
},
vtype: function() {
if (this.name[0] == "." ||
this.name[0] == "/" ||
this.name.substring(0, 4) == 'http' ||
this.name.substring(0, 5) == 'https' ||
this.name.substring(0, 3) == 'ftp'
) {
return false;
}
return true;
},
sizes: function() {
if (typeof this.size === 'string') {
if (/[rpx|upx|rem|em|vx|vh|px]$/.test(this.size)) {
return this.size;
}
return uni.upx2px(parseInt(this.size)) + 'px';
}
if (typeof this.size === 'number' && !isNaN(this.size)) {
return uni.upx2px(this.size) + 'px';
}
},
color_tmeme: function() {
if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
.fllowTheme) {
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
colors: {
get: function() {
if (!this.color_tmeme) return 'text-primary';
if (!this.$TestColor(this.color_tmeme)) {
return this.color_tmeme;
}
return 'text-' + this.color_tmeme;
},
set: function() {
if (!this.$TestColor(this.color_tmeme)) {
this.colorTheme = false;
return this.color_tmeme;
}
this.colorTheme = true;
}
} }
return this.color;
}, },
data() { colors: {
return { get: function() {
colorTheme: true if (!this.color_tmeme) return 'text-primary';
}; if (!this.$TestColor(this.color_tmeme)) {
}, return this.color_tmeme;
methods: { }
onclick(e) { return 'text-' + this.color_tmeme;
this.$emit('click', e); },
set: function() {
if (!this.$TestColor(this.color_tmeme)) {
this.colorTheme = false;
return this.color_tmeme;
}
this.colorTheme = true;
} }
} }
}; },
data() {
return {
colorTheme: true
};
},
methods: {
onclick(e) {
this.$emit('click', e);
}
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.tm-icons { .tm-icons {
vertical-align: middle; display: inline-block;
.tm-icons-item{
.icons { display: flex;
&.black { justify-content: center;
color: #fff; align-items: center;
} }
.icons {
&.black {
color: #fff;
} }
} }
}
</style> </style>
+5 -2
View File
@@ -25,7 +25,7 @@
<view v-if="title" class="d-inline-block " <view v-if="title" class="d-inline-block "
:style="{fontSize:title_size}" :style="{fontSize:title_size}"
:class="[titleClass,black_tmeme?'bk text-grey-lighten-3':'']"> :class="[titleClass,black_tmeme?'bk text-grey-lighten-3':'']">
<text v-if="required" class="text-red">*</text> <text v-if="_required" class="text-red">*</text>
<slot name="default" :title="title"> <slot name="default" :title="title">
{{title}} {{title}}
</slot> </slot>
@@ -368,6 +368,9 @@
}; };
}, },
computed: { computed: {
_required(){
return this.required
},
height_rpx:function(){ height_rpx:function(){
return this.height; return this.height;
}, },
@@ -430,7 +433,7 @@
set:function(val){ set:function(val){
this.$emit('input', val) this.$emit('input', val)
this.$emit('update:value', val) this.$emit('update:value', val)
if (this.required) { if (this._required) {
this.$nextTick(function(){ this.$nextTick(function(){
this.verifyInput(); this.verifyInput();
}) })
@@ -1,6 +1,6 @@
<!-- 列表项目类似单元格 --> <!-- 列表项目类似单元格 -->
<template> <template>
<view class="tm-listitem "> <view class="tm-listitem " :hover-class="url?'opacity-6':''">
<view <view
@click="click" @click="click"
@@ -280,9 +280,15 @@ export default {
return this.$tm.vx.state().tmVuetify.color; return this.$tm.vx.state().tmVuetify.color;
} }
return this.leftIconColor; return this.leftIconColor;
},
groupPublickStyle:function(){
if(!this.GroupListStyles) return null
return this.GroupListStyles()
} }
}, },
inject:{
GroupListStyles:{default:null}
},
data() { data() {
return { return {
pz_theme: { pz_theme: {
@@ -296,13 +302,25 @@ export default {
}; };
}, },
created() { created() {
this.pz_themeCus = { if(this.groupPublickStyle){
margin: this.margin, this.pz_themeCus = {
padding: this.padding, margin: this.groupPublickStyle.margin,
shadow: this.shadow, padding: this.groupPublickStyle.padding,
round: this.round, shadow: this.groupPublickStyle.shadow,
borderBottom: this.borderBottom round: this.groupPublickStyle.round,
}; borderBottom: this.groupPublickStyle.borderBottom||this.borderBottom
};
}else{
this.pz_themeCus = {
margin: this.margin,
padding: this.padding,
shadow: this.shadow,
round: this.round,
borderBottom: this.borderBottom
};
}
}, },
mounted() { mounted() {
@@ -22,7 +22,6 @@
<text class="iconfont icon-angle-left" :class="[`text-${fontColorTheme}`]" :style="{ fontSize: '28rpx' }"></text> <text class="iconfont icon-angle-left" :class="[`text-${fontColorTheme}`]" :style="{ fontSize: '28rpx' }"></text>
</navigator> </navigator>
</block> </block>
<slot name="left" :data="{ style: widths, isTransparent: isTransparent, title: title }"></slot> <slot name="left" :data="{ style: widths, isTransparent: isTransparent, title: title }"></slot>
</view> </view>
<view class="center flex-center text-size-g text-overflow text-align-center" :class="[`text-${fontColorTheme}`]"> <view class="center flex-center text-size-g text-overflow text-align-center" :class="[`text-${fontColorTheme}`]">
@@ -36,6 +35,7 @@
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
@@ -61,6 +61,9 @@
components: { components: {
tmIcons tmIcons
}, },
options:{
multipleSlots: true
},
name: 'tm-menubars', name: 'tm-menubars',
props: { props: {
// 是否开启暗黑模式 // 是否开启暗黑模式
+12 -10
View File
@@ -109,18 +109,12 @@ import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
mounted() { mounted() {
this.$nextTick(function(){ this.$nextTick(function(){
this.downOpen = this.open; this.downOpen = this.open;
this.getRect()
let t = this;
t.$Querey('.tm-more-content',t).then(syninfo=>{
if (syninfo[0].height - 40 <= t.hs) {
t.show = false;
}
}).catch(e => {});
}) })
}, },
updated() {
this.getRect()
},
computed: { computed: {
hs: function() { hs: function() {
return uni.upx2px(this.maxHeight) || 100; return uni.upx2px(this.maxHeight) || 100;
@@ -131,6 +125,14 @@ import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
} }
}, },
methods: { methods: {
getRect(){
let t = this;
t.$Querey('.tm-more-content',t,0).then(syninfo=>{
if (syninfo[0].height - 40 <= t.hs) {
t.show = false;
}
}).catch(e => {});
},
openMore() { openMore() {
this.$emit('click'); this.$emit('click');
if (this.disabled) return; if (this.disabled) return;
+7 -7
View File
@@ -232,7 +232,7 @@
this.aniData = ''; this.aniData = '';
let aniData = uni.createAnimation({ let aniData = uni.createAnimation({
duration:240, duration:240,
timingFunction: 'linear', timingFunction: 'ease',
}) })
this.aniData = aniData; this.aniData = aniData;
if(pos=='bottom'){ if(pos=='bottom'){
@@ -327,15 +327,15 @@
pointer-events: none; pointer-events: none;
} }
&.blur { &.blur {
backdrop-filter: blur(10px); backdrop-filter: blur(3px);
} }
&.on { &.on {
animation: opta 1s linear; animation: opta 1s ease;
} }
&.off { &.off {
animation: opta_off 0.35s linear; animation: opta_off 0.24s ease;
} }
.tm-poup-wk { .tm-poup-wk {
position: absolute; position: absolute;
@@ -393,7 +393,7 @@
@keyframes opta { @keyframes opta {
from { from {
opacity: 0.6; opacity: 0.3;
} }
to { to {
@@ -495,7 +495,7 @@
@keyframes Centerleft { @keyframes Centerleft {
from { from {
transform: scale(0.65); transform: scale(0.65);
opacity: 0.65; opacity: 0.3;
} }
to { to {
@@ -512,7 +512,7 @@
to { to {
transform: scale(0.65); transform: scale(0.65);
opacity: 0.65; opacity: 0.3;
} }
} }
@@ -166,19 +166,25 @@ export default {
destroyed() { destroyed() {
clearInterval(this.tmiddd) clearInterval(this.tmiddd)
}, },
async mounted() { mounted() {
this.getRect()
this.$nextTick(async function(){
let p = await this.$Querey(".tm-propress",this).catch(e=>{})
this.width_upx = p[0].width+'px';
if(this.loading){
await this.startAni();
}
})
}, },
updated() {
this.getRect()
},
methods: { methods: {
getRect(){
let t =this
this.$Querey(".tm-propress",this,0).then((p)=>{
if(!p) return;
if(!p[0].width) return;
t.width_upx = p[0].width+'px';
if(t.loading){
t.startAni();
}
}).catch(e=>{})
},
async startAni(){ async startAni(){
// clearInterval(this.tmiddd) // clearInterval(this.tmiddd)
let t = this; let t = this;
+27 -26
View File
@@ -1,10 +1,7 @@
<template> <template>
<view @click="$emit('click',$event)" :gutter="gutter" class="tm--row" :class="[preatClass]" > <view @click="$emit('click',$event)" :gutter="gutter" class="tm--row" :class="[preatClass]" >
<view class="tm--row--body" :style="style" :class="[customClass]"> <view class="tm--row--body" :style="style" :class="[customClass]">
<view v-show="chuliWsok==true"> <slot></slot>
<slot></slot>
</view>
</view> </view>
</view> </view>
</template> </template>
@@ -64,30 +61,34 @@
width_px:0, width_px:0,
children_num:0, children_num:0,
style:'', style:'',
chuliWsok:false,//处理完宽度计算信息再进行显示内部内容。
}; };
}, },
async mounted() { updated() {
let t = this; this.getContinaRect()
},
await this.$Querey('.tm--row',this).then(preantw=>{ mounted() {
t.width_px = preantw[0].width; this.getContinaRect()
// #ifndef H5 },
t.children_num = t.$children.length; methods:{
// #endif getContinaRect(){
// #ifdef H5 let t = this;
t.children_num = t.$children[0].$children[0].$children[0].$children.length; this.$Querey('.tm--row',this).then(preantw=>{
// #endif t.width_px = preantw[0].width;
t.style = uni.$tm.objToString({ // #ifndef H5
'justify-content':t.justify, t.children_num = t.$children.length;
'align-items':t.align, // #endif
'width':t.width, // #ifdef H5
'height':!t.height?'default':(uni.upx2px(t.height)+'px') t.children_num = t.$children[0].$children[0].$children[0].$children.length;
},';'); // #endif
t.style = uni.$tm.objToString({
t.chuliWsok = true; 'justify-content':t.justify,
}).catch(e=>{}) 'align-items':t.align,
'width':t.width,
'height':!t.height?'default':(uni.upx2px(t.height)+'px')
},';');
}).catch(e=>{})
}
} }
} }
</script> </script>
@@ -191,10 +191,10 @@
}, },
mounted() { mounted() {
let t = this; let t = this;
uni.$tm.sleep(30).then(()=>{ t.setInits();
t.setInits(); },
updated() {
}) this.setInits();
}, },
methods: { methods: {
setInits() { setInits() {
+2 -20
View File
@@ -25,7 +25,7 @@
]" ]"
> >
<view class="fulled" v-if="showSheet"> <view class="fulled" >
<slot name="default"></slot> <slot name="default"></slot>
</view> </view>
</view> </view>
@@ -151,25 +151,7 @@ export default {
return this.$tm.vx.state().tmVuetify.black; return this.$tm.vx.state().tmVuetify.black;
} }
}, },
data() {
return {
showSheet:true,
};
},
created() {
// #ifdef APP-VUE || APP-PLUS || MP
this.showSheet = false;
// #endif
},
mounted() {
let t= this;
// #ifdef APP-VUE || APP-PLUS || MP
setTimeout(function() {
t.showSheet = true;
}, 30);
// #endif
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -12,7 +12,6 @@
@touchstart="touchstart" @touchstart="touchstart"
@touchmove.stop.prevent="touchsmove" @touchmove.stop.prevent="touchsmove"
@touchend="touchsend" @touchend="touchsend"
@mousedown="touchstart" @mousedown="touchstart"
@mousemove.stop.prevent="touchsmove" @mousemove.stop.prevent="touchsmove"
@mouseup="touchsend" @mouseup="touchsend"
+12 -1
View File
@@ -244,6 +244,17 @@
this.barLeft = rdl >= this.sliderWidth || rdl < 0 ? this.sliderWidth : rdl; this.barLeft = rdl >= this.sliderWidth || rdl < 0 ? this.sliderWidth : rdl;
}); });
}, },
async updated() {
this.$nextTick(async function() {
await this.getwidth();
if (Math.abs(this.value) > Math.abs(this.max)) {
this.isError = true;
return;
}
let rdl = this.sliderWidth * (Math.abs(this.value) / Math.abs(this.max));
this.barLeft = rdl >= this.sliderWidth || rdl < 0 ? this.sliderWidth : rdl;
});
},
methods: { methods: {
barStart(e) { barStart(e) {
@@ -306,7 +317,7 @@
}, },
async getwidth() { async getwidth() {
let res = await this.$Querey('.tm-slider-id', this).catch(e=>{}); let res = await this.$Querey('.tm-slider-id', this,0).catch(e=>{});
res[0].width = res[0].width||uni.upx2px(this.width); res[0].width = res[0].width||uni.upx2px(this.width);
res[0].height = res[0].height||uni.upx2px(this.height); res[0].height = res[0].height||uni.upx2px(this.height);
if (this.showLeft === false && this.showRight === false) { if (this.showLeft === false && this.showRight === false) {
@@ -297,6 +297,20 @@
this.barLeft_1 = rdl_1 >= this.sliderWidth || rdl_1 < 0 ? this.sliderWidth : rdl_1; this.barLeft_1 = rdl_1 >= this.sliderWidth || rdl_1 < 0 ? this.sliderWidth : rdl_1;
}); });
}, },
updated() {
this.$nextTick(async function() {
await this.getwidth();
if (Math.abs(this.value[1]) > Math.abs(this.max)) {
this.isError = true;
return;
}
let rdl = this.sliderWidth * (Math.abs(this.value[0]) / Math.abs(this.max));
this.barLeft = rdl >= this.sliderWidth || rdl < 0 ? this.sliderWidth : rdl;
let rdl_1 = this.sliderWidth * (Math.abs(this.value[1]) / Math.abs(this.max));
this.barLeft_1 = rdl_1 >= this.sliderWidth || rdl_1 < 0 ? this.sliderWidth : rdl_1;
});
},
methods: { methods: {
barStart(e) { barStart(e) {
if (this.disabled || this.isError) return; if (this.disabled || this.isError) return;
@@ -407,7 +421,7 @@
}, },
async getwidth() { async getwidth() {
let res = await this.$Querey('.tm-slider-id', this).catch(e=>{}); let res = await this.$Querey('.tm-slider-id', this,0).catch(e=>{});
res[0].width = res[0].width||uni.upx2px(this.width); res[0].width = res[0].width||uni.upx2px(this.width);
res[0].height = res[0].height||uni.upx2px(this.height); res[0].height = res[0].height||uni.upx2px(this.height);
+358 -399
View File
@@ -1,83 +1,43 @@
<template> <template>
<view class="tm-swiper " :class="[inline ? 'd-inline-block' : '']"> <view class="tm-swiper " :class="[inline ? 'd-inline-block' : '']">
<swiper <swiper :previous-margin="`${ani3d}rpx`" :next-margin="`${ani3d}rpx`" :style="{
:previous-margin="`${ani3d}rpx`"
:next-margin="`${ani3d}rpx`"
:style="{
width: w_s + 'rpx', width: w_s + 'rpx',
height: h_s + 'rpx' height: h_s + 'rpx'
}" }" :vertical="vertical" :autoplay="autoplay&&!isPlayVedio" :circular="circular" :interval="interval" :duration="duration"
:vertical="vertical" :indicator-active-color="color_tmeme" :current="nowIndex" @change="change" :class="[round_num > 0 ? ` round-${round_num} overflow` : '']">
:autoplay="autoplay && !isPlayVedio"
:circular="circular"
:interval="interval"
:duration="duration"
:indicator-active-color="color_tmeme"
:current="nowIndex"
@change="change"
>
<block v-for="(item, index) in dataList" :key="index"> <block v-for="(item, index) in dataList" :key="index">
<swiper-item <swiper-item :style="{
:style="{
width: w_s + 'rpx', width: w_s + 'rpx',
height: h_s + 'rpx' height: h_s + 'rpx'
}" }" class="shadow-24" :class="[round_num > 0 ? ` round-${round_num} overflow` : '']">
class="shadow-24"
:class="[round_num > 0 ? ` round-${round_num} overflow` : '']"
>
<view <view
:class="[ :class="[nowIndex !== index&&ani3d>0?'a3d':'',round_num > 0 ? ` round-${round_num} overflow` : '',nowIndex<index&&ani3d>0?'a3dL':'',nowIndex>index&&ani3d>0?'a3dR':'']"
nowIndex !== index && ani3d > 0 ? 'a3d' : '', class="tm-swiper-ik fulled fulled-height" :key="index">
round_num > 0 ? ` round-${round_num} overflow` : '',
nowIndex < index && ani3d > 0 ? 'a3dL' : '',
nowIndex > index && ani3d > 0 ? 'a3dR' : ''
]"
class="tm-swiper-ik fulled fulled-height"
:key="index"
>
<view class="actvieMarginDh"> <view class="actvieMarginDh">
<view class="actvieMarginDh-item" :class="[round_num > 0 ? ` round-${round_num} overflow` : '']"> <view class="actvieMarginDh-item"
<image :class="[round_num > 0 ? ` round-${round_num} overflow` : '']">
v-if="item.dtype != 'video'" <image v-if="item.dtype!='video'" @click="itemClick(item)" :style="{
@click="itemClick(item)"
:style="{
height: h_s + 'rpx', height: h_s + 'rpx',
width: w_s - margin_px + 'rpx' width: (w_s - margin_px) + 'rpx'
}" }" @load="imgload($event, index)" :src="item.url"
@load="imgload($event, index)" :class="[round_num > 0 ? ` round-${round_num} overflow` : '']"></image>
:src="item.url" <video @play="isPlayVedio = true" @pause="isPlayVedio=false" @ended="isPlayVedio=false" :autoplay="nowIndex == index?true:false" :style="{
:class="[round_num > 0 ? ` round-${round_num} overflow` : '']"
></image>
<video
@play="isPlayVedio = true"
@pause="isPlayVedio = false"
@ended="isPlayVedio = false"
:autoplay="nowIndex == index ? true : false"
:style="{
height: h_s + 'rpx', height: h_s + 'rpx',
width: w_s - margin_px + 'rpx' width: (w_s - margin_px) + 'rpx'
}" }" v-if="item.dtype=='video'" :src="item.url"></video>
v-if="item.dtype == 'video'"
:src="item.url"
></video>
<view <view v-if="item.title" :style="{
v-if="item.title" width: (w_s - margin_px) + 'rpx'
:style="{ }" class="flex-start relative ">
width: w_s - margin_px + 'rpx'
}"
class="flex-start relative "
>
<view <view
class="text-size-s px-16 absolute b-0 l-0 zIndex-14 flex-start text-overflow text-white" class="text-size-s px-16 absolute b-0 l-0 zIndex-14 flex-start text-overflow text-white"
:style="{ :style="{
height: '66rpx', height: '66rpx',
width: w_s - margin_px - 32 + 'rpx', width: (w_s - margin_px-32) + 'rpx',
lineHeight: '66rpx', lineHeight:'66rpx',
background: 'rgba(0,0,0,0.4)' background:'rgba(0,0,0,0.4)'
}" }">
> {{item.title}}
{{ item.title }}
</view> </view>
</view> </view>
</view> </view>
@@ -86,24 +46,19 @@
</swiper-item> </swiper-item>
</block> </block>
</swiper> </swiper>
<view class="tm-swiper-dot" v-if="indicatorDots && nowshowDot" :class="[dotDirection]"> <view class="tm-swiper-dot" v-if="indicatorDots&&nowshowDot" :class="[dotDirection]">
<block v-if="dotModel != 'round'"> <block v-if="dotModel != 'round'">
<view <view @click="nowIndex = index" v-for="(item, index) in dataList" :key="index"
@click="nowIndex = index"
v-for="(item, index) in dataList"
:key="index"
class="tm-swiper-dot-item flex-center mx-8" class="tm-swiper-dot-item flex-center mx-8"
:class="[nowIndex == index ? color_tmeme : 'unactive', dotModel]" :class="[nowIndex == index ? color_tmeme : 'unactive', dotModel]">
>
<text v-if="dotModel === 'number'" class="text-size-xs">{{ index + 1 }}</text> <text v-if="dotModel === 'number'" class="text-size-xs">{{ index + 1 }}</text>
</view> </view>
</block> </block>
<block v-if="dotModel == 'round'"> <block v-if="dotModel == 'round'">
<view <view :class="[dotModel]"
:class="[dotModel]"
class="text-size-xs balck text-white round-24 px-24 tm-swiper-dot-item flex-center flex-shrink" class="text-size-xs balck text-white round-24 px-24 tm-swiper-dot-item flex-center flex-shrink"
:style="{ height: '40rpx', minWidth: '60rpx' }" :style="{ height: '40rpx', minWidth: '60rpx' }">
>
{{ nowIndex + 1 + '/' + dataList.length }} {{ nowIndex + 1 + '/' + dataList.length }}
</view> </view>
</block> </block>
@@ -112,353 +67,357 @@
</template> </template>
<script> <script>
/** /**
* 图片轮播 * 图片轮播
* @description 很参数与原官方相同。 * @description 很参数与原官方相同。
* @property {Number} width = [] 默认:0,轮播宽度,0为自己计算。 * @property {Number} width = [] 默认:0,轮播宽度,0为自己计算。
* @property {Number} height = [] 默认:0,轮播高度,0为自己计算。 * @property {Number} height = [] 默认:0,轮播高度,0为自己计算。
* @property {Array} list = [] 默认:[],图片列表,可以是string数组或者object数组。 * @property {Array} list = [] 默认:[],图片列表,可以是string数组或者object数组。
* @property {String} rang-key = [] 默认:[],图片列表object数组时,需要提供图片地址 的键值。 * @property {String} rang-key = [] 默认:[],图片列表object数组时,需要提供图片地址 的键值。
* @property {Boolean} inline = [] 默认:false,是否内联,方便一排放多个轮播组件。 * @property {Boolean} inline = [] 默认:false,是否内联,方便一排放多个轮播组件。
* @property {Boolean} previmage = [] 默认:true,是否预览图片,点击图片时,放大预览。 * @property {Boolean} previmage = [] 默认:true,是否预览图片,点击图片时,放大预览。
* @property {Boolean} vertical = [] 默认:false,是否竖向滚动。 * @property {Boolean} vertical = [] 默认:false,是否竖向滚动。
* @property {Boolean} circular = [] 默认:false,是否采用衔接滑动,即播放到末尾后重新回到开头 * @property {Boolean} circular = [] 默认:false,是否采用衔接滑动,即播放到末尾后重新回到开头
* @property {Boolean} autoplay = [] 默认:false,是否自动切换 * @property {Boolean} autoplay = [] 默认:false,是否自动切换
* @property {Number} interval = [] 默认:3000,自动切换时间间隔 * @property {Number} interval = [] 默认:3000,自动切换时间间隔
* @property {Number} duration = [] 默认:500,滑动动画时长 * @property {Number} duration = [] 默认:500,滑动动画时长
* @property {Number} ani3d = [] 默认:0,开启3d缩放动画 * @property {Number} ani3d = [] 默认:0,开启3d缩放动画
* @property {Boolean} indicator-dots = [] 默认:true,是否显示指示 * @property {Boolean} indicator-dots = [] 默认:true,是否显示指示
* @property {String} color = [] 默认:primary,指示点的主题色。 * @property {String} color = [] 默认:primary,指示点的主题色。
* @property {Number} current = [] 默认:0,如果需要双向绑定请使用current.sync. * @property {Number} current = [] 默认:0,如果需要双向绑定请使用current.sync.
* @property {String} dot-model = [dot|number|rect|round] 默认:dot,指示点的类型。 * @property {String} dot-model = [dot|number|rect|round] 默认:dot,指示点的类型。
* @property {String} dot-direction = [left|center|right] 默认:center,指示点的位置。 * @property {String} dot-direction = [left|center|right] 默认:center,指示点的位置。
* @property {Number} round = [] 默认:0,圆角,单位rpx * @property {Number} round = [] 默认:0,圆角,单位rpx
* @property {Number} margin = [] 默认:0,单位rpx * @property {Number} margin = [] 默认:0,单位rpx
* @property {Function} change 轮播切换时触发。参数返回当前播放位置。 * @property {Function} change 轮播切换时触发。参数返回当前播放位置。
* @property {Function} click 轮播项目被点击时触发发,返回项目数据 * @property {Function} click 轮播项目被点击时触发发,返回项目数据
* @example <tm-swiper :list="['https://picsum.photos/300?jv=3','https://picsum.photos/300?jv=3']" ></tm-swiper> * @example <tm-swiper :list="['https://picsum.photos/300?jv=3','https://picsum.photos/300?jv=3']" ></tm-swiper>
*/ */
export default { export default {
name: 'tm-swiper', name: 'tm-swiper',
props: { props: {
width: { width: {
type: Number | String, type: Number | String,
default: 0 default: 0
},
// 自定高度。
height: {
type: Number | String,
default: 0
},
list: {
type: Array,
default: () => {
return [];
}
},
rangKey: {
type: String,
default: 'src'
},
// 是否内联。
inline: {
type: Boolean,
default: false
},
// 是否开启预览模式,即点击图片可以预览。
previmage: {
type: Boolean | String,
default: true
},
vertical: false,
circular: false,
autoplay: false,
interval: {
type: Number,
default: 3000
},
duration: {
type: Number,
default: 500
},
// 是否显示指示
indicatorDots: false,
//指示点的主题色。
color: {
type: String,
default: 'primary'
},
// 当前位置。
current: {
type: Number,
default: 0
},
ani3d: {
type: Number,
default: 0
},
// 指示点的类型。
dotModel: {
type: String,
default: 'dot' //dot|number|rect
},
// 指示点的位置 。
dotDirection: {
type: String,
default: 'center' //left|center|right
},
round: {
type: Boolean | Number,
default: 0
},
margin: {
type: Number,
default: 0
},
// 跟随主题色的改变而改变。
fllowTheme: {
type: Boolean | String,
default: true
}
},
watch: {
current: function(newval) {
// if (newval >= this.dataList.length) {
// this.nowIndex = 0;
// return;
// }
// this.nowIndex = newval;
},
list: {
deep: true,
handler() {
this.chulidata();
}
}
},
computed: {
color_tmeme: function() {
if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this.fllowTheme) {
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
round_num: function() {
if (typeof this.round === 'boolean') return 0;
return this.round;
},
nowIndex: {
get: function() {
return this.dotIndex;
}, },
set: function(val) { // 自定高度。
this.dotIndex = val; height: {
this.$emit('update:current', val); type: Number | String,
this.$emit('change', val); default: 0
}
},
nowshowDot: function() {
return this.showdot();
},
w_s: {
get: function() {
return this.w_w;
}, },
set: function(val) { list: {
this.w_w = val; type: Array,
} default: () => {
}, return [];
h_s: { }
get: function() {
return this.h_h;
}, },
set: function(val) { rangKey: {
this.h_h = val; type: String,
default: 'src'
},
// 是否内联。
inline: {
type: Boolean,
default: false
},
// 是否开启预览模式,即点击图片可以预览。
previmage: {
type: Boolean | String,
default: true
},
vertical: false,
circular: false,
autoplay: false,
interval: {
type: Number,
default: 3000
},
duration: {
type: Number,
default: 500
},
// 是否显示指示
indicatorDots: false,
//指示点的主题色。
color: {
type: String,
default: 'primary'
},
// 当前位置。
current: {
type: Number,
default: 0
},
ani3d: {
type: Number,
default: 0
},
// 指示点的类型。
dotModel: {
type: String,
default: 'dot' //dot|number|rect
},
// 指示点的位置 。
dotDirection: {
type: String,
default: 'center' //left|center|right
},
round: {
type: Boolean | Number,
default: 0
},
margin: {
type: Number,
default: 0
},
// 跟随主题色的改变而改变。
fllowTheme: {
type: Boolean | String,
default: true
} }
}, },
margin_px: function() { watch: {
return this.margin * 2; current: function(newval) {
} if (newval >= this.dataList.length) {
}, this.nowIndex = 0;
return;
data() { }
return { this.nowIndex = newval;
w_w: 0, },
h_h: 0, list: {
dataList: [], deep: true,
dotIndex: 0, handler() {
isPlayVedio: false this.chulidata();
}; }
},
async mounted() {
// this.nowIndex = this.current;
let w = this.width;
if (String(w).indexOf('px') > -1 && typeof w == 'string') {
let p = parseInt(h);
let sy = 750 / uni.getSystemInfoSync().windowWidth;
w = p * sy;
}
if (typeof w == 'string') {
w = parseInt(w);
}
this.w_w = w;
let h = this.height;
if (String(h).indexOf('px') > -1 && typeof h == 'string') {
let p = parseInt(h);
let sy = 750 / uni.getSystemInfoSync().windowWidth;
h = p * sy;
}
if (typeof h == 'string') {
h = parseInt(h);
}
this.h_h = h;
this.$nextTick(async function() {
await this.chulidata();
});
},
methods: {
showdot() {
if (typeof this.dataList[this.nowIndex] == 'string') return true;
if (typeof this.dataList[this.nowIndex] == 'object') {
if (this.dataList[this.nowIndex].dtype == 'video') return false;
} }
return true;
}, },
async chulidata() { computed: {
let t = this; color_tmeme: function() {
let tb = await this.$Querey('.tm-swiper', this).catch(ev => {}); if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
//console.log(uni.getSystemInfoSync()); .fllowTheme) {
let sy = 750 / uni.getSystemInfoSync().windowWidth; return this.$tm.vx.state().tmVuetify.color;
let upxw = tb[0].width * sy; }
let sw = this.w_s > 0 ? this.w_s : upxw > 0 ? upxw : 100; return this.color;
this.w_s = sw; },
let sh = this.h_s > 0 ? this.h_s : tb[0].height > 0 ? tb[0].height : 300; round_num: function() {
this.h_s = sh; if (typeof this.round === 'boolean') return 0;
let d = []; return this.round;
this.list.forEach(item => { },
if (typeof item === 'string') { nowIndex: {
d.push({ get: function() {
width: sw, return this.dotIndex;
height: sh, },
url: item, set: function(val) {
title: '', this.dotIndex = val;
dtype: '', this.$emit('update:current', val);
data: item this.$emit('change', val);
}); }
} else if (typeof item === 'object') { },
d.push({ nowshowDot:function(){
width: sw, return this.showdot();
height: sh,
url: item[t.rangKey], },
title: item['title'] || '', w_s: {
dtype: item['type'] || '', get: function() {
data: item return this.w_w;
},
set: function(val) {
this.w_w = val;
}
},
h_s: {
get: function() {
return this.h_h;
},
set: function(val) {
this.h_h = val;
}
},
margin_px: function() {
return this.margin * 2;
},
},
data() {
return {
w_w: 0,
h_h: 0,
dataList: [],
dotIndex: 0,
isPlayVedio:false,
};
},
async mounted() {
this.nowIndex = this.current;
let w = this.width;
if (String(w).indexOf('px') > -1 && typeof w == 'string') {
let p = parseInt(h);
let sy = 750 / uni.getSystemInfoSync().windowWidth;
w = p * sy;
}
if (typeof w == 'string') {
w = parseInt(w);
}
this.w_w = w;
let h = this.height;
if (String(h).indexOf('px') > -1 && typeof h == 'string') {
let p = parseInt(h);
let sy = 750 / uni.getSystemInfoSync().windowWidth;
h = p * sy;
}
if (typeof h == 'string') {
h = parseInt(h);
}
this.h_h = h;
this.$nextTick(async function() {
await this.chulidata();
});
},
methods: {
showdot(){
if(typeof this.dataList[this.nowIndex]=='string') return true;
if(typeof this.dataList[this.nowIndex]=='object'){
if(this.dataList[this.nowIndex].dtype=='video') return false;
}
return true;
},
async chulidata() {
let t = this;
let tb = await this.$Querey('.tm-swiper', this).catch(ev => {});
//console.log(uni.getSystemInfoSync());
let sy = 750 / uni.getSystemInfoSync().windowWidth;
let upxw = tb[0].width * sy;
let sw = this.w_s > 0 ? this.w_s : upxw > 0 ? upxw : 100;
this.w_s = sw;
let sh = this.h_s > 0 ? this.h_s : tb[0].height > 0 ? tb[0].height : 300;
this.h_s = sh;
let d = [];
this.list.forEach(item => {
if (typeof item === 'string') {
d.push({
width: sw,
height: sh,
url: item,
title: '',
dtype: '',
data: item
});
} else if (typeof item === 'object') {
d.push({
width: sw,
height: sh,
url: item[t.rangKey],
title: item['title'] || '',
dtype: item['type'] || '',
data: item
});
}
});
this.dataList = d;
},
imgload(e, index) {},
change(event) {
this.nowIndex = event.detail.current;
},
itemClick(e) {
if (this.previmage) {
uni.previewImage({
current: e.url,
urls: [e.url]
}); });
} }
}); this.$emit('click', e);
this.dataList = d;
},
imgload(e, index) {},
change(event) {
this.nowIndex = event.detail.current;
},
itemClick(e) {
if (this.previmage) {
uni.previewImage({
current: e.url,
urls: [e.url]
});
} }
this.$emit('click', e);
} }
} };
};
</script> </script>
<style></style> <style></style>
<style lang="scss" scoped> <style lang="scss" scoped>
.tm-swiper { .tm-swiper {
position: relative; position: relative;
.tm-swiper-ik { .tm-swiper-ik {
transition: all 1s; transition: all 1s;
}
.a3d {
transform: scale(0.76);
}
.a3dL {
transform: scale(0.76) translateX(-24rpx);
}
.a3dR {
transform: scale(0.76) translateX(24rpx);
}
.actvieMarginDh {
display: flex;
justify-content: center;
.actvieMarginDh-item {
overflow: hidden;
line-height: 0;
}
}
.tm-swiper-dot {
.tm-swiper-dot-item {
width: 16upx;
height: 16upx;
border-radius: 50%;
&.unactive {
background-color: rgba(255, 255, 255, 0.6);
}
&.number {
width: 34upx;
height: 34upx;
}
&.rect {
width: 24upx;
height: 6upx;
border-radius: 0;
}
&.round {
background-color: rgba(0, 0, 0, 0.4);
}
} }
width: 100%; .a3d {
position: absolute; transform: scale(0.76);
left: 0; }
display: flex;
bottom: 20upx;
&.center { .a3dL {
transform: scale(0.76) translateX(-24rpx)
}
.a3dR {
transform: scale(0.76) translateX(24rpx)
}
.actvieMarginDh {
display: flex; display: flex;
justify-content: center; justify-content: center;
.actvieMarginDh-item {
overflow: hidden;
line-height: 0;
}
} }
&.left { .tm-swiper-dot {
display: flex; .tm-swiper-dot-item {
justify-content: flex-start; width: 16upx;
padding-left: 20upx; height: 16upx;
width: calc(100% - 20upx); border-radius: 50%;
}
&.right { &.unactive {
background-color: rgba(255, 255, 255, 0.6);
}
&.number {
width: 34upx;
height: 34upx;
}
&.rect {
width: 24upx;
height: 6upx;
border-radius: 0;
}
&.round {
background-color: rgba(0, 0, 0, 0.4);
}
}
width: 100%;
position: absolute;
left: 0;
display: flex; display: flex;
justify-content: flex-end; bottom: 20upx;
padding-right: 20upx;
width: calc(100% - 20upx); &.center {
display: flex;
justify-content: center;
}
&.left {
display: flex;
justify-content: flex-start;
padding-left: 20upx;
width: calc(100% - 20upx);
}
&.right {
display: flex;
justify-content: flex-end;
padding-right: 20upx;
width: calc(100% - 20upx);
}
} }
} }
}
</style> </style>
@@ -13,7 +13,7 @@
* @property {Number} wait 延时 * @property {Number} wait 延时
* @property {String} animation-name = [fadeUp|fadeDown|fadeLeft|fadeRight|zoomIn|zoomOut|fadeIn|fadeOut] 动画效果名称. * @property {String} animation-name = [fadeUp|fadeDown|fadeLeft|fadeRight|zoomIn|zoomOut|fadeIn|fadeOut] 动画效果名称.
* @property {String|Boolean} auto = [true|false] 默认:true,是否自动播放动画. * @property {String|Boolean} auto = [true|false] 默认:true,是否自动播放动画.
* @example <tm-translate wait="500" animation-name="fadeUp"><tm-upload></tm-upload></tm-translate> * @example <tm-translate wait="500" animation-name="fadeDown"><tm-upload></tm-upload></tm-translate>
*/ */
export default { export default {
name:"tm-translate", name:"tm-translate",
+60 -35
View File
@@ -1,5 +1,5 @@
<template> <template>
<view class="tm-upload flex-start " id="tm-upload"> <view class="tm-upload flex-start relative" id="tm-upload">
<view v-for="(item,index) in list" :key="index" class="tm-upload-item " :class="[grid!=1?'ma-4':'']" :style="{ <view v-for="(item,index) in list" :key="index" class="tm-upload-item " :class="[grid!=1?'ma-4':'']" :style="{
width:itemWidth+'px', width:itemWidth+'px',
height:itemHeight+'px' height:itemHeight+'px'
@@ -31,9 +31,18 @@
<!-- 上传的进度 --> <!-- 上传的进度 -->
<view v-if="item.progress>0&&item.progress!=100&&!disabled" class="tm-upload-pro green" <view v-if="item.progress>0&&item.progress!=100&&!disabled" class="tm-upload-pro green"
:style="{width:item.progress+'%'}"></view> :style="{width:item.progress+'%'}"></view>
<!-- 上传的排序 -->
<view v-if="showSort" class="absolute l-0 fulled flex-between" :class="[disabled?'b-0':'b-40']" :style="{height:'46rpx'}">
<view @click.stop="prevSort(item,index,'prev')" class="round-r-24 flex-center px-16 py-6" :class="[index==0?'opacity-0':'']" style="background-color: rgba(0, 0, 0, 0.3);">
<tm-icons name="icon-angle-left" size="24" :color="color_tmeme"></tm-icons>
</view>
<view @click.stop="prevSort(item,index,'next')" class="round-l-24 flex-center px-16 py-6" :class="[index==list.length-1?'opacity-0':'']" style="background-color: rgba(0, 0, 0, 0.3);">
<tm-icons name="icon-angle-right" size="24" :color="color_tmeme"></tm-icons>
</view>
</view>
</view> </view>
<view @click="addfile" v-if="list.length<max&&!disabled&&showSheet" class="tm-upload-item ma-4 grey-lighten-4 " :class="[`round-${round}`]" :style="{ <view @click="addfile" v-if="list.length<max&&!disabled" class="tm-upload-item ma-4 grey-lighten-4 " :class="[`round-${round}`]" :style="{
width:itemWidth+'px', width:itemWidth+'px',
height:itemHeight+'px' height:itemHeight+'px'
}"> }">
@@ -79,6 +88,10 @@
components:{tmIcons}, components:{tmIcons},
name: "tm-upload", name: "tm-upload",
props: { props: {
showSort:{
type:Boolean|String,
default:false
},
model:{ model:{
type:String, type:String,
default:'scaleToFill' default:'scaleToFill'
@@ -216,8 +229,7 @@
itemWidth: 0, itemWidth: 0,
itemHeight: 0, itemHeight: 0,
list: [], list: [],
//兼容app使用.
showSheet:true,
upObje:null, upObje:null,
}; };
}, },
@@ -228,13 +240,51 @@
}, },
async mounted() { async mounted() {
let t = this; let t = this;
if (typeof t.filelist === 'object' && Array.isArray(t.filelist)) {
let plist = [...t.filelist];
plist.forEach((item, index) => {
let url = "";
if (typeof item === 'string') {
url = item;
} else if (typeof item === 'object') {
url = item[t.urlKey]
}
t.list.push({
url: url,
status: "上传成功",
progress: 100,
fileId: t.$tm.guid(),
statusCode: 3,
data: item,
})
})
this.$nextTick(async function(){ }
this.getRect()
this.$Querey('.tm-upload', this,30).then(o=>{
// #ifdef APP-VUE || APP-PLUS || MP },
t.showSheet = true; updated() {
// #endif this.getRect()
},
methods: {
prevSort(item,index,type){
if((index==0&&type=='prev')||(index==this.list.length-1&&type=='next')){
return;
}
let nowindex = type=='prev'?index-1:index+1
let nowItem = this.list[index];
let newnowItem = this.list[nowindex];
let nowfilelist= [...this.list]
nowfilelist.splice(index,1,newnowItem)
nowfilelist.splice(nowindex,1,nowItem)
this.list = [...nowfilelist]
this.$emit('update:filelist', nowfilelist);
},
getRect(){
let t = this;
this.$Querey('.tm-upload', this,0).then(o=>{
if(!o[0].width&&t.maxWidth) return;
t.maxWidth = o[0].width||t.width; t.maxWidth = o[0].width||t.width;
let itemWidth = (t.maxWidth - (parseInt(t.grid) - 1) * uni.upx2px(12)) / parseInt(t.grid); let itemWidth = (t.maxWidth - (parseInt(t.grid) - 1) * uni.upx2px(12)) / parseInt(t.grid);
t.itemWidth = itemWidth; t.itemWidth = itemWidth;
@@ -242,33 +292,8 @@
if (t.imgHeight > 0) { if (t.imgHeight > 0) {
t.itemHeight = parseInt(uni.upx2px(t.imgHeight)); t.itemHeight = parseInt(uni.upx2px(t.imgHeight));
} }
if (typeof t.filelist === 'object' && Array.isArray(t.filelist)) {
let plist = [...t.filelist];
plist.forEach((item, index) => {
let url = "";
if (typeof item === 'string') {
url = item;
} else if (typeof item === 'object') {
url = item[t.urlKey]
}
t.list.push({
url: url,
status: "上传成功",
progress: 100,
fileId: t.$tm.guid(),
statusCode: 3,
data: item,
})
})
}
}) })
}) },
},
methods: {
errorFile(item,index){ errorFile(item,index){
let id = item; let id = item;
id['loaderror'] = true; id['loaderror'] = true;
@@ -134,8 +134,10 @@
let day = nwod.getDate(); let day = nwod.getDate();
let week = nwod.getDay(); let week = nwod.getDay();
let new_weekDay = [nwod]; let new_weekDay = [nwod];
let timcha = Math.abs(week-7); let timcha = Math.abs(week-7);
let zcha = Math.abs(7-timcha); let zcha = Math.abs(7-timcha);
let weekCn=["周日","周一","周二","周三","周四","周五","周六"]; let weekCn=["周日","周一","周二","周三","周四","周五","周六"];
for(let i=1;i<zcha;i++){ for(let i=1;i<zcha;i++){
let d = new Date(year,month,day-i); let d = new Date(year,month,day-i);
@@ -157,9 +159,17 @@
} }
weekDay.push(sc); weekDay.push(sc);
} }
weekDay.sort(function(a, b){return a.week - b.week}); weekDay.sort(function(a, b){return a.week - b.week});
weekDay.push(weekDay[0]) weekDay.push(weekDay[0])
weekDay.splice(0,1) weekDay.splice(0,1)
if(weekDay.length==8){
weekDay.splice(0,1)
weekDay.unshift(weekDay[weekDay.length-1])
weekDay.splice(weekDay.length-1,1)
}
let t= this; let t= this;
this.timeList = []; this.timeList = [];
this.$nextTick(function(){ this.$nextTick(function(){
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "tm-vuetify", "id": "tm-vuetify",
"displayName": "tmUI-vuetify", "displayName": "tmUI-vuetify",
"version": "2.0.0", "version": "2.0.1",
"description": "tm-vuetify是一个新势力由主题驱动的UI组件库,相比其它优势大,组件全,设计趋势紧跟未来。具有主题生成,主题实时切换,暗黑实时切换,lottie动画,图表等新颖功能,tmui TMUI", "description": "tm-vuetify是一个新势力由主题驱动的UI组件库,相比其它优势大,组件全,设计趋势紧跟未来。具有主题生成,主题实时切换,暗黑实时切换,lottie动画,图表等新颖功能,tmui TMUI",
"keywords": [ "keywords": [
"tmUI-vuetify", "tmUI-vuetify",
+8 -8
View File
@@ -9,20 +9,20 @@
/**用户自定主题,默认主题,不可删除,可通过工具生成覆盖**/ /**用户自定主题,默认主题,不可删除,可通过工具生成覆盖**/
@import "./theme/amber.css"; @import "./theme/amber.css";
@import "./theme/blue.css"; @import "./theme/blue.css";
@import "./theme/brown.css"; /* @import "./theme/brown.css"; */
@import "./theme/cyan.css"; @import "./theme/cyan.css";
@import "./theme/green.css"; @import "./theme/green.css";
@import "./theme/indigo.css"; /* @import "./theme/indigo.css"; */
@import "./theme/lime.css"; /* @import "./theme/lime.css"; */
@import "./theme/orange.css"; @import "./theme/orange.css";
@import "./theme/pink.css"; /* @import "./theme/pink.css"; */
@import "./theme/purple.css"; /* @import "./theme/purple.css"; */
@import "./theme/red.css"; @import "./theme/red.css";
/**组件库,必要的主题,不可删除**/ /**组件库,必要的主题,不可删除**/
@import "./theme/teal.css"; /* @import "./theme/teal.css"; */
@import "./theme/yellow.css"; @import "./theme/yellow.css";
@import "./theme/blue-grey.css"; @import "./theme/blue-grey.css";
@import "./theme/deep-orange.css"; @import "./theme/deep-orange.css";
@import "./theme/deep-purple.css"; /*@import "./theme/deep-purple.css";*/
@import "./theme/light-blue.css"; @import "./theme/light-blue.css";
@import "./theme/light-green.css"; /*@import "./theme/light-green.css"; */
@@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_plugin_calendar=t()}(this,(function(){"use strict";return function(e,t,a){var n="h:mm A",d={lastDay:"[Yesterday at] "+n,sameDay:"[Today at] "+n,nextDay:"[Tomorrow at] "+n,nextWeek:"dddd [at] "+n,lastWeek:"[Last] dddd [at] "+n,sameElse:"MM/DD/YYYY"};t.prototype.calendar=function(e,t){var n=t||this.$locale().calendar||d,o=a(e||void 0).startOf("d"),s=this.diff(o,"d",!0),i="sameElse",f=s<-6?i:s<-1?"lastWeek":s<0?"lastDay":s<1?"sameDay":s<2?"nextDay":s<7?"nextWeek":i,l=n[f]||d[f];return"function"==typeof l?l.call(this,a()):this.format(l)}}}));
+1 -1
View File
@@ -4,4 +4,4 @@
* *
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/ */
!function(e,_){"object"==typeof exports&&"undefined"!=typeof module?module.exports=_(require("./dayjs.min")):"function"==typeof define&&define.amd?define(["dayjs"],_):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_locale_zh_cn=_(e.dayjs)}(this,(function(e){"use strict";function _(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var t=_(e),d={name:"zh-cn",weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),ordinal:function(e,_){switch(_){case"W":return e+"周";default:return e+"日"}},weekStart:1,yearStart:4,formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},relativeTime:{future:"%s后",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},meridiem:function(e,_){var t=100*e+_;return t<600?"凌晨":t<900?"早上":t<1100?"上午":t<1300?"中午":t<1800?"下午":"晚上"}};return t.default.locale(d,null,!0),d})); !function(e,_){"object"==typeof exports&&"undefined"!=typeof module?module.exports=_(require("./dayjs.min")):"function"==typeof define&&define.amd?define(["./dayjs.min"],_):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_locale_zh_cn=_(e.dayjs)}(this,(function(e){"use strict";function _(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var t=_(e),d={name:"zh-cn",weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),ordinal:function(e,_){switch(_){case"W":return e+"周";default:return e+"日"}},weekStart:1,yearStart:4,formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},relativeTime:{future:"%s后",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},meridiem:function(e,_){var t=100*e+_;return t<600?"凌晨":t<900?"早上":t<1100?"上午":t<1300?"中午":t<1800?"下午":"晚上"}};return t.default.locale(d,null,!0),d}));
+1
View File
@@ -5,6 +5,7 @@
*/ */
function sleep(wait=500){ function sleep(wait=500){
let timid = null; let timid = null;
if(wait==0) return Promise.resolve(true)
clearTimeout(timid); clearTimeout(timid);
return new Promise((res,rej)=>{ return new Promise((res,rej)=>{
timid = setTimeout(function() { timid = setTimeout(function() {
+1
View File
@@ -197,4 +197,5 @@ export default {
chinaPost, chinaPost,
password, password,
password2, password2,
bankCard
} }
+4 -4
View File
@@ -19,16 +19,16 @@ class vuex {
let t = this; let t = this;
const g = this.store.getters const g = this.store.getters
let keys = Object.keys(g); let keys = Object.keys(g);
console.log(keys)
let k = keys.map((el,index)=>{ let k = keys.map((el,index)=>{
let f = el.split('/'); let f = el.split('/');
let tst = {} let tst = {}
if(f.length==1){ if(f.length==1){
tst[el]=g[el] tst[el]=g[el]
}else{ }else{
tst[f[1]]=g[el]
tst[f[0]]={} // tst[f[0]+'_'+f[1]]=g[el]
tst[f[0]][f[1]] = g[el] // tst[f[0]][f[1]] = g[el]
} }
return tst return tst
+1
View File
@@ -55,6 +55,7 @@ const store = new Vuex.Store({
// $tm:state=>{ // $tm:state=>{
// return $tm; // return $tm;
// } // }
}, },
mutations: { mutations: {
setTmVuetifyColor(state, color) { setTmVuetifyColor(state, color) {
-5
View File
@@ -1,5 +0,0 @@
## 2.3.32022-07-14
1.添加空数据图点击事件回调。
2.修复在nvue中偶现的下拉刷新回弹跳动的问题。
3.修复在nvue中偶现的slot="top"挡住下拉刷新view的问题。
4.禁止在h5中滚动到底部时上拉手势冒泡,以避免由此引发的列表被短暂锁住无法滚动的问题。
@@ -1,34 +0,0 @@
<!-- z-paging -->
<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群790460711 -->
<!-- z-paging-cell用于在nvue中使用cell包裹vue中使用view包裹 -->
<template>
<!-- #ifdef APP-NVUE -->
<cell :style="[cellStyle]">
<slot />
</cell>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view :style="[cellStyle]">
<slot />
</view>
<!-- #endif -->
</template>
<script>
export default {
name: "z-paging-cell",
props: {
//cellStyle
cellStyle: {
type: Object,
default: function() {
return {}
}
}
}
}
</script>

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