Compare commits
No commits in common. "main" and "master" have entirely different histories.
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.out
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.pem
|
||||||
|
*.log
|
||||||
|
*.glb
|
||||||
|
*.zip
|
||||||
|
*.rar
|
||||||
|
*.pdf
|
||||||
|
*.docx
|
||||||
|
*.xls
|
||||||
|
*.doc
|
||||||
|
*.gltf
|
||||||
|
*.mp3
|
||||||
|
*.mp4
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
资料/*
|
||||||
|
web/ud/docs/*
|
||||||
|
web/ud/2025/*
|
||||||
|
web/ud/2026/*
|
||||||
|
web/ud/2027/*
|
||||||
|
web/ud/2028/*
|
||||||
|
**/unpackage/
|
||||||
|
**/tmp/
|
||||||
|
web.ini
|
||||||
|
gitup.bat
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "ciyon main",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceRoot}",
|
||||||
|
"env": {},
|
||||||
|
"args": [],
|
||||||
|
"showLog": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"editor.unicodeHighlight.includeComments": false,
|
||||||
|
"editor.unicodeHighlight.includeStrings": false
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "刷新CDN缓存",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "node ../../nodejs/refreshcdn/refreshcdn.js ${workspaceFolder}",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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.
|
||||||
|
|
||||||
|
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 convey 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 an idea of what it does. Copyright (C) yyyy name of author
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice
|
||||||
173
README.md
173
README.md
|
|
@ -1,3 +1,172 @@
|
||||||
# KunWeb_ai
|
# Ciyon - 众产全栈开发框架
|
||||||
|
## 技术特点
|
||||||
|
### AI辅助决策
|
||||||
|
基于Function Call和JSON的AI能力,实现了定期AI决策及渐进式主动决策执行能力。
|
||||||
|
|
||||||
|
利用置信度缓解AI幻觉难题,基于量化函数可实现专用AI能力。
|
||||||
|
|
||||||
|
### Web3D地球
|
||||||
|
基于Cesium与ThreeJS,实现了三维场景可视化配置和开发JS独立组件。
|
||||||
|
|
||||||
|
支持多种地图源、地形图、GLB模型、光照、无人机建模等。
|
||||||
|
|
||||||
|
### 原生重构组件
|
||||||
|
内生发展,尽量不引用第三方库,拆解掌握原理后重写。
|
||||||
|
|
||||||
|
PC端组件20+,移动端组件60+,不断扩展中。
|
||||||
|
|
||||||
|
### PHP+Golang
|
||||||
|
PHP在项目原型验证阶段快速开发上线。
|
||||||
|
|
||||||
|
Golang作为服务器集群降成本的高并发优化。
|
||||||
|
|
||||||
|
### 免编译模式
|
||||||
|
尽量用免编译模式开发,降低老旧代码维护难度。
|
||||||
|
|
||||||
|
是未来演进的重要研究基础。
|
||||||
|
|
||||||
|
### 代码生成器
|
||||||
|
支持基于数据表的通用功能的代码生成能力。
|
||||||
|
|
||||||
|
数据表注解定义,自动生成代码,再利用AI补全微调。
|
||||||
|
|
||||||
|
遵循一定的开发规范,能产生90%高质量直接运行代码。
|
||||||
|
|
||||||
|
|
||||||
|
## 软件架构
|
||||||
|
### 总控端原生JS
|
||||||
|
使用原生JS实现一系列的常用函数封装。
|
||||||
|
|
||||||
|
包括websocket、bigscreen、openai、sse、i18n等。
|
||||||
|
|
||||||
|
结合Web3D的数据大屏驾驶舱示例代码实现。
|
||||||
|
|
||||||
|
### 总控端PHP
|
||||||
|
原生实现独立开发框架,输入安全校验、唯一访问入口。
|
||||||
|
|
||||||
|
拆解吸收多种大型框架源码。本框架结构简单,可读性强。
|
||||||
|
|
||||||
|
### 总控端Golang
|
||||||
|
原生实现独立开发框架,未实现函数自动转至PHP执行。
|
||||||
|
|
||||||
|
支持mock、连接池、自更新等。
|
||||||
|
|
||||||
|
### 移动端Vue3
|
||||||
|
在Vue3基础上极简封装各类常用组件。
|
||||||
|
|
||||||
|
统一封装常见函数,页面全面可自定义,多语言。
|
||||||
|
|
||||||
|
提供路由工具,一键生成路由代码。
|
||||||
|
|
||||||
|
### Web站原生JS库
|
||||||
|
让Web呈现扁平的价值传达,减少酷炫效果对阅读的干扰,整站SEO可完整解析。
|
||||||
|
|
||||||
|
### Web站缓存机制
|
||||||
|
自定义的动态页面缓存模式,结合各类CDN回源策略减轻对源服务器请求。
|
||||||
|
|
||||||
|
|
||||||
|
## 软件工程
|
||||||
|
### 项目可行性验证阶段
|
||||||
|
用原生JS+PHP+微信小程序开发。
|
||||||
|
|
||||||
|
在数周内完成项目快速开发。
|
||||||
|
|
||||||
|
低成本投入市场验证迭代。
|
||||||
|
|
||||||
|
### 项目快速发展阶段
|
||||||
|
Web服务器集群规模或数据库服务器连接数承压后,
|
||||||
|
|
||||||
|
用Golang重写高并发请求的函数接口,逐步替代。
|
||||||
|
|
||||||
|
### 项目稳定运营阶段
|
||||||
|
Golang将业务侧数据全部重写,完全替换PHP低效代码。
|
||||||
|
|
||||||
|
根据业务特点拆分,扩展成多地多中心异构拓扑。
|
||||||
|
|
||||||
|
|
||||||
|
## 未来演进
|
||||||
|
### 全量区块链
|
||||||
|
创新的实现区块链底层架构,将上传的文件图片视频资源、数据库资源全部完整上链。
|
||||||
|
|
||||||
|
非简单的hash上链。
|
||||||
|
|
||||||
|
### 后端智能合约化
|
||||||
|
后端研发基于区块链JS智能合约,
|
||||||
|
|
||||||
|
实现统一的前端JS访问入口,实现区块链级事务。
|
||||||
|
|
||||||
|
### 大前端上链
|
||||||
|
从区块链上下载前端代码包,加载到用户端(PC/手机/XR眼镜等),任何交互操作均直接请求区块链智能合约。
|
||||||
|
|
||||||
|
### 代码可审计
|
||||||
|
区块链基于共识算法开放协议,天然可审计。
|
||||||
|
|
||||||
|
前端代码及后端智能合约不允许混淆和编译。
|
||||||
|
|
||||||
|
用户端可随时调阅源码分析。
|
||||||
|
|
||||||
|
|
||||||
|
# 在线演示
|
||||||
|
|
||||||
|
https://ciyon.ciy.cn/
|
||||||
|
https://ciyon.ciy.cn/admin/
|
||||||
|
|
||||||
|
# Windows开发环境部署
|
||||||
|
[详见教程](https://ciyon.ciy.cn/docs/#100)
|
||||||
|
|
||||||
|
部署软件: Nginx、PHP、MariaDB、Golang
|
||||||
|
建议安装: Git、python3、node.js
|
||||||
|
开发IDE: VSCode(Cursor/Claude Code/Antigravity)、UniAPP、微信开发者工具
|
||||||
|
开发工具: Navicat、WinSCP5、Google Chrome、S3 Browser、Apifox
|
||||||
|
效率工具: XMind、WPS Office、Everything、ToDesk
|
||||||
|
网络工具: SocketTool、MQTT-Explorer
|
||||||
|
|
||||||
|
# Linux生产环境部署
|
||||||
|
[详见教程](https://ciyon.ciy.cn/docs/#102)
|
||||||
|
操作系统: Debian
|
||||||
|
运维工具: Navicat、WinSCP5+、S3 Browser
|
||||||
|
|
||||||
|
# 重要更新记录
|
||||||
|
|
||||||
|
## 2026.03.01
|
||||||
|
- 升级: 增加总控MCP和用户MCP通用接口
|
||||||
|
|
||||||
|
## 2026.02.02
|
||||||
|
- 升级: 路由重构,支持软路由,需结合Nginx配置
|
||||||
|
|
||||||
|
## 2025.12.01
|
||||||
|
- 里程碑: 众产事业平台上线
|
||||||
|
|
||||||
|
## 2025.09.06
|
||||||
|
- 文档: 编写移动端 Demo代码
|
||||||
|
|
||||||
|
## 2025.08.25
|
||||||
|
- 文档: docs文档整理
|
||||||
|
|
||||||
|
## 2025.06.12
|
||||||
|
- 文档: Ciyon文档上线,文档整理
|
||||||
|
|
||||||
|
## 2025.05.16
|
||||||
|
- 新增: Ciyon官网上线、Git内部公开发布
|
||||||
|
|
||||||
|
## 2025.04.06
|
||||||
|
- 文档: 编写PC Demo代码
|
||||||
|
|
||||||
|
## 2025.02.20
|
||||||
|
- 升级: 移动端Vue3框架所有组件完成去依赖
|
||||||
|
|
||||||
|
## 2024.12.26
|
||||||
|
- 新增: AI辅助决策。支持多轮AI任务
|
||||||
|
|
||||||
|
## 2024.10.05
|
||||||
|
- 新增: Web3D地编器及ciyearth.js组件库
|
||||||
|
|
||||||
|
## 2024.08.30
|
||||||
|
- 新增: Golang语言开发模式
|
||||||
|
|
||||||
|
## 2024.05.21
|
||||||
|
- 升级: 移动端Vue3/Uniapp兼容框架(原Vue2框架废弃)
|
||||||
|
|
||||||
|
## 2024.03.12
|
||||||
|
- 里程碑: 基于CIYPHP重写开发SaaS框架
|
||||||
|
|
||||||
进行ai_seo
|
|
||||||
|
|
@ -0,0 +1,933 @@
|
||||||
|
# Ciyon PC前端开发指南
|
||||||
|
|
||||||
|
## 框架概述
|
||||||
|
|
||||||
|
Ciyon是一个轻量级、高性能的PC前端开发框架,采用原生JavaScript开发,不依赖第三方库(如Vue、React、jQuery),专注于企业级后台管理系统和SaaS应用的快速开发。
|
||||||
|
|
||||||
|
### 核心特点
|
||||||
|
|
||||||
|
- **零依赖**: 纯原生JavaScript,无第三方库依赖
|
||||||
|
- **组件化**: 提供丰富的表单组件和业务组件
|
||||||
|
- **高性能**: 优化的DOM操作和事件处理
|
||||||
|
- **响应式**: 支持多端适配(PC、平板、手机)
|
||||||
|
- **国际化**: 内置多语言支持
|
||||||
|
- **主题系统**: CSS变量实现主题切换
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 框架架构
|
||||||
|
|
||||||
|
### 核心库文件
|
||||||
|
|
||||||
|
```
|
||||||
|
web/jscss/
|
||||||
|
├── ciy.js # 基础工具库和DOM操作
|
||||||
|
├── ciycmp.js # 表单组件库
|
||||||
|
├── ciycmp2.js # 扩展组件库
|
||||||
|
├── ciytable.js # 表格和列表组件
|
||||||
|
├── ciybigscreen.js # 数据大屏组件
|
||||||
|
├── ciy_websocket.js # WebSocket通信
|
||||||
|
├── style.css # 核心样式
|
||||||
|
└── theme.js # 暗黑模式
|
||||||
|
```
|
||||||
|
|
||||||
|
### 设计模式
|
||||||
|
|
||||||
|
#### DOM封装模式
|
||||||
|
|
||||||
|
框架使用 `$5()` 函数替代jQuery,提供统一的DOM操作接口:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 选择元素
|
||||||
|
var dom = $5('.class-name');
|
||||||
|
|
||||||
|
// 链式调用
|
||||||
|
dom.css({color: 'red'}).addClass('active').show();
|
||||||
|
|
||||||
|
// 事件绑定
|
||||||
|
dom.on('click', function(e) {
|
||||||
|
console.log('clicked');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 组件化模式
|
||||||
|
|
||||||
|
使用自定义标签和 `ciycmp()` 函数初始化组件:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-datetime com="starttime" value="2026-01-01"></ciy-datetime>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
ciycmp({
|
||||||
|
dom: '[com=starttime]',
|
||||||
|
type: 'datetime',
|
||||||
|
onchange: function(e) {
|
||||||
|
console.log('selected:', e.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 面向对象模式
|
||||||
|
|
||||||
|
使用类封装复杂功能:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var table = new ciyclass.table({
|
||||||
|
dom: '.table',
|
||||||
|
url: 'api/list',
|
||||||
|
pagecount: 20,
|
||||||
|
fn_done: function(json) {
|
||||||
|
console.log('data loaded');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
table.callpage(1);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 组件体系
|
||||||
|
|
||||||
|
### 表单组件
|
||||||
|
|
||||||
|
#### 日期时间选择器(ciy-datetime)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-datetime com="date1" type="date" value="2026-01-01"></ciy-datetime>
|
||||||
|
<ciy-datetime com="datetime1" type="datetime" value="2026-01-01 12:00"></ciy-datetime>
|
||||||
|
<ciy-datetime com="month1" type="month" value="2026-01"></ciy-datetime>
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性说明**:
|
||||||
|
- `com`: 组件名称(必填)
|
||||||
|
- `type`: 类型(date/datetime/month)
|
||||||
|
- `value`: 初始值(时间戳或日期字符串)
|
||||||
|
- `mindate`: 最小日期
|
||||||
|
- `maxdate`: 最大日期
|
||||||
|
- `placeholder`: 占位文本
|
||||||
|
|
||||||
|
#### 日期范围选择器(ciy-daterange)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-daterange com="daterange1" type="date" value="2026-01-01~2026-12-31"></ciy-daterange>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出格式**:`开始日期~结束日期`
|
||||||
|
|
||||||
|
#### 下拉选择框(ciy-select)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-select com="status1" range="auditstatus" all="全部"></ciy-select>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
ciycmp({
|
||||||
|
dom: '[com=status1]',
|
||||||
|
range: 'auditstatus', // 字典key
|
||||||
|
all: '全部', // 第一项
|
||||||
|
filter: {field: 'upid', value: 0}, // 过滤条件
|
||||||
|
onchange: function(e) {
|
||||||
|
console.log('selected:', e.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 多选下拉框(ciy-selmulti)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-selmulti com="tags1" range="tags"></ciy-selmulti>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出格式**:`,id1,id2,id3,`
|
||||||
|
|
||||||
|
#### 级联选择框(ciy-selcas)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-selcas com="region1" range="region"></ciy-selcas>
|
||||||
|
```
|
||||||
|
|
||||||
|
用于省市区级联选择。
|
||||||
|
|
||||||
|
#### 开关(ciy-switch)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-switch com="enable1" value="1"></ciy-switch>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出值**:`1`(开启)/ `2`(关闭)
|
||||||
|
|
||||||
|
#### 单位编辑器(ciy-inputunitedit)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-inputunitedit com="unit1" value="瓶|24|盒|20|箱"></ciy-inputunitedit>
|
||||||
|
```
|
||||||
|
|
||||||
|
用于三级单位换算,如:1箱=20盒,1盒=24瓶。
|
||||||
|
|
||||||
|
#### 地图选择器(ciy-map)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-map com="location1" value="116.404,39.915"></ciy-map>
|
||||||
|
```
|
||||||
|
|
||||||
|
输出经纬度:`lng,lat`
|
||||||
|
|
||||||
|
#### 文本编辑器(ciy-textarea)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-textarea com="content1" max="1000"></ciy-textarea>
|
||||||
|
```
|
||||||
|
|
||||||
|
支持Tab键、字数统计、@用户提示。
|
||||||
|
|
||||||
|
#### 文件上传(ciy-upload)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-upload com="file1" type="jpg,png" maxcount="1"></ciy-upload>
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性说明**:
|
||||||
|
- `type`: 允许的文件类型
|
||||||
|
- `maxcount`: 最大上传数量
|
||||||
|
- `maxkb`: 文件大小限制(KB)
|
||||||
|
|
||||||
|
### 列表组件
|
||||||
|
|
||||||
|
#### 表格组件(ciyclass.table)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="table">
|
||||||
|
<div class="list">
|
||||||
|
<!-- 表格内容自动生成 -->
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="btmbtn"></div>
|
||||||
|
<div>
|
||||||
|
<div class="btmbtn"></div>
|
||||||
|
<div class="page"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var table = new ciyclass.table({
|
||||||
|
dom: '.table',
|
||||||
|
url: 'list',
|
||||||
|
pagecount: 20,
|
||||||
|
fn_tdcontent: function(key, value, field, row, json) {
|
||||||
|
// 自定义单元格内容
|
||||||
|
if (key == 'status') {
|
||||||
|
return '<span class="tag">' + value + '</span>';
|
||||||
|
}
|
||||||
|
// 自定义操作按钮
|
||||||
|
if (key == '_btn') {
|
||||||
|
var html = '';
|
||||||
|
html += `<a class="btn def" onclick="menubtn(this, 'view')">查看</a>`;
|
||||||
|
// 根据需求添加或删除按钮
|
||||||
|
// html += `<a class="btn" onclick="menubtn(this, 'edit')">修改</a>`;
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
fn_done: function(json, post) {
|
||||||
|
// 数据加载完成回调
|
||||||
|
}
|
||||||
|
});
|
||||||
|
table.callpage(1);
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**功能特性**:
|
||||||
|
- 动态列配置
|
||||||
|
- 列宽调整记忆
|
||||||
|
- 列排序
|
||||||
|
- 列隐藏
|
||||||
|
- 行选择
|
||||||
|
- 分页
|
||||||
|
- 搜索
|
||||||
|
- 顶部选项卡筛选
|
||||||
|
|
||||||
|
**顶部选项卡筛选**:使用 `fillsearch` 的 `lidata` 参数添加顶部选项卡,`liall` 设置"全部"选项的文本:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
table = new ciyclass.table({
|
||||||
|
dom: '.table',
|
||||||
|
url: 'list',
|
||||||
|
pagecount: 20,
|
||||||
|
fn_beforedata: function(json) {
|
||||||
|
ciyfn.fillsearch({
|
||||||
|
searchdom: '.search',
|
||||||
|
data: json,
|
||||||
|
liall: '全部',
|
||||||
|
lidata: [
|
||||||
|
{id: 1, name: '未使用'},
|
||||||
|
{id: 2, name: '已使用'}
|
||||||
|
],
|
||||||
|
//lidata: '【字典代码】', // 引用字典写法
|
||||||
|
//lidata: ':全部.1:未使用.2:已使用', //数组简写
|
||||||
|
liclick: function(dom) {
|
||||||
|
table.search(dom, 'li');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**liid编号**:自定义标识值应从1开始,不要使用0。
|
||||||
|
|
||||||
|
**后端处理**:在 `setwhere` 函数中根据 `liid` 参数进行筛选。
|
||||||
|
|
||||||
|
#### 卡片列表(ciyclass.cardtable)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="table">
|
||||||
|
<ul class="list row">
|
||||||
|
<!-- 卡片内容自动生成 -->
|
||||||
|
</ul>
|
||||||
|
<div>
|
||||||
|
<div class="btmbtn"></div>
|
||||||
|
<div class="page"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var table = new ciyclass.cardtable({
|
||||||
|
dom: '.table',
|
||||||
|
url: 'api/list',
|
||||||
|
pagecount: 9,
|
||||||
|
fn_lihtml: function(ldat) {
|
||||||
|
return `<li data-id="${ldat.id}">
|
||||||
|
<div class="ciy-list">
|
||||||
|
<div class="l1">${ldat.name}</div>
|
||||||
|
<div class="l2">${ldat.memo}</div>
|
||||||
|
</div>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
table.callpage(1);
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 功能组件
|
||||||
|
|
||||||
|
#### 弹窗(ciyfn.alert)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
ciyfn.alert({
|
||||||
|
title: '提示',
|
||||||
|
content: '操作成功',
|
||||||
|
btn: ['确定', '取消'],
|
||||||
|
cb: function(opn) {
|
||||||
|
if (opn.btn == '确定') {
|
||||||
|
// 确定操作
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Toast提示(ciyfn.toast)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
ciyfn.toast('操作成功');
|
||||||
|
ciyfn.toast('操作失败', 'error');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 选项卡(ciyfn.tabcard)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="ciy-tabcard">
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab active">标签1</div>
|
||||||
|
<div class="tab">标签2</div>
|
||||||
|
</div>
|
||||||
|
<div class="contents">
|
||||||
|
<div class="content active">内容1</div>
|
||||||
|
<div class="content">内容2</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开发规范
|
||||||
|
|
||||||
|
### HTML结构规范
|
||||||
|
|
||||||
|
#### 标准页面结构
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="/jscss/style.css" rel="stylesheet">
|
||||||
|
<script src="/jscss/theme.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<!-- 搜索表单 -->
|
||||||
|
<form class="search" onsubmit="table.search(this,'btn');return false;">
|
||||||
|
<div>
|
||||||
|
<div class="sinps">
|
||||||
|
<div class="ciy-form">
|
||||||
|
<label>状态</label>
|
||||||
|
<div><ciy-select com="status" range="status"></ciy-select></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sbtns">
|
||||||
|
<button class="btn" type="submit">查询</button>
|
||||||
|
<a class="btn" onclick="edit(0)">添加</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- 列表区域 -->
|
||||||
|
<div class="table">
|
||||||
|
<div class="list"></div>
|
||||||
|
<div>
|
||||||
|
<div class="btmbtn"></div>
|
||||||
|
<div class="page"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/jscss/ciy.js"></script>
|
||||||
|
<script src="/jscss/ciycmp.js"></script>
|
||||||
|
<script src="/jscss/ciycmp2.js"></script>
|
||||||
|
<script src="/jscss/ciytable.js"></script>
|
||||||
|
<script src="./common.js"></script>
|
||||||
|
<script>
|
||||||
|
// 页面逻辑
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 表单结构
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="ciy-form">
|
||||||
|
<label>字段名称</label>
|
||||||
|
<div>
|
||||||
|
<ciy-select com="field" range="dict"></ciy-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### JavaScript编码规范
|
||||||
|
|
||||||
|
#### 页面初始化
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var table;
|
||||||
|
ciyfn.pageload(function() {
|
||||||
|
// 初始化组件
|
||||||
|
ciycmp({
|
||||||
|
dom: '[com=status]',
|
||||||
|
range: 'status',
|
||||||
|
all: '全部'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化表格
|
||||||
|
table = new ciyclass.table({
|
||||||
|
dom: '.table',
|
||||||
|
url: 'api/list',
|
||||||
|
pagecount: 20
|
||||||
|
});
|
||||||
|
table.callpage(1);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 组件初始化
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 标准初始化
|
||||||
|
ciycmp({
|
||||||
|
dom: '[com=component]',
|
||||||
|
range: 'dictionary',
|
||||||
|
value: '1',
|
||||||
|
onchange: function(e) {
|
||||||
|
console.log('changed:', e.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 事件处理
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用$5绑定事件
|
||||||
|
$5('.btn-save').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
// 保存逻辑
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用原生addEventListener
|
||||||
|
document.querySelector('.btn-save').addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
// 保存逻辑
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### API调用
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
ciyfn.callfunc('api/admin.update', {
|
||||||
|
id: 1,
|
||||||
|
name: 'test'
|
||||||
|
}, function(json) {
|
||||||
|
//返回code:1,成功回调
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 表单获取
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var form = ciyfn.getform('.search');
|
||||||
|
console.log(form);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 样式规范
|
||||||
|
|
||||||
|
#### CSS变量
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
/* 主色 */
|
||||||
|
--man3: #d7eeff;
|
||||||
|
--man4: #80c1f3;
|
||||||
|
--man5: #1E9FFF;
|
||||||
|
--man6: #1e89db;
|
||||||
|
--man7: #8568f7;
|
||||||
|
--mant: #ffffff;
|
||||||
|
|
||||||
|
/* 成功色 */
|
||||||
|
--succ5: #03a547;
|
||||||
|
--succ6: #048238;
|
||||||
|
--succt: #ffffff;
|
||||||
|
|
||||||
|
/* 警示色 */
|
||||||
|
--warn5: #e39725;
|
||||||
|
--warn6: #b97a1c;
|
||||||
|
--warnt: #ffffff;
|
||||||
|
|
||||||
|
/* 失败色 */
|
||||||
|
--dag5: #e34242;
|
||||||
|
--dag6: #bd2525;
|
||||||
|
--dagt: #ffffff;
|
||||||
|
|
||||||
|
/* 文字色 */
|
||||||
|
--txt1: #8c9ba4;
|
||||||
|
--txt2: #818e97;
|
||||||
|
--txt3: #738088;
|
||||||
|
--txt4: #646e76;
|
||||||
|
--txt5: #576067;
|
||||||
|
--txt6: #454d52;
|
||||||
|
--txt7: #2c3236;
|
||||||
|
--txt8: #060708;
|
||||||
|
--txt9: #000000;
|
||||||
|
|
||||||
|
/* 背景色 */
|
||||||
|
--bg1: #ffffff;
|
||||||
|
--bg2: #fbfbfc;
|
||||||
|
--bg3: #f7f8f8;
|
||||||
|
--bg4: #f0f2f2;
|
||||||
|
--bg5: #e3e6e7;
|
||||||
|
--bg6: #cdd2d4;
|
||||||
|
--bg7: #afb6b9;
|
||||||
|
--bg8: #939da1;
|
||||||
|
--bg9: #7e8a8e;
|
||||||
|
|
||||||
|
|
||||||
|
/* 其他css变量 */
|
||||||
|
--e-scroll: rgba(0, 0, 0, 0.2);
|
||||||
|
--e-tabselect: #fffec5;
|
||||||
|
--e-dialog: 2px 2px 20px -10px #000000;
|
||||||
|
--e-inputbg: #f7f7f7;
|
||||||
|
--e-inputbr: #ffffff;
|
||||||
|
--e-switchtxt: #2c3236;
|
||||||
|
--e-inputshadow: 0 1px 3px 0 #00000042;
|
||||||
|
--e-menusec: 0.5s;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应式断点
|
||||||
|
|
||||||
|
```css
|
||||||
|
@media (max-width: 767px) { /* 手机 */ }
|
||||||
|
@media (max-width: 991px) { /* 平板 */ }
|
||||||
|
@media (min-width: 576px) { /* 平板及以上 */ }
|
||||||
|
@media (min-width: 992px) { /* PC */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后端交互
|
||||||
|
|
||||||
|
### API调用规范
|
||||||
|
|
||||||
|
#### 标准请求格式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
ciyfn.callfunc('/admin/user.update', {
|
||||||
|
param1: 'value1',
|
||||||
|
param2: 'value2'
|
||||||
|
}, function(json) {
|
||||||
|
// 处理响应
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 标准响应格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 1,
|
||||||
|
"msg": "成功",
|
||||||
|
"data": {},
|
||||||
|
"list": [],
|
||||||
|
"count": 100,
|
||||||
|
"pageno": 1,
|
||||||
|
"once": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 认证机制
|
||||||
|
|
||||||
|
框架使用JWT进行用户认证,Token存储在Cookie或LocalStorage中。
|
||||||
|
```
|
||||||
|
// 获取
|
||||||
|
var me = ciyfn.getstorage(ciy_vars.tokenfield);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 权限控制
|
||||||
|
|
||||||
|
```
|
||||||
|
// 检查权限
|
||||||
|
if (ciyfn.nopower(me.power, 'p1v')) {
|
||||||
|
ciyfn.alert('未被授权');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
权限格式:`.p1v.p2v.p3v.`(p=父权限,v=查看)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 组件命名
|
||||||
|
|
||||||
|
- 使用 `com` 属性标识组件name
|
||||||
|
- 组件名采用下划线命名法
|
||||||
|
- 表单字段使用有意义的名称
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ciy-select com="user_status" range="userstatus"></ciy-select>
|
||||||
|
<ciy-datetime com="start_time" type="datetime"></ciy-datetime>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 数据字典
|
||||||
|
|
||||||
|
字典数据通过 `range` 属性引用:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 字典结构
|
||||||
|
[{
|
||||||
|
id: 1,
|
||||||
|
name: '状态1',
|
||||||
|
upid: 0
|
||||||
|
}]
|
||||||
|
|
||||||
|
// 使用
|
||||||
|
ciycmp({
|
||||||
|
dom: '[com=status]',
|
||||||
|
range: 'userstatus' // 从localstorage缓存读取
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 事件处理
|
||||||
|
|
||||||
|
- 使用 `onchange` 处理组件值变化
|
||||||
|
- 事件回调接收统一的参数对象
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
ciycmp({
|
||||||
|
dom: '[com=status]',
|
||||||
|
onchange: function(e) {
|
||||||
|
console.log(e.name); // 组件名称
|
||||||
|
console.log(e.value); // 组件值
|
||||||
|
console.log(e.dom); // DOM元素
|
||||||
|
console.log(e.from); // 触发来源
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 国际化
|
||||||
|
|
||||||
|
使用 `ciyfn.lang()` 函数实现多语言:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
console.log(ciyfn.lang('保存'));
|
||||||
|
console.log(ciyfn.lang('删除'));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 性能优化
|
||||||
|
|
||||||
|
- 使用 `ciyfn.throttle()` 防抖
|
||||||
|
- 使用 `ciyfn.lazyimg()` 懒加载图片
|
||||||
|
- 列表分页加载
|
||||||
|
- 图片URL转换:使用 `ciyfn.file_stor()` 将数据库存储路径转换为云存储绝对URL
|
||||||
|
- 图片查看:使用 `ciyfn.showimg(index, imagesString)` 查看多张图片,参数为起始索引和用`~`连接的图片路径字符串
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 图片URL转换
|
||||||
|
var imgurl = ciyfn.file_stor('/2024/03/14/image.jpg');
|
||||||
|
|
||||||
|
// 查看多张图片,用~分隔(数据库中的原始存储)
|
||||||
|
ciyfn.showimg(1, '/img/1.jpg~/img/2.jpg~/img/3.jpg'); // 从第2张开始查看
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 防抖示例
|
||||||
|
$5('.search-input').on('input', function() {
|
||||||
|
if (ciyfn.throttle(this)) return;
|
||||||
|
// 搜索逻辑
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开发流程
|
||||||
|
|
||||||
|
### 新建页面
|
||||||
|
|
||||||
|
1. 在 `web/xxx/` 下创建同名HTML文件和后端文件
|
||||||
|
2. 引入必要的JS和CSS文件
|
||||||
|
3. 使用组件标签构建页面
|
||||||
|
4. 编写初始化逻辑
|
||||||
|
5. 实现交互功能
|
||||||
|
6. 测试和优化
|
||||||
|
|
||||||
|
### 示例代码
|
||||||
|
|
||||||
|
#### 列表页面示例
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link href="/jscss/style.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<form class="search" onsubmit="table.search(this,'btn');return false;">
|
||||||
|
<div>
|
||||||
|
<div class="sinps">
|
||||||
|
<div class="ciy-form">
|
||||||
|
<label>状态</label>
|
||||||
|
<div><ciy-select com="status" range="status" all="全部"></ciy-select></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sbtns">
|
||||||
|
<button class="btn" type="submit">查询</button>
|
||||||
|
<a class="btn" onclick="edit(0)">添加</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="table">
|
||||||
|
<div class="list"></div>
|
||||||
|
<div>
|
||||||
|
<div class="btmbtn"></div>
|
||||||
|
<div class="page"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/jscss/ciy.js"></script>
|
||||||
|
<script src="/jscss/ciycmp.js"></script>
|
||||||
|
<script src="/jscss/ciycmp2.js"></script>
|
||||||
|
<script src="/jscss/ciytable.js"></script>
|
||||||
|
<script src="./common.js"></script>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
var table;
|
||||||
|
ciyfn.pageload(function() {
|
||||||
|
ciycmp({ dom: '[com=status]', range: 'status', all: '全部' });
|
||||||
|
|
||||||
|
table = new ciyclass.table({
|
||||||
|
dom: '.table',
|
||||||
|
url: 'list', //JS引擎将自动拼接为当前目录/文件名.list /admin/demopage.list
|
||||||
|
pagecount: 20,
|
||||||
|
fn_beforedata: function(json) {
|
||||||
|
ciyfn.fillsearch({ dom: '.search', data: json });
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
table.callpage(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
function edit(id) {
|
||||||
|
ciyfn.alert({
|
||||||
|
title: id == 0 ? '添加' : '修改',
|
||||||
|
width: '600px',
|
||||||
|
frame: 'edit.html?id=' + id,
|
||||||
|
cb: function(opn) {
|
||||||
|
opn.close();
|
||||||
|
table.updateline(opn.inputs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 表单页面示例
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link href="/jscss/style.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<form onsubmit="save(event);">
|
||||||
|
<div class="ciy-form">
|
||||||
|
<label>名称</label>
|
||||||
|
<div><input type="text" name="name" required></div>
|
||||||
|
</div>
|
||||||
|
<div class="ciy-form">
|
||||||
|
<label>状态</label>
|
||||||
|
<div><ciy-switch com="status" value="1"></ciy-switch></div>
|
||||||
|
</div>
|
||||||
|
<div class="ciy-form">
|
||||||
|
<label>时间</label>
|
||||||
|
<div><ciy-datetime com="time" type="datetime"></ciy-datetime></div>
|
||||||
|
</div>
|
||||||
|
<button class="btn" type="submit">保存</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/jscss/ciy.js"></script>
|
||||||
|
<script src="/jscss/ciycmp.js"></script>
|
||||||
|
<script src="./common.js"></script>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
ciyfn.pageload(function() {
|
||||||
|
ciycmp({ dom: '[com=status]' });
|
||||||
|
ciycmp({ dom: '[com=time]', type: 'datetime' });
|
||||||
|
});
|
||||||
|
|
||||||
|
function save(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var postparam = ciyfn.getform(event.target);
|
||||||
|
ciyfn.callfunc('save', postparam, function(json) {
|
||||||
|
ciyfn.toast('保存成功');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常用API
|
||||||
|
|
||||||
|
### 工具函数
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 全局函数
|
||||||
|
tostr(val, defval) // 转字符串
|
||||||
|
toint(val, def) // 转整数
|
||||||
|
tofloat(val, def) // 转浮点数
|
||||||
|
tostamp(time) // 转时间戳
|
||||||
|
isarray(v) // 判断是否Array类型
|
||||||
|
isobj(v) // 判断是否Object类型
|
||||||
|
iselement(v) // 判断是否Element类型
|
||||||
|
|
||||||
|
// DOM操作
|
||||||
|
$5(selector) // 选择元素
|
||||||
|
dom.css('color') // 获取样式
|
||||||
|
dom.css()['color'] // 获取计算后样式
|
||||||
|
dom.css(name, val) // 设置样式
|
||||||
|
dom.css({color:#xxx}) // 批量设置样式
|
||||||
|
dom.show() / dom.hide() // 显示/隐藏
|
||||||
|
dom.on(event, handler) // 绑定事件
|
||||||
|
dom.val(value) // 获取/设置值
|
||||||
|
|
||||||
|
// 数据处理
|
||||||
|
ciyfn.tojson(str) // JSON解析
|
||||||
|
ciyfn.jsontostr(obj) // JSON序列化
|
||||||
|
ciyfn.tostamp(time) // 转时间戳
|
||||||
|
ciyfn.todatetime(stamp, fmt) // 格式化日期
|
||||||
|
|
||||||
|
// 存储
|
||||||
|
ciyfn.getstorage(key) // 读取存储
|
||||||
|
ciyfn.setstorage(key, val) // 写入存储
|
||||||
|
|
||||||
|
// 消息提示
|
||||||
|
ciyfn.toast(msg, type) // 提示
|
||||||
|
ciyfn.alert(opn) // 弹窗
|
||||||
|
|
||||||
|
// API调用
|
||||||
|
ciyfn.callfunc(url, data, callback, opn) // 调用接口
|
||||||
|
```
|
||||||
|
|
||||||
|
### 表格API
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 分页
|
||||||
|
table.callpage(page); // 加载页面
|
||||||
|
table.updateline(json); // 更新行
|
||||||
|
table.delline(json); // 删除行
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
table.search(dom, act); // 执行搜索
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、注意事项
|
||||||
|
|
||||||
|
1. **原生开发**: 尽量使用原生开发,已封装$5(jQuery改进版)
|
||||||
|
1. **严格模式**: 所有JS代码使用 `'use strict'`
|
||||||
|
3. **引号使用**: 代码中使用单引号
|
||||||
|
4. **事件处理**: 使用 `$5().on()` 或原生 `addEventListener`
|
||||||
|
5. **异步处理**: 使用回调函数处理异步结果
|
||||||
|
6. **数据验证**: 后端必须验证数据
|
||||||
|
7. **错误处理**: 无需处理API错误,自动弹窗。特殊情况,在opn参数中定义fail函数
|
||||||
|
8. **性能优化**: 大数据列表使用分页加载
|
||||||
|
9. **兼容性**: 确保IE11+兼容
|
||||||
|
10. **安全性**: 防止XSS和CSRF攻击
|
||||||
|
11. **菜单结构设计**: PC端菜单应具备清晰的层级结构,二次菜单设计必须有一级菜单。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q: 组件不显示?
|
||||||
|
|
||||||
|
A: 检查是否正确引入了组件库文件(ciycmp.js、ciycmp2.js)。
|
||||||
|
|
||||||
|
### Q: 表格数据不加载?
|
||||||
|
|
||||||
|
A: 检查API返回格式是否符合标准,确认 `url` 参数正确。
|
||||||
|
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
|
||||||
|
- 组件示例:`web/admin/demo/front/`
|
||||||
|
- API文档:参考各组件的源码注释
|
||||||
|
- 设计思路:参考框架注释中的设计说明
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**版本**: 1.0.0
|
||||||
|
**作者**: Ciyon Team
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,428 @@
|
||||||
|
# ciyon 数据字典设计 Skill 文档
|
||||||
|
参考zc_cata表,未指定新字典表,则复用该表。
|
||||||
|
|
||||||
|
## 数据库表结构
|
||||||
|
|
||||||
|
### zc_cata 表定义
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `zc_cata` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`upid` int(11) NOT NULL COMMENT '上级,DB,zc_cata',
|
||||||
|
`csort` int(11) NOT NULL DEFAULT 10 COMMENT '排序',
|
||||||
|
`isuse` int(11) NOT NULL DEFAULT 1 COMMENT '|行为|,BOOL',
|
||||||
|
`cbid` int(11) NOT NULL DEFAULT 0 COMMENT '库,DB,zc_cata',
|
||||||
|
`codeid` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '值',
|
||||||
|
`name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
|
||||||
|
`clas` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '样式类',
|
||||||
|
`extdata` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '使用表',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
INDEX `cbid`(`cbid`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 12001701 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典表' ROW_FORMAT = Dynamic;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字段说明
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | int(11) | 主键ID |
|
||||||
|
| upid | int(11) | 上级ID,支持树形结构,多级字典使用 |
|
||||||
|
| csort | int(11) | 排序字段 |
|
||||||
|
| isuse | int(11) | 是否启用,1=启用,2=禁用。是否使用开关。已被使用不能被删除,可操作关闭。关闭后前端组件不可选该字典项。|
|
||||||
|
| cbid | int(11) | cbid=0为字典集合,cbid>0为某个字典的字典项集合 |
|
||||||
|
| codeid | varchar(20) | 字典集合的codeid为字典代码,通常英文命名,一般与列名相同。字典项集合的codeid一般为数字。 |
|
||||||
|
| name | varchar(30) | 显示名称 |
|
||||||
|
| clas | varchar(20) | 一般用于给前端元素标记class名,**仅在前端页面需用不同颜色显示的情况设置样式类,其余不设置** |
|
||||||
|
| extdata | varchar(180) | 使用表列表,一行一个 |
|
||||||
|
|
||||||
|
### 字典项编号
|
||||||
|
|
||||||
|
一般从10开始编号
|
||||||
|
- 进行中过程一般设置10/20/30
|
||||||
|
- 失败一般设置90/91等
|
||||||
|
- 成功一般设置100
|
||||||
|
- 归档/完成等一般设置110/120等。
|
||||||
|
|
||||||
|
**重要规范**:在前端选项卡筛选等场景中,字典项标识应从1开始编号,避免使用0。例如:
|
||||||
|
- 变动类型:10=类型1,20=类型2,30=类型3
|
||||||
|
- 数据状态:1=公开,2=订阅
|
||||||
|
|
||||||
|
### 数据组织结构
|
||||||
|
|
||||||
|
字典采用双层结构:
|
||||||
|
|
||||||
|
- **库层级**:`cbid=0` 的记录为字典库
|
||||||
|
- **值层级**:`cbid>0` 的记录为字典值,`cbid` 指向所属库的 `id`
|
||||||
|
|
||||||
|
示例数据:
|
||||||
|
```
|
||||||
|
id=10, cbid=0, codeid='sex', name='性别' → 字典库
|
||||||
|
id=1000, cbid=10, codeid='10', name='男' → 字典值
|
||||||
|
id=1001, cbid=10, codeid='20', name='女' → 字典值
|
||||||
|
```
|
||||||
|
|
||||||
|
## 字典类型
|
||||||
|
|
||||||
|
### 固定字典(small data)
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 库和值都存储在 zc_cata 表中
|
||||||
|
- 支持多级树形结构(通过 upid)
|
||||||
|
- 登录时自动加载到前端缓存
|
||||||
|
|
||||||
|
**适用场景**:
|
||||||
|
- 数据量小(< 1000条)
|
||||||
|
- 需要频繁修改
|
||||||
|
- 需要多级树形结构
|
||||||
|
|
||||||
|
**管理方式**:
|
||||||
|
- 使用 `/web/admin/rigger/cataindex.php` 管理字典库
|
||||||
|
- 使用 `/web/admin/rigger/cata.php` 管理字典值
|
||||||
|
|
||||||
|
|
||||||
|
### 大数据量静态字典(large data)
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 数据存储为独立的 JS 文件
|
||||||
|
- 按需加载,减少初始加载时间
|
||||||
|
- PC端和移动端均可使用
|
||||||
|
|
||||||
|
**适用场景**:
|
||||||
|
- 数据量大(> 1000条)
|
||||||
|
- 数据相对固定
|
||||||
|
- 不需要频繁修改
|
||||||
|
|
||||||
|
**文件格式**:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var ciy_arearpc=[
|
||||||
|
{"id":"110000","upid":"0","name":"北京市"},
|
||||||
|
{"id":"110100","upid":"110000","name":"市辖区"},
|
||||||
|
{"id":"110101","upid":"110100","name":"东城区"}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**文件位置**:
|
||||||
|
- PC端:`/web/ud/dict/`
|
||||||
|
- 移动端:通过远程URL加载
|
||||||
|
|
||||||
|
## PC端实现
|
||||||
|
|
||||||
|
### 登录时加载字典
|
||||||
|
|
||||||
|
**后端接口**:`/web/admin/login.php` 中的 `json_login()` 方法
|
||||||
|
|
||||||
|
```php
|
||||||
|
static function getsync($userrow, $oid = 0, $sid = '') {
|
||||||
|
// ... 认证代码 ...
|
||||||
|
|
||||||
|
$ret['storage'] = array();
|
||||||
|
$csql = new \ciy\sql('zc_cata');
|
||||||
|
$csql->order('csort,id');
|
||||||
|
$ret['storage']['cata'] = $db->get($csql); // 加载所有字典
|
||||||
|
|
||||||
|
// ... 其他数据 ...
|
||||||
|
|
||||||
|
return succjson($ret);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 前端缓存字典
|
||||||
|
|
||||||
|
**前端函数**:`/web/jscss/ciy.js` 中的 `savedict()` 函数
|
||||||
|
|
||||||
|
**存储格式**:
|
||||||
|
- 键名:`cata_{codeid}`,例如:`cata_sex`
|
||||||
|
- 值格式:数组,每个元素包含 `id`, `name`, `upid`, `clas`, `isuse`
|
||||||
|
|
||||||
|
### 查询字典
|
||||||
|
|
||||||
|
**ccode** - 单值查询:
|
||||||
|
```javascript
|
||||||
|
// 根据id查询name
|
||||||
|
var name = ciyfn.ccode('sex', '10'); // 返回 '男'
|
||||||
|
|
||||||
|
// 查询其他字段
|
||||||
|
var item = ciyfn.ccode('sex', '10', '_obj'); // 返回完整对象
|
||||||
|
var clas = ciyfn.ccode('sex', '10', 'clas'); // 返回样式类
|
||||||
|
```
|
||||||
|
|
||||||
|
**scode** - 多值查询:
|
||||||
|
```javascript
|
||||||
|
var names = ciyfn.scode(sexArray, '10,20'); // 返回 ['男', '女']
|
||||||
|
```
|
||||||
|
|
||||||
|
**mcode** - 多级查询:
|
||||||
|
```javascript
|
||||||
|
// 查询从当前节点到根节点的所有名称
|
||||||
|
var path = ciyfn.mcode(areaArray, '110101'); // 返回 ['东城区', '市辖区', '北京市']
|
||||||
|
```
|
||||||
|
|
||||||
|
**bcode** - 位标记查询:
|
||||||
|
```javascript
|
||||||
|
// 假设使用位标记存储多个状态
|
||||||
|
var flags = ciyfn.bcode(statusArray, 5); // 5 = 1 + 4,返回对应的状态数组
|
||||||
|
```
|
||||||
|
|
||||||
|
## 移动端实现
|
||||||
|
|
||||||
|
### 字典加载
|
||||||
|
|
||||||
|
**登录时加载**:
|
||||||
|
```javascript
|
||||||
|
// /fapp/ciyon_ap/util/ciy.js
|
||||||
|
ciyfn.pageload(function () {
|
||||||
|
this.me = this.getme();
|
||||||
|
// 字典存储在 this.g 中
|
||||||
|
this.g = this.getstorage('g', {});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**设置字典**:
|
||||||
|
```javascript
|
||||||
|
// 登录成功后
|
||||||
|
ciyfn.setstorage(ciy_vars.tokenfield, json.me);
|
||||||
|
if (json.storage)
|
||||||
|
ciyfn.savedict(json.storage);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字典查询
|
||||||
|
|
||||||
|
**在页面中使用**:
|
||||||
|
```
|
||||||
|
<view>{{ccode(g.sex, sexcode)}}</view>
|
||||||
|
<ciy-select :range="g.sex" ></ciy-select>
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
getSexName(code) {
|
||||||
|
return this.ccode(this.g.sex, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**核心函数**:
|
||||||
|
ccode(arr, value, field, nonestr) - 单值查询
|
||||||
|
scode(arr, ids, field) - 多值查询
|
||||||
|
mcode(arr, value, field) - 多级查询
|
||||||
|
|
||||||
|
### 按需加载静态字典
|
||||||
|
|
||||||
|
**加载函数**:
|
||||||
|
```javascript
|
||||||
|
async load_ciydict(url) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用示例**:
|
||||||
|
```javascript
|
||||||
|
// 按需加载地区字典
|
||||||
|
var [err, res] = await this.go(this.load_ciydict('/dict/ciy_arearpc.js'));
|
||||||
|
if (!err) {
|
||||||
|
this.g.arearpc = res.arr; // 存储到全局变量
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 字典管理
|
||||||
|
|
||||||
|
### 创建新字典库
|
||||||
|
|
||||||
|
**方式一:通过管理界面**
|
||||||
|
1. 访问 `/web/admin/rigger/cataindex.html`
|
||||||
|
2. 点击"批量添加"
|
||||||
|
3. 填写格式:
|
||||||
|
```
|
||||||
|
性别,sex
|
||||||
|
男,10
|
||||||
|
女,20
|
||||||
|
其他,90
|
||||||
|
```
|
||||||
|
|
||||||
|
**方式二:直接SQL插入**
|
||||||
|
```sql
|
||||||
|
-- 插入库
|
||||||
|
INSERT INTO zc_cata (upid, csort, isuse, cbid, codeid, name)
|
||||||
|
VALUES (0, 10, 1, 0, 'education', '学历');
|
||||||
|
|
||||||
|
-- 获取库ID(假设为102)
|
||||||
|
-- 插入库值
|
||||||
|
INSERT INTO zc_cata (upid, csort, isuse, cbid, codeid, name, clas)
|
||||||
|
VALUES
|
||||||
|
(0, 10, 1, 102, '10', '小学', ''),
|
||||||
|
(0, 20, 1, 102, '20', '初中', ''),
|
||||||
|
(0, 30, 1, 102, '30', '高中', '');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 管理字典值
|
||||||
|
|
||||||
|
**访问字典管理页面**:
|
||||||
|
```
|
||||||
|
/web/admin/rigger/cata.html?cbid=10
|
||||||
|
```
|
||||||
|
|
||||||
|
**支持的URL参数**:
|
||||||
|
- `cbid`: 字典库ID
|
||||||
|
- `issub=yes`: 支持子码
|
||||||
|
- `ismulti=yes`: 支持批量添加
|
||||||
|
- `ext=扩展名`: 显示扩展字段
|
||||||
|
|
||||||
|
### 字典刷新
|
||||||
|
|
||||||
|
当字典数据变更后,需要刷新前端缓存:
|
||||||
|
|
||||||
|
**方式一:管理界面刷新**
|
||||||
|
- 访问字典管理页面,点击"刷新缓存"按钮
|
||||||
|
|
||||||
|
**方式二:API刷新**
|
||||||
|
```
|
||||||
|
POST /web/admin/login.php
|
||||||
|
参数: action=restorage
|
||||||
|
```
|
||||||
|
|
||||||
|
## AI生成字典和代码的指导原则
|
||||||
|
|
||||||
|
### 生成固定字典的步骤
|
||||||
|
|
||||||
|
**步骤一:定义库**
|
||||||
|
```sql
|
||||||
|
INSERT INTO zc_cata (upid, csort, isuse, cbid, codeid, name, extdata)
|
||||||
|
VALUES (0, 10, 1, 0, 'orderstatus', '订单状态', 'ap_order');
|
||||||
|
```
|
||||||
|
|
||||||
|
**步骤二:定义值**
|
||||||
|
```sql
|
||||||
|
INSERT INTO zc_cata (upid, csort, isuse, cbid, codeid, name, clas)
|
||||||
|
VALUES
|
||||||
|
(0, 10, 1, [库ID], '10', '待支付', 'def'),
|
||||||
|
(0, 20, 1, [库ID], '20', '已支付', 'warn'),
|
||||||
|
(0, 30, 1, [库ID], '30', '已发货', 'man'),
|
||||||
|
(0, 100, 1, [库ID], '100', '已完成', 'succ');
|
||||||
|
```
|
||||||
|
|
||||||
|
- **开关类字段**:如是否启用、是否公开等,直接使用数据库字段存储,不需要定义为字典
|
||||||
|
|
||||||
|
**步骤三:定义哪些表使用了该字典**
|
||||||
|
extdata:表名1.不相同的字段名\n表名2\n表名3
|
||||||
|
删除字典项时,检索每个表的字段是否已引用。已引用的禁止删除。
|
||||||
|
|
||||||
|
**步骤四:前端使用**
|
||||||
|
```javascript
|
||||||
|
// 查询单个值
|
||||||
|
var name = ciyfn.ccode('orderstatus', '10'); // '待支付'
|
||||||
|
|
||||||
|
// 查询带样式
|
||||||
|
var item = ciyfn.ccode('orderstatus', '10', '_obj'); // {id:'10', name:'待支付', clas:'def'}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生成业务代码的规范
|
||||||
|
|
||||||
|
**表字段设计**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE ap_order (
|
||||||
|
id INT PRIMARY KEY,
|
||||||
|
orderstatus INT COMMENT '订单状态,CATA,orderstatus',
|
||||||
|
-- ...
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**前端展示**:
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<text>{{ ccode(g.orderstatus, order.orderstatus) }}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
order: { orderstatus: '10' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码生成检查清单
|
||||||
|
|
||||||
|
生成字典相关代码时,必须检查:
|
||||||
|
|
||||||
|
- [ ] 字典库是否已创建(cbid=0 的记录)
|
||||||
|
- [ ] 字典值是否已插入(cbid 指向库ID)
|
||||||
|
- [ ] extdata 是否定义了引用表(如需要)
|
||||||
|
- [ ] clas 字段是否根据字典类型合理设置(前端需用不同颜色显示时设置样式,其余不设置)
|
||||||
|
- [ ] isuse 字段是否设置为1(启用)
|
||||||
|
- [ ] 前端是否正确调用 ccode/scode/mcode/bcode
|
||||||
|
- [ ] 修改字典后是否刷新了缓存
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
**问题一:哪些场景不适合使用字典?**
|
||||||
|
|
||||||
|
**答案**:
|
||||||
|
- 需要用户自主设置的类型/状态,不适合
|
||||||
|
- 开关类字段(如是否启用、是否公开等),直接使用数据库字段存储,不需要定义为字典
|
||||||
|
|
||||||
|
**问题二:字典修改后为什么前端没有更新?**
|
||||||
|
|
||||||
|
**答案**: 需要刷新缓存:
|
||||||
|
控制台右上角 点击"刷新缓存"按钮
|
||||||
|
|
||||||
|
**问题三:如何支持多级字典?**
|
||||||
|
|
||||||
|
**答案**: 使用 `upid` 字段:
|
||||||
|
```sql
|
||||||
|
-- 一级:省
|
||||||
|
INSERT INTO zc_cata VALUES (..., 0, ..., '110000', '北京市');
|
||||||
|
|
||||||
|
-- 二级:市
|
||||||
|
INSERT INTO zc_cata VALUES (..., [省ID], ..., '110100', '市辖区');
|
||||||
|
|
||||||
|
-- 三级:区
|
||||||
|
INSERT INTO zc_cata VALUES (..., [市ID], ..., '110101', '东城区');
|
||||||
|
```
|
||||||
|
|
||||||
|
查询多级路径:
|
||||||
|
```javascript
|
||||||
|
var path = ciyfn.mcode('area', '110101'); // ['东城区', '市辖区', '北京市']
|
||||||
|
```
|
||||||
|
|
||||||
|
**问题四:如何在移动端使用字典?**
|
||||||
|
|
||||||
|
**答案**:
|
||||||
|
1. 登录后字典自动加载到 `this.g`
|
||||||
|
2. 在页面中直接使用 `this.ccode()`
|
||||||
|
3. 大数据量字典使用 `this.load_ciydict()` 按需加载
|
||||||
|
|
||||||
|
|
||||||
|
## 附录
|
||||||
|
|
||||||
|
### 样式类说明
|
||||||
|
|
||||||
|
| clas | 说明 | 颜色 |
|
||||||
|
|------|------|------|
|
||||||
|
| dag | 失败 | 红色 |
|
||||||
|
| warn | 警告 | 橙色 |
|
||||||
|
| succ | 成功 | 绿色 |
|
||||||
|
| def | 灰色 | 灰色 |
|
||||||
|
| man | 主色 | 蓝色 |
|
||||||
|
|
||||||
|
### 核心函数速查
|
||||||
|
|
||||||
|
| 函数 | 平台 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| ccode(arr, value, field, nonestr) | 全 | 单值查询 |
|
||||||
|
| scode(arr, ids, field) | 全 | 多值查询 |
|
||||||
|
| mcode(arr, value, field) | 全 | 多级查询 |
|
||||||
|
| bcode(arr, value, field) | 全 | 位标记查询 |
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本**: v1.0
|
||||||
|
**更新日期**: 2026-03-20
|
||||||
|
**维护者**: ciyon开发团队
|
||||||
|
|
@ -0,0 +1,787 @@
|
||||||
|
# 数据库建表 SQL 指导文档
|
||||||
|
|
||||||
|
你是数据库 DBA 管理员。需根据开发者已经规划好的表结构,转义成 create table SQL 语句。
|
||||||
|
|
||||||
|
|
||||||
|
### 输出文档名称
|
||||||
|
/建表SQL.sql
|
||||||
|
|
||||||
|
## 列注释标准格式
|
||||||
|
|
||||||
|
### 基本格式
|
||||||
|
|
||||||
|
```
|
||||||
|
COMMENT '中文列名,组件名,参数'
|
||||||
|
```
|
||||||
|
|
||||||
|
**三部分说明:**
|
||||||
|
1. **中文列名**:显示在界面上的字段标题,支持对齐标记
|
||||||
|
2. **组件名**:决定前端组件类型和数据格式化方式
|
||||||
|
3. **参数**:组件的配置参数(可选)
|
||||||
|
|
||||||
|
### 对齐方式标记
|
||||||
|
|
||||||
|
在中文列名中使用竖线标记对齐方式:
|
||||||
|
|
||||||
|
- **居中对齐**:`|状态|` - 两端加竖线
|
||||||
|
- **右对齐**:`金额|` - 右侧加竖线
|
||||||
|
- **左对齐**:默认,不加竖线
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```sql
|
||||||
|
`artstatus` int(11) NOT NULL COMMENT '|文章状态|,CATA,artstatus', -- 居中
|
||||||
|
`studycnt` int(11) NOT NULL DEFAULT 0 COMMENT '精读数|', -- 右对齐
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '文章标题', -- 左对齐(默认)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 特殊标记
|
||||||
|
|
||||||
|
- **默认隐藏列**:中文列名前加 `#`,如 `#隐藏字段`
|
||||||
|
- **列表不显示**:中文列名前加 `,`,如 `,内部字段`
|
||||||
|
|
||||||
|
## 输出格式
|
||||||
|
|
||||||
|
- 一行一条 SQL,每行分号结束
|
||||||
|
- 不要包含任何代码格式包裹和其他内容或解释
|
||||||
|
|
||||||
|
## 总体遵循规则
|
||||||
|
|
||||||
|
- 将中文表名作为表注释
|
||||||
|
- id 字段设置自增
|
||||||
|
- 除 id 列外,其他所有列都要加列注释
|
||||||
|
- 不要建立任何的外键、索引、触发器等
|
||||||
|
- 所有列必须设置默认值,字符串默认为空字符串,数字默认为 0
|
||||||
|
- 所有列都禁止 null
|
||||||
|
- 所有列名称全部小写
|
||||||
|
- 所有列名称两端都用反引号包裹
|
||||||
|
- 中文列名对齐规则:
|
||||||
|
- 如果右侧有竖线,则为右对齐(例如:金额|)
|
||||||
|
- 如果两边有竖线,则为居中对齐(例如:|xx状态|)
|
||||||
|
- 尽量对中文列名进行合理的居中对齐和右对齐
|
||||||
|
- 字典、level、status、type 等列,bool 列,url 链接列,应居中对齐,在列注释的中文列名两边加竖线
|
||||||
|
- 重量、金额、长度、百分比等纯数字的整数列,应右对齐,在列注释的中文列名右边加竖线
|
||||||
|
|
||||||
|
## 特别说明
|
||||||
|
|
||||||
|
- 组件名为 CATU、CATA、BOOL、URL 的列,中文列名需在两边加竖线
|
||||||
|
- 组件名为 CNY、KG、PCT、TC、METRE、SEC、INT、CYC 的列,中文列名需在右侧加竖线
|
||||||
|
- 中文列名结尾是"日期"的列,组件名: DATE,参数为 Y-m-d
|
||||||
|
|
||||||
|
## 字段类型规则
|
||||||
|
|
||||||
|
- 尽量只用 varchar、bigint、int,谨慎使用 text 字段类型
|
||||||
|
- 列名称结尾为 times 的时间日期列,必须用 bigint 类型
|
||||||
|
- 与金额相关的列,如果预计金额不超过百万的情况,可以用 int,否则用 bigint
|
||||||
|
- 一个列可能包含多个附件的,例如 imgs,应适当评估文件数量,varchar(n),n 是 50*文件数量
|
||||||
|
- 一个列只可能包含一个文件的,例如 img1,用 varchar(50)
|
||||||
|
- 与文本有关的列,尽量评估较大容量,适当的使用 varchar(20/50/100/180/250) 等值
|
||||||
|
- 与公斤、吨、金额、米、温度、百分比有关的列,应使用 bigint 或 int
|
||||||
|
- 与经纬度有关的列,例如 lat、lng,应使用 int 字段类型
|
||||||
|
- 与真假布尔有关的 bool 类型的列,使用 int 字段类型
|
||||||
|
|
||||||
|
## 组件名规则(优先级从高到低)
|
||||||
|
|
||||||
|
- 列名称结尾为 user 的列,组件名: CATU。参数为 ap_user
|
||||||
|
- 所属关联有关的列,组件名: DB。参数为关联表的表名
|
||||||
|
- 字典有关的列,组件名: CATA。参数为英文列名称
|
||||||
|
- 列名称结尾为 times 的列,组件名: DATE。如果中文列名包含"日期"字样那么参数为: Y-m-d
|
||||||
|
- 金额相关的列,组件名: CNY
|
||||||
|
- 与科学带小数数字有关的列,组件名: BET。参数1为单位名称。参数2为倍率,默认100
|
||||||
|
- 重量相关的列,组件名: WGT
|
||||||
|
- 长度相关的列,组件名: LGH
|
||||||
|
- 百分比相关的列,组件名: PCT
|
||||||
|
- 温度相关的列,组件名: TC
|
||||||
|
- 可带单位的数字列,组件名: INT。参数为单位名。将显示为 5个、2批
|
||||||
|
- bool 相关的列,组件名: BOOL
|
||||||
|
- 与经纬度有关的列,lng 列的组件名: LOC,参数为 lat。lat 列不填组件和参数
|
||||||
|
- 周期相关的列,组件名: CYC
|
||||||
|
- 时长相关的列,组件名: SEC。将显示为 xx分钟、xx天
|
||||||
|
- 文档附件类的列,上传多图组件名: IMG,上传单图组件名: IMG1、上传附件组件名: DOWN(例如:照片,IMG)
|
||||||
|
- url 链接相关的列,组件名: URL
|
||||||
|
- 列名称以 unit 结尾,多级单位定义有关的列,组件名: UNIT。将显示为: 1箱=24盒,1盒=10支
|
||||||
|
- 中文列名为说明、内容、简介、介绍、摘要的列,组件名: BR
|
||||||
|
- 敏感的列,组件名: MSK,参数为****,代表后4位用*代替
|
||||||
|
- 文件尺寸相关的列,组件名: FSIZE
|
||||||
|
- 列名称包含 name 的列,中文列名包含[编号、名称、号、名、单位]的列,无组件名
|
||||||
|
|
||||||
|
## 中文列名规则
|
||||||
|
|
||||||
|
- 组件名为 CATU、CATA、BOOL、URL 的列,中文列名在两边加竖线(例如:|xx状态|)
|
||||||
|
- 组件名为 BET、CNY、KG、PCT、TC、METRE、SEC、INT、CYC 的列,中文列名在右侧加竖线(例如:金额|、重量|、百分比|)
|
||||||
|
- id 字段不加列注释
|
||||||
|
|
||||||
|
|
||||||
|
## 组件名完整列表
|
||||||
|
|
||||||
|
### 字典类组件
|
||||||
|
|
||||||
|
#### CATA - 字典下拉(单选)
|
||||||
|
```
|
||||||
|
COMMENT '|状态|,CATA,字典code'
|
||||||
|
```
|
||||||
|
- 用途:从字典表读取选项的下拉选择
|
||||||
|
- 参数:字典的code值
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`artstatus` int(11) NOT NULL COMMENT '|文章状态|,CATA,artstatus',
|
||||||
|
`userlevel` int(11) NOT NULL COMMENT '|用户等级|,CATA,userlevel',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CATU - 用户字典(单选)
|
||||||
|
```
|
||||||
|
COMMENT '审核人,CATU,adminuser'
|
||||||
|
```
|
||||||
|
- 用途:从用户表读取选项的下拉选择
|
||||||
|
- 参数:通常为 `adminuser`。登录成功随数据字典带出 机构用户id,name列表。
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`audituser` int(11) NOT NULL DEFAULT 0 COMMENT '审核人,CATU,adminuser',
|
||||||
|
`inputuser` int(11) NOT NULL DEFAULT 0 COMMENT '撰写人,CATU,adminuser',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CATS - 字典下拉(多选,小写逗号分隔)
|
||||||
|
```
|
||||||
|
COMMENT '认证情况,CATS,字典code|分隔符'
|
||||||
|
```
|
||||||
|
- 用途:多选字典值,以逗号分隔存储
|
||||||
|
- 参数:字典code和可选分隔符(默认为 ` - `)
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`certs` varchar(30) NOT NULL DEFAULT '' COMMENT '认证,CATS,certs',
|
||||||
|
`certs` varchar(30) NOT NULL DEFAULT '' COMMENT '认证,CATS,certs|<code>?</code>',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CATM - 树形字典(级联)
|
||||||
|
```
|
||||||
|
COMMENT '组织结构,CATM,树形字典code|分隔符'
|
||||||
|
```
|
||||||
|
- 用途:树形结构字典的级联选择
|
||||||
|
- 参数:树形字典表名和可选分隔符(默认为 ` - `)
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`prodcata` int(11) NOT NULL COMMENT '组织结构,CATM,zc_depart',
|
||||||
|
`areacode` int(11) NOT NULL COMMENT '所在地区,CATM,ciy_arearpc',
|
||||||
|
`areacode` int(11) NOT NULL COMMENT '所在地区,CATM,ciy_arearpc|<code>?</code>',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### TBIN - 位运算字典(多选)
|
||||||
|
```
|
||||||
|
COMMENT '认证情况,TBIN,字典code|分隔符'
|
||||||
|
```
|
||||||
|
- 用途:通过位运算存储的多选值(最多16个选项)
|
||||||
|
- 参数:字典code和可选分隔符
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`renzheng` int(11) NOT NULL DEFAULT 0 COMMENT '认证,TBIN,certs',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### TINT - 整型字典
|
||||||
|
```
|
||||||
|
COMMENT '发送人,TINT,10:用户.20:平台.30:AI客服'
|
||||||
|
```
|
||||||
|
- 用途:直接定义的整型字典选项
|
||||||
|
- 参数:`值:名称` 格式的选项列表
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`sendtype` int(11) NOT NULL COMMENT '发送人,TINT,10:用户.20:平台.30:AI客服',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 关联类组件
|
||||||
|
|
||||||
|
#### DB - 表关联(单选)
|
||||||
|
```
|
||||||
|
COMMENT '|版块|,DB,关联表名'
|
||||||
|
```
|
||||||
|
- 用途:关联其他表的下拉选择
|
||||||
|
- 参数:关联表名
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`sectionid` int(11) NOT NULL COMMENT '|版块|,DB,ap_art_section',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 日期时间类组件
|
||||||
|
|
||||||
|
#### DATE - 日期时间
|
||||||
|
```
|
||||||
|
COMMENT '创建时间,DATE'
|
||||||
|
COMMENT '有效期至,DATE,Y-m-d'
|
||||||
|
```
|
||||||
|
- 用途:日期时间显示和选择
|
||||||
|
- 参数:
|
||||||
|
- 无参数:显示 `Y-m-d H:i`
|
||||||
|
- `Y-m-d`:仅显示日期(年-月-日)
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '创建时间,DATE',
|
||||||
|
`accounttimes` bigint(20) NOT NULL COMMENT '有效期至,DATE,Y-m-d',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### TIME - 时间点
|
||||||
|
```
|
||||||
|
COMMENT '营业时间,TIME'
|
||||||
|
```
|
||||||
|
- 用途:一天内的时间点选择(HH:MM格式)
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`dayclock` int(11) NOT NULL COMMENT '营业时间,TIME',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 金额数值类组件
|
||||||
|
|
||||||
|
#### CNY - 金额(元)
|
||||||
|
```
|
||||||
|
COMMENT '充值金额|,CNY'
|
||||||
|
```
|
||||||
|
- 用途:人民币金额显示(单位:元)
|
||||||
|
- 自动格式化:`1000000` → `10,000.00元`
|
||||||
|
- 实际存储:分为最小单元
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`iemoney` int(11) NOT NULL COMMENT '金额|,CNY',
|
||||||
|
`cashmoney` int(10) NOT NULL COMMENT '提现金额|,CNY',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MCNY - 金额(万元)
|
||||||
|
```
|
||||||
|
COMMENT '金额|,WCNY,2'
|
||||||
|
```
|
||||||
|
- 用途:人民币金额显示(单位:万元)
|
||||||
|
- 参数:小数位数(默认3位)
|
||||||
|
- 自动格式化:`100000000` → `100.000万`
|
||||||
|
- 实际存储:分(0.01元)为最小单元
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`bankmoney` int(11) NOT NULL COMMENT '贷款金额|,WCNY,2',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MCNY - 金额单位(毫)
|
||||||
|
```
|
||||||
|
COMMENT '金额|,WCNY'
|
||||||
|
```
|
||||||
|
- 用途:人民币金额显示(单位:元)
|
||||||
|
- 参数:小数位数,默认保留4位小数
|
||||||
|
- 自动格式化:`10000` → `1.00元`
|
||||||
|
- 实际存储:毫元为最小单元,10000毫分=100分=1元
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`qian` int(11) NOT NULL COMMENT '提成金额|,MCNY',
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### BET - 科学计数法(带小数)
|
||||||
|
```
|
||||||
|
COMMENT '热功|,BET,焦耳,1000,3'
|
||||||
|
```
|
||||||
|
- 用途:带小数的数值显示
|
||||||
|
- 参数:单位,倍率,小数位数
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`price` int(11) NOT NULL COMMENT '热功|,BET,焦耳,1000,3',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 物理单位类组件
|
||||||
|
|
||||||
|
#### WGT - 重量
|
||||||
|
```
|
||||||
|
COMMENT '重量|,WGT,2'
|
||||||
|
```
|
||||||
|
- 用途:重量单位显示
|
||||||
|
- 参数:小数位数
|
||||||
|
- 自动转换:根据数值自动选择单位
|
||||||
|
- 实际存储:克为最小单元,1000克=1公斤
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`ton` int(11) NOT NULL COMMENT '吨位|,WGT',
|
||||||
|
`weightg` int(11) NOT NULL COMMENT '体重|,WGT',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LGH - 长度
|
||||||
|
```
|
||||||
|
COMMENT '长度|,LGH,厘米.米.公里,2'
|
||||||
|
```
|
||||||
|
- 用途:长度单位显示
|
||||||
|
- 参数:单位列表,小数位数
|
||||||
|
- 实际存储:毫米为最小单元
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`metre` int(11) NOT NULL COMMENT '长度|,LGH',
|
||||||
|
`height` int(11) NOT NULL COMMENT '身高|,LGH',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### METRE - 米制单位
|
||||||
|
```
|
||||||
|
COMMENT '长度|,METRE,米|1000|公里'
|
||||||
|
```
|
||||||
|
- 用途:米制单位显示(固定倍率)
|
||||||
|
- 参数:单位1|倍率|单位2
|
||||||
|
- 实际存储:米为最小单元
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`metre` int(11) NOT NULL COMMENT '直线距离|,METRE',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### TC - 温度
|
||||||
|
```
|
||||||
|
COMMENT '温度|,TC'
|
||||||
|
```
|
||||||
|
- 用途:温度显示(摄氏度)
|
||||||
|
- 实际存储:1/1000摄氏度为最小单元
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`eartmpr` int(11) NOT NULL COMMENT '耳温|,TC',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SEC - 时长(秒)
|
||||||
|
```
|
||||||
|
COMMENT '执行用时|,SEC'
|
||||||
|
```
|
||||||
|
- 用途:以秒为单位的时长显示
|
||||||
|
- 自动格式化:根据数值显示为 `xx秒`、`xx分钟`、`xx小时`
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`runsec` int(11) NOT NULL COMMENT '执行用时|,SEC',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CYC - 周期
|
||||||
|
```
|
||||||
|
COMMENT '执行周期|,CYC'
|
||||||
|
```
|
||||||
|
- 用途:周期显示
|
||||||
|
- 自动格式化:根据数值显示为 `xx天`、`xx月`
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`npcyc` int(11) NOT NULL COMMENT '执行周期|,CYC',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### PCT - 百分比
|
||||||
|
```
|
||||||
|
COMMENT '百分比|,PCT'
|
||||||
|
```
|
||||||
|
- 用途:百分比显示
|
||||||
|
- 自动格式化:`50` → `50.00%`
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`pct` int(11) NOT NULL COMMENT '百分比|,PCT',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### INT - 可带单位的整数
|
||||||
|
```
|
||||||
|
COMMENT '积分|,INT,分'
|
||||||
|
COMMENT '活动期数,INT,第?期'
|
||||||
|
```
|
||||||
|
- 用途:带单位的整数显示
|
||||||
|
- 参数:单位名(可用 `?` 占位数值)
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`mypnt` int(11) NOT NULL COMMENT '积分|,INT,分',
|
||||||
|
`acttm` int(11) NOT NULL COMMENT '活动期数,INT,第?期',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 布尔类组件
|
||||||
|
|
||||||
|
#### BOOL - 布尔开关
|
||||||
|
```
|
||||||
|
COMMENT '|是否使用|,BOOL'
|
||||||
|
```
|
||||||
|
- 用途:布尔值的开关显示
|
||||||
|
- 参数:真值.假值(默认为 `✔.✘`)
|
||||||
|
- 存储:真值为1,假值为2。其他值无效
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`isuse` int(11) NOT NULL COMMENT '|是否使用|,BOOL,✔.✘',
|
||||||
|
`isopen` int(11) NOT NULL COMMENT '|是否开启|,BOOL,开启.关闭',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 文件附件类组件
|
||||||
|
|
||||||
|
#### IMG1 - 单图上传
|
||||||
|
```
|
||||||
|
COMMENT '头像,IMG1'
|
||||||
|
COMMENT '身份证人像面,IMG1'
|
||||||
|
```
|
||||||
|
- 用途:单张图片上传
|
||||||
|
- 前端组件:`<ciy-upload com="xxx" num="1" />`
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`img` varchar(50) NOT NULL COMMENT '缩略图,IMG1',
|
||||||
|
`avar` varchar(50) NOT NULL DEFAULT '' COMMENT '头像,IMG1',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### IMG - 多图上传
|
||||||
|
```
|
||||||
|
COMMENT '图片,IMG'
|
||||||
|
COMMENT '活动花絮,IMG'
|
||||||
|
```
|
||||||
|
- 用途:多张图片上传
|
||||||
|
- 前端组件:`<ciy-upload com="xxx" num="3" />`
|
||||||
|
- 存储格式:路径1~路径2~路径3
|
||||||
|
- 存储容量:约50字符串一个附件,3个附件=150varchar
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`imgs` varchar(250) NOT NULL DEFAULT '' COMMENT '图片,IMG',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### DOWN - 文件下载
|
||||||
|
```
|
||||||
|
COMMENT '发票,DOWN'
|
||||||
|
COMMENT '文档,DOWN'
|
||||||
|
```
|
||||||
|
- 用途:文件上传和下载链接
|
||||||
|
- 前端组件:`<ciy-upload com="xxx" num="3" type="*"/>`
|
||||||
|
- 存储格式:路径1~路径2~路径3
|
||||||
|
- 存储容量:约50字符串一个附件,3个附件=150varchar
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`invfile` varchar(50) NOT NULL DEFAULT '' COMMENT '发票,DOWN',
|
||||||
|
`downurl` varchar(200) NOT NULL DEFAULT '' COMMENT '文档,DOWN',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### FILEMD - Markdown文档
|
||||||
|
```
|
||||||
|
COMMENT '内容,FILEMD'
|
||||||
|
```
|
||||||
|
- 用途:文件存储的Markdown文档
|
||||||
|
- 前端组件:`<ciy-markdown com="xxx" />`
|
||||||
|
- 存储格式:云存储路径
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`content` mediumtext NOT NULL COMMENT ',内容,FILEMD',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 文本类组件
|
||||||
|
|
||||||
|
#### BR - 多行文本(换行)
|
||||||
|
```
|
||||||
|
COMMENT '摘要,BR'
|
||||||
|
COMMENT '工单提问,BR'
|
||||||
|
```
|
||||||
|
- 用途:多行文本内容(自动换行显示)
|
||||||
|
- 前端组件:`<ciy-textarea com="xxx" />`
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`descs` varchar(250) NOT NULL COMMENT ',摘要,BR',
|
||||||
|
`content` text NOT NULL COMMENT '答复内容,BR',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MD - Markdown编辑器
|
||||||
|
```
|
||||||
|
COMMENT '内容,MD'
|
||||||
|
```
|
||||||
|
- 用途:Markdown富文本编辑器
|
||||||
|
- 前端组件:`<ciy-markdown com="xxx" />`
|
||||||
|
- 存储格式:字符串数据库存储
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`content` mediumtext NOT NULL COMMENT ',内容,MD',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 特殊组件
|
||||||
|
|
||||||
|
#### UNIT - 多级单位定义
|
||||||
|
```
|
||||||
|
COMMENT '库存单位,UNIT'
|
||||||
|
```
|
||||||
|
- 用途:定义多级单位换算关系(如 箱→盒→支)
|
||||||
|
- 存储格式:`单位1|数量|单位2|数量|单位3`
|
||||||
|
- 示例:`瓶|24|盒|20|箱` 表示 1箱=20盒,1盒=24瓶
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`unit` varchar(50) NOT NULL COMMENT '库存单位,UNIT',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LOC - 地理位置坐标
|
||||||
|
```
|
||||||
|
COMMENT '位置,LOC'
|
||||||
|
```
|
||||||
|
- 用途:经纬度坐标(配合 `lng` 字段使用)
|
||||||
|
- 前端组件:`<ciy-map com="loc" />`
|
||||||
|
- 需要两个字段:`lat`(纬度)和 `lng`(经度)
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`lat` int(11) NOT NULL COMMENT '纬度',
|
||||||
|
`lng` int(11) NOT NULL COMMENT '位置,LOC,lat',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### URL - 链接
|
||||||
|
```
|
||||||
|
COMMENT '链接,URL'
|
||||||
|
```
|
||||||
|
- 用途:URL链接
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`url` varchar(180) NOT NULL COMMENT '链接,URL',
|
||||||
|
`returnurl` varchar(250) NOT NULL DEFAULT '' COMMENT '回调链接,URL',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### IP - IP地址
|
||||||
|
```
|
||||||
|
COMMENT 'IP,IP'
|
||||||
|
```
|
||||||
|
- 用途:IP地址显示
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`ip` varchar(40) NOT NULL COMMENT 'IP,IP',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MSK - 敏感信息脱敏
|
||||||
|
```
|
||||||
|
COMMENT '手机号,MSK,****'
|
||||||
|
```
|
||||||
|
- 用途:敏感信息脱敏显示(如手机号后4位)
|
||||||
|
- 参数:脱敏标记
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`mobile` varchar(30) NOT NULL COMMENT '手机号,MSK,****',
|
||||||
|
```
|
||||||
|
|
||||||
|
#### FSIZE - 文件大小
|
||||||
|
```
|
||||||
|
COMMENT '文件大小|,FSIZE,2'
|
||||||
|
```
|
||||||
|
- 用途:文件大小自动格式化
|
||||||
|
- 参数:小数位数(默认2位)
|
||||||
|
- 自动格式化:根据数值显示为 Bytes/KB/MB/GB...
|
||||||
|
- 示例:
|
||||||
|
```sql
|
||||||
|
`filesize` int(11) NOT NULL COMMENT '文件大小|,FSIZE,2',
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 字段类型规则
|
||||||
|
|
||||||
|
### 字段类型选择
|
||||||
|
|
||||||
|
| 类型 | 用途 | 示例 |
|
||||||
|
|-----|------|------|
|
||||||
|
| `varchar(n)` | 文本 | `varchar(50)`, `varchar(180)` |
|
||||||
|
| `bigint` | 大整数/时间戳 | `bigint(20)` |
|
||||||
|
| `int` | 整数 | `int(11)` |
|
||||||
|
| `text/mediumtext` | 长文本 | `text`, `mediumtext` |
|
||||||
|
|
||||||
|
### 具体规则
|
||||||
|
|
||||||
|
1. **尽量只用**:`varchar`、`bigint`、`int`
|
||||||
|
2. **谨慎使用**:`text` 字段类型
|
||||||
|
3. **时间日期列**(`times` 结尾):必须用 `bigint`
|
||||||
|
4. **金额列**:
|
||||||
|
- 不超过百万:可用 `int`
|
||||||
|
- 超过百万:用 `bigint` ,不考虑字段对齐,则都用bigint
|
||||||
|
5. **单文件**:`varchar(50)`
|
||||||
|
6. **多文件**:`varchar(50 * 文件数量)`
|
||||||
|
7. **文本列**:
|
||||||
|
- 适当评估容量
|
||||||
|
- 使用 `varchar(20/50/100/180/250)` 等。180及以下建索引效率较高。
|
||||||
|
8. **物理单位**(公斤/吨/金额/米/温度/百分比):用 `bigint`
|
||||||
|
9. **经纬度**(`lat`/`lng`):用 `int`
|
||||||
|
10. **布尔值**:用 `int`
|
||||||
|
|
||||||
|
### 默认值规则
|
||||||
|
|
||||||
|
- **字符串**:默认为空字符串 `''`
|
||||||
|
- **数字**:默认为 `0`
|
||||||
|
- **禁止 NULL**:所有列都禁止 null
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
### 简单示例
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `ap_art_post` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`sectionid` int(11) NOT NULL COMMENT '|版块|,DB,ap_art_section',
|
||||||
|
`artstatus` int(11) NOT NULL COMMENT '|文章状态|,CATA,artstatus',
|
||||||
|
`artsort` int(11) NOT NULL COMMENT '|推荐排序|,CATA,artsort',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '文章标题',
|
||||||
|
`source` varchar(100) NOT NULL COMMENT '来源',
|
||||||
|
`author` varchar(50) NOT NULL COMMENT '作者',
|
||||||
|
`studycnt` int(11) NOT NULL DEFAULT 0 COMMENT '精读数|',
|
||||||
|
`readcnt` int(11) NOT NULL COMMENT '阅读数|',
|
||||||
|
`img` varchar(50) NOT NULL COMMENT '缩略图,IMG1',
|
||||||
|
`descs` varchar(250) NOT NULL COMMENT ',摘要,BR',
|
||||||
|
`inputuser` int(11) NOT NULL COMMENT '撰写人,CATU,adminuser',
|
||||||
|
`audituser` int(11) NOT NULL DEFAULT 0 COMMENT '审核人,CATU,adminuser',
|
||||||
|
`pubtimes` bigint(20) NOT NULL DEFAULT 0 COMMENT '发布时间,DATE',
|
||||||
|
`content` mediumtext NOT NULL COMMENT ',内容,MD',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE = InnoDB COMMENT = '版块文章表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 复杂示例
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS `demo_normal`;
|
||||||
|
CREATE TABLE `demo_normal` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID,ENID',
|
||||||
|
`auditstatus` int(11) NOT NULL COMMENT '|审核状态|,CATA,auditstatus',
|
||||||
|
`audituser` int(11) NOT NULL DEFAULT 0 COMMENT '审核人,CATU,adminuser',
|
||||||
|
`audittimes` bigint(20) NOT NULL COMMENT '审核时间,DATE',
|
||||||
|
`auditmsg` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '审核理由',
|
||||||
|
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '默认标题',
|
||||||
|
`menuid` int(11) NOT NULL COMMENT '所属菜单,DB,zc_menu',
|
||||||
|
`filesize` int(11) NOT NULL COMMENT '文件大小|,FSIZE',
|
||||||
|
`metre` int(11) NOT NULL COMMENT '长度|,METRE',
|
||||||
|
`bankmoney` bigint(20) NOT NULL COMMENT '贷款金额|,WCNY',
|
||||||
|
`setdate` bigint(20) NOT NULL COMMENT '设置日期,DATE,Y-m-d',
|
||||||
|
`settimes` bigint(20) NOT NULL COMMENT '设置时间,DATE',
|
||||||
|
`dayclock` int(11) NOT NULL COMMENT '|营业时间|,TIME,H:i:s',
|
||||||
|
`downurl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '|文档|,IMG,t',
|
||||||
|
`avar` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '头像,IMG1',
|
||||||
|
`isuse` int(11) NOT NULL COMMENT '|是否使用|,BOOL',
|
||||||
|
`isopen` int(11) NOT NULL COMMENT '|是否开启|,BOOL,开启.关闭',
|
||||||
|
`unit` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '库存单位,UNIT',
|
||||||
|
`sigstatus` int(11) NOT NULL COMMENT '|单选状态|,CATA,auditstatus',
|
||||||
|
`mauditstatus` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '多选状态,CATS,auditstatus|~',
|
||||||
|
`prodcata` int(11) NOT NULL COMMENT '组织结构,CATM,zc_depart',
|
||||||
|
`areacode` int(11) NOT NULL COMMENT '所在地区,CATM,ciy_arearpc|<code>?</code>',
|
||||||
|
`renzheng` int(11) NOT NULL COMMENT '认证情况,TBIN,re.nz.he.ng|<kbd>?</kbd>',
|
||||||
|
`ppint` int(11) NOT NULL COMMENT '|临时字典|,TINT,1:aaa.3:bbbb.5:cccc',
|
||||||
|
`npcyc` int(11) NOT NULL COMMENT '|执行周期|,CYC',
|
||||||
|
`runsec` int(11) NOT NULL COMMENT '执行用时|,SEC',
|
||||||
|
`acttm` int(11) NOT NULL COMMENT '活动期数|,INT,第?期',
|
||||||
|
`imgs` varchar(800) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '活动花絮,IMG,?50',
|
||||||
|
`ton` bigint(20) NOT NULL COMMENT '吨位|,TON',
|
||||||
|
`price` bigint(20) NOT NULL COMMENT '单价|,CNY',
|
||||||
|
`lat` int(11) NOT NULL COMMENT ',纬度',
|
||||||
|
`lng` int(11) NOT NULL COMMENT '|位置|,LOC,lat',
|
||||||
|
`pct` int(11) NOT NULL COMMENT '百分比|,PCT',
|
||||||
|
`url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '链接,URL,跳转',
|
||||||
|
`weightg` bigint(20) NOT NULL COMMENT '体重|,KG,1,KG|1000|吨',
|
||||||
|
`eartmpr` int(11) NOT NULL COMMENT '耳温|,TC,3',
|
||||||
|
`qian` bigint(20) NOT NULL COMMENT '中式钱|,LNY',
|
||||||
|
`meishi` bigint(20) NOT NULL COMMENT '美式钱|,SNY',
|
||||||
|
`weight` bigint(20) NOT NULL COMMENT '重量|,WGT,G.*KG.TON,1',
|
||||||
|
`height` bigint(20) NOT NULL COMMENT '长度|,LGH',
|
||||||
|
`skt` bigint(20) NOT NULL COMMENT '科学数|,BET,SKT,1000,1',
|
||||||
|
`idcard` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '身份证号,MSK,******#*',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '添加时间,DATE',
|
||||||
|
`content` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT ',介绍,BR',
|
||||||
|
`md` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT ',富文本,MD',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 78 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '复杂功能表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 前端组件对应表
|
||||||
|
|
||||||
|
| 列注释组件 | 前端HTML组件 | 说明 |
|
||||||
|
|-----------|------------|------|
|
||||||
|
| CATA | `<ciy-select com="xxx" all="无" />` | 字典下拉 |
|
||||||
|
| CATU | `<ciy-select com="xxx" />` | 用户下拉 |
|
||||||
|
| DB | `<ciy-select com="xxx" all="无" />` | 关联表下拉 |
|
||||||
|
| CATM | `<ciy-selcas com="xxx" />` | 级联选择 |
|
||||||
|
| CATS | `<ciy-checkbox com="xxx" />` | 多选框 |
|
||||||
|
| TBIN | `<ciy-checkbox com="xxx" />` | 位运算多选 |
|
||||||
|
| BOOL | `<ciy-switch com="xxx" y="✔" n="✘" />` | 开关 |
|
||||||
|
| IMG1 | `<ciy-upload com="xxx" num="1" type="jpg,png" />` | 单图上传 |
|
||||||
|
| IMG | `<ciy-upload com="xxx" num="3" type="jpg,png" />` | 多图上传 |
|
||||||
|
| DOWN | `<ciy-upload com="xxx" num="3" type="pdf,docx,xlsx,zip" />` | 文件上传 |
|
||||||
|
| DATE | `<ciy-datetime com="xxx" />` | 日期选择 |
|
||||||
|
| TIME | `<ciy-timepoint com="xxx" />` | 时间点选择 |
|
||||||
|
| LOC | `<ciy-map com="xxx" />` | 地图选择 |
|
||||||
|
| BR | `<ciy-textarea com="xxx" />` | 多行文本 |
|
||||||
|
| MD | `<ciy-markdown com="xxx" />` | Markdown编辑器 |
|
||||||
|
| CNY | `<ciy-inputbet com="xxx" unit="元" bet="100" />` | 金额输入 |
|
||||||
|
| WGT | `<ciy-inputbet com="xxx" unit="KG" bet="1000" />` | 重量输入 |
|
||||||
|
| LGH | `<ciy-inputbet com="xxx" unit="米" bet="1000" />` | 长度输入 |
|
||||||
|
| PCT | `<ciy-inputbet com="xxx" unit="%" bet="100" />` | 百分比输入 |
|
||||||
|
| SEC | `<ciy-inputbet com="xxx" unit="秒" bet="1" />` | 时长输入 |
|
||||||
|
| CYC | `<ciy-inputcyc com="xxx" />` | 周期输入 |
|
||||||
|
| UNIT | `<ciy-inputunitedit com="xxx" />` | 单位编辑 |
|
||||||
|
| BET | `<ciy-inputbet com="xxx" unit="元" bet="100" />` | 小数输入 |
|
||||||
|
| INT | `<input type="text" name="xxx" />` | 普通输入 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据格式化对照表
|
||||||
|
|
||||||
|
| 组件名 | 存储值 | 显示值 |
|
||||||
|
|-------|-------|-------|
|
||||||
|
| CNY | 1000000 | 10,000.00元 |
|
||||||
|
| MCNY | 1000000 | 100.00元 |
|
||||||
|
| WCNY | 1000000 | 1.00万元 |
|
||||||
|
| WCNY | 10000000000 | 1.00亿元 |
|
||||||
|
| WGT | 1000 | 1.00千克 |
|
||||||
|
| WGT | 1000000 | 1.00吨 |
|
||||||
|
| LGH | 1000 | 1.00米 |
|
||||||
|
| LGH | 1000000 | 1.00公里 |
|
||||||
|
| PCT | 50 | 50.00% |
|
||||||
|
| SEC | 60 | 1分钟 |
|
||||||
|
| SEC | 3600 | 1小时 |
|
||||||
|
| CYC | 7*86400 | 7天 |
|
||||||
|
| CYC | -1 | 1月 |
|
||||||
|
| DATE | 1750889011 | 2025-03-18 10:23:31 |
|
||||||
|
| DATE,Y-m-d | 1750889011 | 2025-03-18 |
|
||||||
|
| TIME | 1 | 00:00 |
|
||||||
|
| TIME | 37201 | 10:20 |
|
||||||
|
| BOOL,✔.✘ | 1 | ✔ |
|
||||||
|
| BOOL,✔.✘ | 2 | ✘ |
|
||||||
|
| BOOL,开启.关闭 | 1 | 开启 |
|
||||||
|
| BOOL,开启.关闭 | 2 | 关闭 |
|
||||||
|
| FSIZE | 1024 | 1.00KB |
|
||||||
|
| FSIZE | 1048576 | 1.00MB |
|
||||||
|
| INT,分 | 100 | 100分 |
|
||||||
|
| INT,第?期 | 5 | 第5期 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 生成SQL
|
||||||
|
|
||||||
|
根据详细设计中的数据表设计。
|
||||||
|
通过中英文字段名,在列注释中给出最匹配的组件配置。
|
||||||
|
**索引**:不加索引。
|
||||||
|
**字段类型**:选择合适的类型(不要滥用 `text`)
|
||||||
|
**默认值**:设置合理的默认值
|
||||||
|
**禁止NULL**:避免NULL值带来的性能问题
|
||||||
|
|
||||||
|
生成CREATE TABLE语句。
|
||||||
|
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 组件选择建议
|
||||||
|
|
||||||
|
| 业务场景 | 推荐组件 | 原因 |
|
||||||
|
|---------|---------|------|
|
||||||
|
| 状态/类型/等级 | CATA | 方便维护字典 |
|
||||||
|
| 审核人/操作人 | CATU | 从用户表读取 |
|
||||||
|
| 树形分类 | CATM | 支持级联选择 |
|
||||||
|
| 多选标签 | CATS | 逗号分隔存储 |
|
||||||
|
| 开关状态 | BOOL | 直观易用 |
|
||||||
|
| 金额 | CNY/WCNY | 自动格式化 |
|
||||||
|
| 图片 | IMG1/IMG | 支持预览和上传 |
|
||||||
|
| 文件 | DOWN | 支持下载 |
|
||||||
|
| 富文本 | MD | Markdown支持 |
|
||||||
|
| 地理位置 | LOC | 地图选点 |
|
||||||
|
| 多级单位 | UNIT | 自动换算 |
|
||||||
|
|
||||||
|
|
||||||
|
## 使用PGSQL特殊字段
|
||||||
|
MariaDB/Mysql数据库不适用。
|
||||||
|
推荐使用geometry、vector、age图、jsonb、gin、array、range、brin等,以提升索引能力为主。
|
||||||
|
|
||||||
|
|
||||||
|
## 附录:参考文件
|
||||||
|
|
||||||
|
- `/c5_ciyon.sql` - 数据库SQL示例
|
||||||
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
# 数据库规划指导文档
|
||||||
|
|
||||||
|
你是数据库规划设计师。
|
||||||
|
Ciyon系统采用**元数据驱动**的设计理念。
|
||||||
|
通过**列注释**实现CURD页面源代码自动生成。
|
||||||
|
|
||||||
|
## 输出格式要求
|
||||||
|
|
||||||
|
每个数据表应按照下面模版格式输出,不要带任何 Markdown 格式:
|
||||||
|
|
||||||
|
```
|
||||||
|
数据表中文名1 数据表英文名1
|
||||||
|
中文列名称1(英文列名1)、中文列名称2(英文列名2)、中文列名称3(英文列名3)...
|
||||||
|
(如某些列有下拉的可选值)中文列名称: 可选值1、可选值2、可选值3...
|
||||||
|
|
||||||
|
数据表中文名2 数据表英文名2
|
||||||
|
中文列名称1(英文列名1)、中文列名称2(英文列名2)、中文列名称3(英文列名3)...
|
||||||
|
(如某些列有下拉的可选值)中文列名称: 可选值1、可选值2、可选值3...
|
||||||
|
```
|
||||||
|
|
||||||
|
**格式说明:**
|
||||||
|
- 第一行为数据表中文名称和英文名称
|
||||||
|
- 第二行为列字段
|
||||||
|
- 第三行及以后为某些列的可选值说明,可有可无
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```
|
||||||
|
版块文章表 ap_art_post
|
||||||
|
文章状态(artstatus)、版块(sectionid)、文章标题(name)、来源(source)、作者(author)、精读数(studycnt)、阅读数(readcnt)、缩略图(img)、摘要(descs)、撰写人(inputuser)、审核人(audituser)、发布时间(pubtimes)、内容(content)
|
||||||
|
文章状态: 待审核.已发布.已下架
|
||||||
|
|
||||||
|
版块表 ap_art_section
|
||||||
|
版块名称(name)、分组名(ngroup)、责任人(adminuser)、待审数(auditcnt)、文章数(artcnt)、创建时间(addtimes)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 数据库规划方法
|
||||||
|
|
||||||
|
### 表命名规则
|
||||||
|
|
||||||
|
1. **格式**:`前缀_主表英文名`
|
||||||
|
2. **避免下划线**:英文名尽量不用下划线
|
||||||
|
3. **使用缩写**:英文名要短,使用常用缩写
|
||||||
|
|
||||||
|
### 主子表命名
|
||||||
|
|
||||||
|
- 主表:`xx_task`
|
||||||
|
- 子表:`xx_taslog`
|
||||||
|
- **改主表名** 修改主表为 `xx_taskbase`
|
||||||
|
- 确保:搜索主表名不会匹配到子表名
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字段命名规则
|
||||||
|
|
||||||
|
| 英文列名 | 说明 | 示例 |
|
||||||
|
|---------|------|------|
|
||||||
|
| `id` | 自增主键 | - |
|
||||||
|
| `vuser` | 所属用户ID(整个表只有一个用户字段用前缀v) | `vuser` |
|
||||||
|
| `addtimes` | 添加时间(自动生成代码,在insert时赋值now) | `addtimes` |
|
||||||
|
| `uptimes` | 更新时间(自动生成代码,添加更新均赋值now) | `uptimes` |
|
||||||
|
| `name` | 名称/标题 | `name` |
|
||||||
|
| `csort` | 排序 | `csort` |
|
||||||
|
| `upid` | 上级父ID | `upid` |
|
||||||
|
| `descs` | 描述 | `descs` |
|
||||||
|
| `{表名}id` | 关联表ID | `sectionid` |
|
||||||
|
| `{缩写}user` | 其他用户关联 | `audituser`, `selleruser` |
|
||||||
|
| `{缩写}times` | 时间日期 | `audittimes`, `pubtimes` |
|
||||||
|
| `{缩写}status` | 状态 | `artstatus`, `cashstatus` |
|
||||||
|
| `{缩写}type` | 类型 | `ordertype`, `paytype` |
|
||||||
|
| `{缩写}level` | 等级 | `userlevel`, `auditlevel` |
|
||||||
|
| `{缩写}img` | 单图 | `bannerimg` |
|
||||||
|
| `{缩写}imgs` | 多图 | `bannerimgs` |
|
||||||
|
| `{缩写}file` | 单文件 | `docfile` |
|
||||||
|
| `{缩写}files` | 多文件 | `docfiles` |
|
||||||
|
|
||||||
|
**注意事项:**
|
||||||
|
- 不要直接使用 `desc`,使用 `descs`
|
||||||
|
- 不要直接使用 `key`,使用 `keyw`
|
||||||
|
- 英文列名除上述表格通用名称外,其余列名应全局唯一
|
||||||
|
- 字典列,应全局字典名唯一
|
||||||
|
- 列名与字典名要相同。
|
||||||
|
|
||||||
|
- **字段名要有语义性**:避免使用过于简短或通用的字段名,如 `mode`、`status`、`type`、`opt` 等,应使用具有明确语义的名称,如 `attrmode`、`bookopt` 等。
|
||||||
|
|
||||||
|
### 特殊字段类型
|
||||||
|
|
||||||
|
**坐标字段**:
|
||||||
|
- 经纬度坐标使用 `lat`(纬度)和 `lng`(经度)字段名
|
||||||
|
- 存储格式:将实际值乘以 1000000 后存储为整数
|
||||||
|
- 例如:实际值 30.258912 → 存储为 30258912
|
||||||
|
- 目的:避免浮点数精度问题,提高查询效率
|
||||||
|
- 前端使用时需除以 1000000 恢复原始值
|
||||||
|
|
||||||
|
### 中文列名规则
|
||||||
|
|
||||||
|
- **长度**:尽量简短
|
||||||
|
- **含义**:清晰描述列的含义
|
||||||
|
- **对齐标记**:
|
||||||
|
- CATA/CATU/BOOL/URL 组件:`|状态|`(居中)
|
||||||
|
- BET/CNY/WGT/PCT/TC/METRE/SEC/INT/CYC 组件:`金额|`(右对齐)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## 数据表英文名要求
|
||||||
|
|
||||||
|
- 格式为"统一前缀_主表英文名"
|
||||||
|
- 英文名尽量不要有下划线
|
||||||
|
- 英文名尽量用缩写,短一些
|
||||||
|
- 英文子表名与英文主表名如果是包含关系,在主表名后面适当少一个字母或主表后加 base,确保搜索主表名不会搜到子表名
|
||||||
|
|
||||||
|
## 英文列名要求
|
||||||
|
|
||||||
|
- 尽量不要有下划线
|
||||||
|
- 状态 status/type/level 等通用字段,要用专有单词 + 通用单词,英文列名保证整个输出的文本唯一(例如 table123status、table123type 等)
|
||||||
|
- 添加时间,统一用 addtimes。每个表第一个时间用这个单词
|
||||||
|
- 添加人关联的用户 ID,统一用 vuser。每个表第一个用户用这个单词
|
||||||
|
- 简易审批的列名称,统一用 audituser/audittimes/auditstatus/auditmsg
|
||||||
|
- 集中审批的列名称,只需要 auditstatus,具体审批功能在通用审批表
|
||||||
|
- 更新时间,统一用 uptimes
|
||||||
|
- 整个表中,尽量有一个英文列名为 name 的列。每个表的标题、名称等,用这个单词
|
||||||
|
- 排序列,统一用 csort
|
||||||
|
- 上级父 ID,统一用 upid
|
||||||
|
- 与其他表关联的所属列,例如所属项目,统一用"所属主表英文名"
|
||||||
|
- 其他用户关联,例如卖家,统一用 xxuser。以 user 结尾
|
||||||
|
- 自增 ID,统一用 id
|
||||||
|
- 代表时间日期的英文列名,应以 times 为结尾
|
||||||
|
- 不要直接用 desc,如需要可用 descs
|
||||||
|
- 不要直接用 key,如需要可用 keyw
|
||||||
|
- 与图片上传、附件有关的列,单个文件的,以 img、file 为结尾。多个附件的,以 imgs、files 结尾
|
||||||
|
- 英文列名仅填英文,不包含其他任何包含可选值的信息
|
||||||
|
|
||||||
|
## 中文列名要求
|
||||||
|
|
||||||
|
尽量限制在 2-6 个字以内,描述清楚列的含义。
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Ciyon测试用例 Skill指南
|
||||||
|
|
||||||
|
## 框架概述
|
||||||
|
|
||||||
|
CiYon是一个基于uniapp的轻量级跨平台移动应用开发框架,采用Vue3 + Vite技术栈,支持小程序、H5、App多端发布。
|
||||||
|
|
||||||
|
## 测试用例
|
||||||
|
为每个API接口编写两个测试脚本及数据集
|
||||||
|
红数据数据集,接口一定会报错
|
||||||
|
蓝数据数据集,接口一定会成功
|
||||||
|
每个接口必须先写测试脚本及红蓝测试数据集。
|
||||||
|
|
||||||
|
## API命名规范
|
||||||
|
测试脚本中的API调用必须遵循命名规范:
|
||||||
|
- 前端调用格式:`{模块名}.{页面名}_{操作名}`
|
||||||
|
- 后端函数名:`json_{页面名}_{操作名}`
|
||||||
|
- 例如:前端 `func: 'aimap.index_init'`,后端函数 `json_index_init()`
|
||||||
|
- 测试时需确保前端 func 参数与后端函数名完全对应
|
||||||
|
|
@ -0,0 +1,491 @@
|
||||||
|
# Ciyon移动端开发框架 Skill指南
|
||||||
|
|
||||||
|
## 框架概述
|
||||||
|
|
||||||
|
CiYon是一个基于uniapp的轻量级跨平台移动应用开发框架,采用Vue3 + Vite技术栈,支持小程序、H5、App多端发布。
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
ai_mapshare/
|
||||||
|
├── fapp/ciyon_ap/ # uniapp移动端项目
|
||||||
|
│ ├── pages/ # 页面目录
|
||||||
|
│ │ ├── main/ # 参考主页面
|
||||||
|
│ │ ├── me/ # 个人中心
|
||||||
|
│ │ ├── pub/ # 公共页面
|
||||||
|
│ │ └── demo/ # 示例页面
|
||||||
|
│ ├── components/ # 60+自定义组件库
|
||||||
|
│ ├── util/ # 工具函数库
|
||||||
|
│ ├── static/ # 静态资源
|
||||||
|
│ ├── App.vue # 应用入口
|
||||||
|
│ ├── main.js # 主入口文件
|
||||||
|
│ ├── pages.json # 页面配置
|
||||||
|
│ ├── manifest.json # 应用配置
|
||||||
|
│ └── vite.config.js # Vite配置
|
||||||
|
```
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- **前端**: Vue3 + Vite + Uniapp
|
||||||
|
- **通信**: HTTP POST API(JSON)
|
||||||
|
- **参考页面**:
|
||||||
|
- /fapp/ciyon_ap/pages/demo/curd/demo_list.vue
|
||||||
|
- /fapp/ciyon_ap/pages/demo/curd/demo_edit.vue
|
||||||
|
- /fapp/ciyon_ap/pages/main/index.vue
|
||||||
|
- /fapp/ciyon_ap/pages/main/me.vue
|
||||||
|
|
||||||
|
|
||||||
|
## 开发规范
|
||||||
|
|
||||||
|
### 页面开发规范
|
||||||
|
|
||||||
|
- 页面存放在 `pages/` 对应模块目录下
|
||||||
|
- 页面注册在 `pages.json` 中配置路由
|
||||||
|
- 使用uniapp标准生命周期
|
||||||
|
|
||||||
|
### 目录及文件名命名规范
|
||||||
|
|
||||||
|
- 在`pages/`下新建项目目录
|
||||||
|
- `/pages/[项目目录]/index.vue`作为首页主页面
|
||||||
|
- `/pages/[项目目录]/me.vue` 作为个人中心主页面
|
||||||
|
- `/pages/[项目目录]/xx_xx.vue` 其他页面均要有一定含义,建议与数据表名称相关。模块_功能
|
||||||
|
- 例如:`order_list.vue` 列表页、`order_info.vue` 详情页、`order_edit.vue` 编辑页、`order_ship.vue` 功能页
|
||||||
|
- 例如: `user_info.vue`、`user_order.vue`、`user_address.vue`
|
||||||
|
- 页面起名尽量贴合业务,不要用`detail.vue`、`list.vue`、`edit.vue`、`add.vue`等通用名称。
|
||||||
|
|
||||||
|
### vue文件API方法命名规范
|
||||||
|
|
||||||
|
- 页面初始化方法一般为`init`
|
||||||
|
- func: 'xx.xx_init'
|
||||||
|
- 列表页,初始化传入once(bool)参数,once=true,首次请求获取初始化数据
|
||||||
|
this.pagepost.once = !this.init.once;
|
||||||
|
参考 /fapp/ciyon_ap/pages/demo/curd/demo_list.vue
|
||||||
|
参考 /fapp/ciyon_ap/pages/demo/curd/demo_edit.vue
|
||||||
|
API参考 /web/ampap/demo/demo.php
|
||||||
|
- 更新 `update`、删除 `delete`、审核 `audit`等方法按此命名。
|
||||||
|
|
||||||
|
- 综合举例:
|
||||||
|
- 前端文件: /pages/[项目目录]/[模块]_list.vue
|
||||||
|
- 前端调用: this.callfunc({func:'[模块].[功能]_init'})、this.callfunc({func:'[模块].[功能]_delete'})
|
||||||
|
- 后端文件: /web/am[项目目录]/[模块].php
|
||||||
|
- 后端函数: json_[功能]_init()、json_[功能]_delete()
|
||||||
|
|
||||||
|
|
||||||
|
### 组件使用规范
|
||||||
|
|
||||||
|
组件前缀统一使用 `ciy-`,已提供60+组件:
|
||||||
|
|
||||||
|
**表单组件**:
|
||||||
|
- `ciy-input` - 基础输入框
|
||||||
|
- `ciy-textarea` - 文本域
|
||||||
|
- `ciy-select` - 选择器
|
||||||
|
- `ciy-radio` - 单选
|
||||||
|
- `ciy-checkbox` - 复选
|
||||||
|
- `ciy-checkitem` - 检查项
|
||||||
|
- `ciy-switch` - 开关
|
||||||
|
- `ciy-selbool` - 布尔选择
|
||||||
|
- `ciy-selcas` - 级联选择
|
||||||
|
- `ciy-selpage` - 页面选择
|
||||||
|
- `ciy-slider` - 滑块
|
||||||
|
- `ciy-inputnumber` - 数字输入
|
||||||
|
- `ciy-inputbet` - 范围输入
|
||||||
|
- `ciy-inputcyc` - 周期输入
|
||||||
|
- `ciy-inputdatetime` - 日期时间
|
||||||
|
- `ciy-inputdaterange` - 日期范围
|
||||||
|
- `ciy-inputtimepoint` - 时间点
|
||||||
|
- `ciy-inputunitedit` - 单位编辑
|
||||||
|
- `ciy-inputocr` - OCR输入
|
||||||
|
- `ciy-capcode` - 验证码输入
|
||||||
|
- `ciy-searchbar` - 搜索栏
|
||||||
|
- `ciy-query` - 查询组件
|
||||||
|
- `ciy-selmap` - 地图选择位置
|
||||||
|
- `ciy-mapbox` - 地图展示组件(基于 Leaflet)
|
||||||
|
- `ciy-upload` - 文件上传
|
||||||
|
|
||||||
|
**展示组件**:
|
||||||
|
- `ciy-showmoney` - 金额展示
|
||||||
|
- `ciy-shownum` - 数字展示
|
||||||
|
- `ciy-showimgs` - 多图片展示
|
||||||
|
- `ciy-textmore` - 文本展开
|
||||||
|
- `ciy-chart-pie` - 饼图
|
||||||
|
- `ciy-markdown` - Markdown渲染
|
||||||
|
- `ciy-svgimg` - 单图片显示
|
||||||
|
- `ciy-totalsem` - 总计语义
|
||||||
|
- `ciy-gesture` - 手势识别
|
||||||
|
- `ciy-handsign` - 手势识别
|
||||||
|
- `ciy-audio` - 音频播放
|
||||||
|
|
||||||
|
**功能组件**:
|
||||||
|
- `ciy-camera` - 相机(在ciy-aicameraocr中)
|
||||||
|
- `ciy-aivoice` - AI语音
|
||||||
|
- `ciy-gesture` - 手势识别
|
||||||
|
- `ciy-handsign` - 手势识别
|
||||||
|
- `ciy-btreader` - 蓝牙读卡器
|
||||||
|
- `ciy-header` - 页面头部
|
||||||
|
- `ciy-tabbar` - 底部导航
|
||||||
|
- `ciy-dialog` - 弹窗
|
||||||
|
- `ciy-toast` - 提示
|
||||||
|
- `ciy-alert` - 警告
|
||||||
|
- `ciy-popmenu` - 弹出菜单
|
||||||
|
- `ciy-calendar` - 日历
|
||||||
|
- `ciy-ratestar` - 评分
|
||||||
|
- `ciy-segment` - 分段器
|
||||||
|
- `ciy-swiper` - 轮播
|
||||||
|
- `ciy-swipelist` - 滑动列表
|
||||||
|
- `ciy-listend` - 列表底部
|
||||||
|
- `ciy-movable` - 可移动
|
||||||
|
|
||||||
|
**动画组件**:
|
||||||
|
- `ciy-ani` - 动画
|
||||||
|
- `ciy-aniheight` - 高度动画
|
||||||
|
- `ciy-anipop` - 弹出动画
|
||||||
|
|
||||||
|
**认证组件**:
|
||||||
|
- `ciy-auth` - 认证
|
||||||
|
|
||||||
|
**自定义组件**:
|
||||||
|
- `diy-apuser` - AP用户
|
||||||
|
- `diy-xxlist` - XX列表
|
||||||
|
|
||||||
|
**调试组件**:
|
||||||
|
- `ciy-dbg` - 调试
|
||||||
|
|
||||||
|
### API通信规范
|
||||||
|
|
||||||
|
**请求封装**:
|
||||||
|
```javascript
|
||||||
|
// 使用 callfunc 方法调用API
|
||||||
|
await this.callfunc({
|
||||||
|
func: 'main.index_init', // API函数名,格式:后端API文件名.前端页面名_方法
|
||||||
|
data: { // 要发送的数据
|
||||||
|
id: 123,
|
||||||
|
name: 'test'
|
||||||
|
},
|
||||||
|
srv: 't', // 服务器标识,默认't'
|
||||||
|
loadhide: false, // 是否隐藏加载提示,默认false
|
||||||
|
cache: 0, // 缓存时间(秒),0不缓存,一般不缓存
|
||||||
|
cachekey: '' // 自定义缓存键
|
||||||
|
}).then(res => {
|
||||||
|
// 处理响应
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**API路径规则**:
|
||||||
|
- 前端调用格式:`{func: 'module.method'}`
|
||||||
|
- URL映射:通过 `jsnurl` 配置映射到实际URL
|
||||||
|
- API命名与页面关联:方法名应与前端页面文件名对应,便于识别和维护。格式建议:`{后端API文件名}.{前端页面名}_{操作方法名}`
|
||||||
|
- 示例:`{func: 'aaa.index_init'}` 对应后端API `/web/ambap/aaa.php`、对应移动端 `pages/aaa/index.vue`
|
||||||
|
- 示例:`{func: 'bbb.detail_init'}` 对应后端API `/web/ambap/bbb.php`、对应移动端 `pages/bbb/detail.vue`
|
||||||
|
- 示例:
|
||||||
|
- 前端调用:`{func: 'main.index_init'}`
|
||||||
|
- 另一个示例:`{func: 'login.login_mobile'}`
|
||||||
|
- **重要**:后端函数名必须与前端的 func 参数完全一致,例如前端 `func: 'aimap.index_init'`,后端函数名为 `json_index_init()`
|
||||||
|
|
||||||
|
**响应格式**:
|
||||||
|
```javascript
|
||||||
|
// 成功响应
|
||||||
|
{
|
||||||
|
code: 1, // 1表示成功
|
||||||
|
// 其他业务数据...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 失败响应
|
||||||
|
{
|
||||||
|
code: 非1, // 非1表示失败,2表示需要重新登录
|
||||||
|
errmsg: '错误信息', // 错误提示
|
||||||
|
// 其他错误数据...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 工具函数
|
||||||
|
|
||||||
|
**util/ciy.js** - 核心工具库:
|
||||||
|
|
||||||
|
**API请求**:
|
||||||
|
- `callfunc(opt)` - 统一API请求方法
|
||||||
|
- `calltxt(opt)` - 纯文本请求
|
||||||
|
|
||||||
|
**存储管理**:
|
||||||
|
- `getstorage(key, def)` - 读取storage
|
||||||
|
- `setstorage(key, val)` - 写入storage
|
||||||
|
- `removestorage(key)` - 删除storage(支持通配符*)
|
||||||
|
- `clearstorage()` - 清空所有storage
|
||||||
|
|
||||||
|
**用户认证**:
|
||||||
|
- `getauth()` - 获取用户信息,未登录自动调起登录
|
||||||
|
|
||||||
|
**提示交互**:
|
||||||
|
- `alert(content)` - 弹窗提示(await)
|
||||||
|
- `toast(content, icon)` - 轻提示(await)
|
||||||
|
- `askmsg(content)` - 询问确认框(await)
|
||||||
|
- `inputmsg(content, def)` - 输入框(await)
|
||||||
|
- `popmenu(options)` - 弹出上拉菜单(await)
|
||||||
|
|
||||||
|
**页面跳转**:
|
||||||
|
- `gourl(url, type, initdata, initkey)` - 页面跳转
|
||||||
|
- `http://` - 打开H5页面
|
||||||
|
- `!` - 打开原型图页面
|
||||||
|
- `*` - alert提示
|
||||||
|
- `$` - 需要登录
|
||||||
|
- `%` - 需要登录且完善信息
|
||||||
|
- `^` - 需要登录且实名认证
|
||||||
|
- `&` - 需要登录且绑定银行卡
|
||||||
|
- `goweb(url, name)` - 带授权打开H5页面
|
||||||
|
- `goloc(lat, lng, bet)` - 打开地图
|
||||||
|
- `gophone(phone)` - 拨打电话
|
||||||
|
|
||||||
|
**数据处理**:
|
||||||
|
- `json_parse(data)` - 字符串转json
|
||||||
|
- `json_string(data)` - json转字符串
|
||||||
|
- `toint(val)` - 转整数
|
||||||
|
- `tofloat(val)` - 转小数
|
||||||
|
- `tostr(val)` - 转字符串
|
||||||
|
- `tostamp(val)` - 转时间戳
|
||||||
|
- `todatetime(val)` - 时间戳转日期时间
|
||||||
|
- `tofix(val, dec)` - 处理小数显示
|
||||||
|
- `tounit(val)` - 显示多级单位
|
||||||
|
- `tocyc(val)` - 显示周期 月/天/分钟
|
||||||
|
- `tomsk(val)` - 显示文字遮罩
|
||||||
|
- `totimespan(val)` - 将时间转成 xx天后/xx小时前
|
||||||
|
- `totimesec(val)` - 将秒数转成 xx天/xx小时
|
||||||
|
- `totimepoint(val)` - 将数字转成 xx:xx[:xx]
|
||||||
|
- `todayage(val)` - 返回日龄天数
|
||||||
|
- `tobr(val)` - 将\n替换成<br/>,用于显示多行文本。结合 v-html 使用:`v-html="tobr(item.descs)"`
|
||||||
|
- `topad0(num, len)` - 数字前面补0
|
||||||
|
- `tonumtho(num)` - 整数部分千分位显示
|
||||||
|
- `tonumdec(num)` - 小数部分
|
||||||
|
|
||||||
|
**类型校验**:
|
||||||
|
- `isfloat0(val)` - 校验float是否0
|
||||||
|
- `isarray(val)` - 判断是否array
|
||||||
|
- `isobject(val)` - 判断是否object
|
||||||
|
- `islocalmedia(val)` - 判断是否本地文件
|
||||||
|
- `isimg(val)` - 是否图片
|
||||||
|
- `isvideo(val)` - 是否视频
|
||||||
|
- `file_ext(filename)` - 获取文件扩展名
|
||||||
|
- `file_stor(url)` - db存储的url转云存储的绝对url
|
||||||
|
|
||||||
|
**字典处理**:
|
||||||
|
- `ccode(catalog, val, key, def)` - 以id查询字典中的值
|
||||||
|
- `scode(catalog, vals, key)` - 以ids查询字典中的多个name
|
||||||
|
- `mcode(catalog, val)` - 以id查询字典中的多级name
|
||||||
|
- `bcode(catalog, val)` - 以int查询字典中的多个name
|
||||||
|
- `hascode(val, codes)` - 某个数字是否在多个数字中
|
||||||
|
- `hasstr(str, substr)` - 字符串是否包含另一个字符串
|
||||||
|
|
||||||
|
**编码转换**:
|
||||||
|
- `enbase64(str)` - base64编码
|
||||||
|
- `svg2bg(svg)` - 将svg转成backgroundImage语法
|
||||||
|
|
||||||
|
**其他工具**:
|
||||||
|
- `sleep(ms)` - 延迟毫秒(await)
|
||||||
|
- `copyboard(text)` - 拷贝文本
|
||||||
|
- `getstrparam(str, sep)` - 解析简易参数
|
||||||
|
- `urlparam(url)` - 解析url
|
||||||
|
- `shareparam(opt)` - 分享链接转换
|
||||||
|
- `arrayfind(arr, val)` - 从数组中匹配值
|
||||||
|
- `objdeepmerge(dest, src)` - object合并
|
||||||
|
- `objtolist(list, obj/id)` - 将object并入list数组,将id从list数组中移除
|
||||||
|
- `objclone(obj)` - 深度复制obj
|
||||||
|
- `str2date(str)` - 字符串转Date
|
||||||
|
- `bin2hex(bin)` - bin转hex字符串
|
||||||
|
- `hex2bin(hex)` - hex字符串转bin
|
||||||
|
- `style2obj(style)` - 将style属性转成object
|
||||||
|
- `nopower(power)` - 权限检查
|
||||||
|
- `getroute()` - 获取当前路由
|
||||||
|
- `getpage(idx)` - 获取当前/上页页面
|
||||||
|
- `getrect(selector)` - 获取元素尺寸(await)
|
||||||
|
- `file_upload1(file)` - 上传单个文件返回url(await)
|
||||||
|
- `file_uploads(files)` - 上传多个文件(await)
|
||||||
|
- `go(e, cb)` - golang式异步错误处理
|
||||||
|
- `goe(e, cb)` - golang式异步错误处理(增强版)
|
||||||
|
|
||||||
|
**页面控制**:
|
||||||
|
- `pagenoscroll(isno)` - 禁止页面滚动
|
||||||
|
- `settheme()` - 设置暗黑模式
|
||||||
|
- `setfont()` - 设置敬老模式
|
||||||
|
- `setTabbar()` - 设置Tabbar
|
||||||
|
- `executepnt(pntid)` - 触发积分埋点
|
||||||
|
|
||||||
|
**加载资源**:
|
||||||
|
- `load_ciydict()` - 获取远程静态dict(await)
|
||||||
|
- `load_svgicon(url)` - 获取远程静态svgicon(await)
|
||||||
|
|
||||||
|
**扫描功能**:
|
||||||
|
- `scanqr()` - 扫二维码(await)
|
||||||
|
|
||||||
|
### 开发流程
|
||||||
|
|
||||||
|
**App.vue 全局配置**:
|
||||||
|
- app.globalData.jsnurl.t,配置入口域名的API入口 例如 'https://ciyon.local.ciy.cn/ambap/'
|
||||||
|
- 在development中 配置本地的入口域名的API入口(用于调试,一般以.local.ciy.cn为主体)
|
||||||
|
- app.globalData.tabbarArr,作为底部TabBar定义,全局定义给ciy-tabbar组件使用。
|
||||||
|
- tabbar虽然自定义,但pages.json需正常配置。且App.vue的globalData.mainpage应指向首页。
|
||||||
|
- tabbar图标用svg定义,默认双色模式。选中颜色bgsel1/bgsel2,未选中颜色bggray1/bggray2。
|
||||||
|
- **tabbarArr 配置要点**:
|
||||||
|
- `fullpath` 必须与实际页面路径一致,如 `/pages/aimap/index`
|
||||||
|
- `name` 使用 i18n 代码,需在 `util/lang/*.json` 中同步配置翻译
|
||||||
|
- 所有 tabbar 页面都必须在模板底部添加 `<ciy-tabbar ref="tabbar"></ciy-tabbar>` 组件
|
||||||
|
- **语言翻译配置**:所有 tabbar 的 name(如 tabbar.topic、tabbar.msg)需在所有语言文件(zh-Hans.json、en.json、zh-Hant.json、ja.json、fr.json)中添加对应的翻译
|
||||||
|
|
||||||
|
**新建页面**:
|
||||||
|
1. 在 `pages/` 对应模块下创建 `.vue` 文件
|
||||||
|
2. 在 `pages.json` 中注册页面路由
|
||||||
|
3. 使用组件和工具函数开发功能
|
||||||
|
|
||||||
|
**新建组件**:
|
||||||
|
1. 在 `components/` 下创建组件目录和文件
|
||||||
|
2. 组件名使用 `ciy-` 前缀
|
||||||
|
3. 支持通过 props 传递参数
|
||||||
|
4. 通过 $emit 触发事件
|
||||||
|
5. 有用户的明确指令,才能新建组件
|
||||||
|
|
||||||
|
**调用API**:
|
||||||
|
1. 确定API函数名,格式:`模块.方法`,如 `main.index_init`
|
||||||
|
2. 使用 `callfunc()` 发送请求:
|
||||||
|
```javascript
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'main.index_init',
|
||||||
|
data: {
|
||||||
|
id: 123
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return this.alert(retjson.errmsg);
|
||||||
|
// 处理成功响应
|
||||||
|
```
|
||||||
|
3. 处理返回数据,成功时 `code=1`,失败时有 `errmsg`
|
||||||
|
|
||||||
|
**首次请求优化**:
|
||||||
|
页面首次加载通过 `once` 标志位一次性返回所有初始化数据,减少后续翻页重复带出初始化数据:
|
||||||
|
```javascript
|
||||||
|
async getlist() {
|
||||||
|
this.pagepost.pageno = this.pageno + 1;
|
||||||
|
this.pagepost.once = !this.init.once;
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'demo.index_list',
|
||||||
|
data: this.pagepost
|
||||||
|
});
|
||||||
|
this.pageno++;
|
||||||
|
if (this.pageno == 1)
|
||||||
|
this.init.list = [];
|
||||||
|
this.init = this.objdeepmerge(this.init, retjson);
|
||||||
|
if (retjson.once) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 样式规范
|
||||||
|
|
||||||
|
- 全局样式: `util/style.css`
|
||||||
|
- 组件内使用 scoped CSS
|
||||||
|
- 使用 rem 单位适配
|
||||||
|
|
||||||
|
### 常用组件
|
||||||
|
**表单组件**:ciy-input、ciy-select、ciy-radio、ciy-checkbox、ciy-selbool、ciy-inputbet、ciy-upload等
|
||||||
|
**展示组件**:ciy-showmoney、ciy-showimgs、ciy-markdown等
|
||||||
|
**功能组件**:ciy-auth、ciy-dialog、ciy-toast、ciy-popmenu等
|
||||||
|
**导航组件**:
|
||||||
|
- ciy-header - 页面头部(所有页面使用,navigationStyle为custom)
|
||||||
|
- ciy-tabbar - 底部导航(tabbar页面必须添加)
|
||||||
|
- ciy-segment - 分段器(使用 `:lis` 属性传递数组,如 `:lis="[{id:1,name:'选项1'}]"`,不要使用 `:options`)
|
||||||
|
|
||||||
|
**地图组件**:
|
||||||
|
- ciy-selmap - 国内地图选择组件(微信小程序用)
|
||||||
|
- ciy-mapbox - 通用地图展示选择组件(基于 Leaflet)
|
||||||
|
- 经纬度在数据库中存储时,应乘以 10000000,取整数
|
||||||
|
- 例如:30.2589121 → 存储为 302589121
|
||||||
|
- 在前端使用时,除以 10000000 恢复原始值
|
||||||
|
|
||||||
|
**ciy-mapbox组件地图瓦片提供商**:
|
||||||
|
- 推荐使用 Esri World Imagery(卫星影像)+ CartoDB Positron Labels(标注层)
|
||||||
|
- Esri World Imagery 提供高质量的卫星影像,适合展示地理位置
|
||||||
|
- CartoDB 标注层提供清晰的文字标注,可叠加在影像层上方
|
||||||
|
|
||||||
|
**复杂查询组件**:
|
||||||
|
- ciy-query - 支持多种输入类型(input、select、checkbox、radio、date、range等)
|
||||||
|
|
||||||
|
|
||||||
|
### 常用配置
|
||||||
|
|
||||||
|
**pages.json** - 页面配置:
|
||||||
|
- 页面路由
|
||||||
|
- 导航栏样式
|
||||||
|
- 底部TabBar(仅需配置 `pagePath`,其他配置由 App.vue 的 `tabbarArr` 定义)
|
||||||
|
- 全局样式
|
||||||
|
- 分包配置:主包放置核心页面(如 aimap、pub),其他功能页面放入子包以优化性能
|
||||||
|
|
||||||
|
**manifest.json** - 应用配置:
|
||||||
|
|
||||||
|
**manifest.json** - 应用配置:
|
||||||
|
- 应用信息
|
||||||
|
- 权限配置
|
||||||
|
- SDK配置
|
||||||
|
- 多端打包设置
|
||||||
|
|
||||||
|
**vite.config.js** - 构建配置:
|
||||||
|
- 别名配置
|
||||||
|
- 插件配置
|
||||||
|
- 构建优化
|
||||||
|
- 所有页面编译时都带ciy-auth、ciy-alert、ciy-toast、ciy-popmenu组件,无需手写
|
||||||
|
|
||||||
|
## 框架已完成事项(无需开发)
|
||||||
|
|
||||||
|
### 注册登录、找回密码功能与后端login.*接口
|
||||||
|
复用,基本无需修改ciy-auth组件和login API接口
|
||||||
|
新建,需复制ap_user、ap_usr_*有关表结构。
|
||||||
|
登录成功,自动同时加载所有字典项到前端,前端缓存到localstorage备用。
|
||||||
|
|
||||||
|
### 默认navigationStyle为custom
|
||||||
|
使用ciy-header组件定义顶部标题栏。可复制新组件自定义。
|
||||||
|
使用ciy-tabbar组件定义底部导航栏。可复制新组建自定义样式。已自动隐藏系统自带的默认tabbar。
|
||||||
|
|
||||||
|
### 已完成通用组件
|
||||||
|
任意页面均支持未登录 弹出登录/注册界面。
|
||||||
|
弹出框已美化,支持ciy-alert、ciy-toast
|
||||||
|
弹出菜单已美化,ciy-popmenu组件,支持多种排版方式,突破了默认组件的数量限制。
|
||||||
|
|
||||||
|
### 已给所有page注入通用变量
|
||||||
|
this.g,为所有缓存的字典项
|
||||||
|
this.me,为登录的用户完整数据
|
||||||
|
this.init,作为页面初始化,统一接收后端请求返回的数据。一般用this.init.code!=1作为骨架屏标识。
|
||||||
|
this.opn,页面传入参数可随意使用,不用在onload另行存储。
|
||||||
|
this.pageno,翻页页码
|
||||||
|
this.pagedata,页面间传递数据,对于页面深度点击传参非常有效。可替代vuex/Pinia
|
||||||
|
this.pagepost,页面object变量
|
||||||
|
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **命名规范**: 组件统一使用 `ciy-` 前缀目录
|
||||||
|
2. **API调用**: 使用 `callfunc()` 方法,函数名格式为 `模块.方法`,后端函数名必须与前端 func 参数对应
|
||||||
|
3. **Token管理**: 自动处理Token,无需手动管理,Token存储在 `localStorage` 中
|
||||||
|
4. **响应格式**: 成功 `{code: 1, ...}`,失败 `{code: 非1, errmsg: '错误信息', ...}`
|
||||||
|
5. **组件复用**: 优先使用现有组件,避免重复开发
|
||||||
|
6. **多端适配**: 使用uniapp条件编译处理平台差异
|
||||||
|
7. **性能优化**:
|
||||||
|
- 使用 `cache` 参数设置缓存时间
|
||||||
|
- 避免频繁请求
|
||||||
|
- 使用 `loadhide: true` 取消不必要的加载提示
|
||||||
|
- 合理使用分包,主包放置核心页面,其他功能放入子包
|
||||||
|
8. **页面跳转**: 使用 `gourl()` 方法,支持多种特殊前缀($需要登录、*提示等)
|
||||||
|
9. **数据传递**: 使用 `pagedata` 对象进行页面间数据传递
|
||||||
|
10. **字典数据**: 通过 `g` 对象访问字典数据,自动同步更新
|
||||||
|
11. **用户信息**: 通过 `me` 对象访问当前用户信息
|
||||||
|
12. **路由参数**: 通过 `opn` 对象访问页面URL参数
|
||||||
|
13. **用户认证**: 注册、登录、找回密码等功能已集成在 `ciy-auth` 组件中,直接复用,无需重复开发
|
||||||
|
14. **TabBar配置**:
|
||||||
|
- pages.json 中只配置 `pagePath`,其他样式由 App.vue 的 `tabbarArr` 定义
|
||||||
|
- tabbarArr 中的 `fullpath` 必须与实际页面路径完全一致
|
||||||
|
- 所有 tabbar 页面必须在模板底部添加 `<ciy-tabbar ref="tabbar"></ciy-tabbar>`
|
||||||
|
- tabbarArr 中的 `name` 需在所有语言文件中配置翻译
|
||||||
|
15. **组件使用注意**:
|
||||||
|
- ciy-segment 使用 `:lis` 属性传递数组,不要使用 `:options`
|
||||||
|
- 遵循框架定义的属性名称,避免使用非标准属性
|
||||||
|
|
||||||
|
## 编译及自动调试
|
||||||
|
运行cmd,编译移动端H5
|
||||||
|
"D:\Program Files\HBuilderX\cli.exe" publish --platform h5 --project "D:\Dreams\ciy\ai_xxx\fapp\ciyon_ap" --webTitle 众产
|
||||||
|
|
||||||
|
编译后访问: https://xxx.local.ciy.cn/ 调试
|
||||||
|
|
@ -0,0 +1,816 @@
|
||||||
|
# Ciyon网站开发Skill指南 - AI驱动的SEO/GEO优化系统
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
Ciyon框架采用原生PHP+JS开发,专注SEO优化和搜索引擎友好性。通过AI自动生成文章、定时发布、关键词管理等功能,实现网站的自动化SEO优化,适合快速搭建企业官网、博客、内容管理系统。
|
||||||
|
|
||||||
|
- **AI自动生成文章**:关键词自动生成、推广方向设计、文章可读性与SEO结合
|
||||||
|
- **SEO优化**:针对传统搜索引擎(Google、百度)
|
||||||
|
- **GEO优化**:针对AI搜索引擎(ChatGPT、Claude、Bing AI)
|
||||||
|
|
||||||
|
|
||||||
|
### 核心模块
|
||||||
|
1. **栏目管理**(www_list_cate)- 定义内容分类和SEO策略
|
||||||
|
2. **已发文章**(www_list_art)- 已发布并在前台显示的文章
|
||||||
|
3. **待发文章**(www_list_preart)- AI生成的文章池
|
||||||
|
4. **单页管理**(www_single)- 独立页面(关于我们、联系我们等)
|
||||||
|
5. **SEO规划**(www_seoplan)- 制定SEO优化计划
|
||||||
|
6. **关键词库**(www_keyword)- 存储SEO关键词
|
||||||
|
7. **锚内关键词**(www_seoword)- 自动插入的关键词链接
|
||||||
|
8. **文章模版**(www_tmplart)- SEO专用文章模板
|
||||||
|
9. **浓缩知识**(www_content)- 与产品相关的浓缩信息
|
||||||
|
10. **用户线索**(www_customer)- 收集访客咨询
|
||||||
|
|
||||||
|
|
||||||
|
## 核心架构
|
||||||
|
|
||||||
|
### 网站内容管理四大模块
|
||||||
|
|
||||||
|
#### 1. 栏目管理(www_list_cate)
|
||||||
|
**功能**:定义网站的内容分类,每个栏目可配置独立的SEO策略
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_list_cate` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '栏目ID',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '栏目名',
|
||||||
|
`precnt` int(11) NOT NULL COMMENT '储备文章数(待发文章池)',
|
||||||
|
`daysent` int(11) NOT NULL COMMENT '日发布量(每天自动发布多少篇)',
|
||||||
|
`bprenow` int(11) NOT NULL COMMENT '直发否(是否直接发布,无需审核)',
|
||||||
|
`promptcute` text NOT NULL COMMENT 'AI生成文章的提示词',
|
||||||
|
`seotitle` varchar(180) NOT NULL COMMENT 'SEO标题',
|
||||||
|
`keyw` varchar(180) NOT NULL COMMENT '关键词',
|
||||||
|
`descs` varchar(250) NOT NULL COMMENT '摘要',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '添加时间',
|
||||||
|
`uptimes` bigint(20) NOT NULL COMMENT '更新时间',
|
||||||
|
`vadmin` int(11) NOT NULL COMMENT '操作人',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用场景**:
|
||||||
|
- 普通栏目:公司动态、产品列表、技术文档FAQ等
|
||||||
|
- SEO栏目:专门用于SEO优化的栏目,配置AI自动生成文章
|
||||||
|
|
||||||
|
**配置示例**:
|
||||||
|
```php
|
||||||
|
// 普通栏目
|
||||||
|
{
|
||||||
|
'name' => '公司动态',
|
||||||
|
'precnt' => 5,
|
||||||
|
'daysent' => 1,
|
||||||
|
'bprenow' => 1,
|
||||||
|
'promptcute' => '生成一篇关于公司产品更新的新闻稿',
|
||||||
|
'seotitle' => '公司动态 - xx科技有限公司',
|
||||||
|
'keyw' => '公司动态,产品更新,新闻资讯',
|
||||||
|
'descs' => '了解公司最新动态和产品更新信息'
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEO栏目
|
||||||
|
{
|
||||||
|
'name' => '技术文章',
|
||||||
|
'precnt' => 30,
|
||||||
|
'daysent' => 3,
|
||||||
|
'bprenow' => 0,
|
||||||
|
'promptcute' => '生成一篇关于{关键词}的技术文章,要求:1.内容原创 2.结构清晰 3.包含实战案例',
|
||||||
|
'seotitle' => '技术文章 - 全栈开发框架',
|
||||||
|
'keyw' => 'PHP开发,Golang开发,全栈框架',
|
||||||
|
'descs' => '分享PHP、Golang、全栈开发技术文章和实战经验'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 已发文章(www_list_art)
|
||||||
|
**功能**:已发布并在网站前台显示的文章
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_list_art` (
|
||||||
|
`id` int(11) NOT NULL COMMENT '文章ID',
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`clickcnt` int(11) NOT NULL COMMENT '点击量',
|
||||||
|
`icon` varchar(250) NOT NULL COMMENT '缩略图',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '主标题',
|
||||||
|
`seotitle` varchar(180) NOT NULL COMMENT 'SEO标题',
|
||||||
|
`keyw` varchar(180) NOT NULL COMMENT '关键词',
|
||||||
|
`author` varchar(100) NOT NULL COMMENT '作者',
|
||||||
|
`descs` varchar(250) NOT NULL COMMENT '摘要',
|
||||||
|
`content` text NOT NULL COMMENT '内容(Markdown格式)',
|
||||||
|
`csort` int(11) NOT NULL COMMENT '排序',
|
||||||
|
`uptimes` bigint(20) NOT NULL COMMENT '更新时间',
|
||||||
|
`vadmin` int(11) NOT NULL COMMENT '操作人',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
**自动发布流程**:
|
||||||
|
1. AI生成文章存入 `www_list_preart`(待发文章表)
|
||||||
|
2. 定时任务根据栏目配置的 `daysent`(日发布量)
|
||||||
|
3. 将待发文章移动到 `www_list_art`(已发文章表)
|
||||||
|
4. 更新网站的sitemap.xml
|
||||||
|
5. 通知搜索引擎索引
|
||||||
|
|
||||||
|
#### 3. 待发文章(www_list_preart)
|
||||||
|
**功能**:AI生成的文章池,等待审核或定时发布
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_list_preart` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文章ID',
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`preartstatus` int(11) NOT NULL COMMENT '文章状态:10.草稿 20.待发 100.已发',
|
||||||
|
`icon` varchar(250) NOT NULL COMMENT '缩略图',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '主标题',
|
||||||
|
`seotitle` varchar(180) NOT NULL COMMENT 'SEO标题',
|
||||||
|
`keyw` varchar(180) NOT NULL COMMENT '关键词',
|
||||||
|
`author` varchar(100) NOT NULL COMMENT '作者',
|
||||||
|
`descs` varchar(250) NOT NULL COMMENT '摘要',
|
||||||
|
`content` text NOT NULL COMMENT '内容(Markdown格式)',
|
||||||
|
`uptimes` bigint(20) NOT NULL COMMENT '更新时间',
|
||||||
|
`vadmin` int(11) NOT NULL COMMENT '创建人',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
**文章状态流转**:
|
||||||
|
```
|
||||||
|
10.草稿(AI生成)→ 20.待发(人工审核)→ 100.已发(发布到前台)
|
||||||
|
```
|
||||||
|
|
||||||
|
**AI生成文章流程**:
|
||||||
|
```php
|
||||||
|
// 1. 读取栏目配置
|
||||||
|
$cate = $db->getone("SELECT * FROM www_list_cate WHERE id = {$cateid}");
|
||||||
|
|
||||||
|
// 2. 读取关键词库
|
||||||
|
$keywords = $db->get("SELECT * FROM www_keyword WHERE cateid = {$cateid}");
|
||||||
|
|
||||||
|
// 3. 随机选择关键词
|
||||||
|
$keyword = $keywords[array_rand($keywords)];
|
||||||
|
|
||||||
|
// 4. 替换提示词中的关键词
|
||||||
|
$prompt = str_replace('{关键词}', $keyword['name'], $cate['promptcute']);
|
||||||
|
|
||||||
|
// 5. 调用AI生成文章
|
||||||
|
$article = ai_generate_article($prompt);
|
||||||
|
|
||||||
|
// 6. 保存到待发文章表
|
||||||
|
$db->insert('www_list_preart', [
|
||||||
|
'cateid' => $cateid,
|
||||||
|
'preartstatus' => 10,
|
||||||
|
'name' => $article['title'],
|
||||||
|
'seotitle' => $article['title'],
|
||||||
|
'keyw' => $keyword['name'],
|
||||||
|
'content' => $article['content'],
|
||||||
|
'descs' => mb_substr(strip_tags($article['content']), 0, 250),
|
||||||
|
'uptimes' => time(),
|
||||||
|
'vadmin' => 0 // 0表示AI生成
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 单页管理(www_single)
|
||||||
|
**功能**:独立页面,如关于我们、联系我们、隐私政策等
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_single` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '页面ID',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '主标题',
|
||||||
|
`seotitle` varchar(180) NOT NULL COMMENT 'SEO标题',
|
||||||
|
`keyw` varchar(180) NOT NULL COMMENT '关键词',
|
||||||
|
`author` varchar(100) NOT NULL COMMENT '作者',
|
||||||
|
`descs` varchar(250) NOT NULL COMMENT '摘要',
|
||||||
|
`content` text NOT NULL COMMENT '内容(Markdown格式)',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '添加时间',
|
||||||
|
`uptimes` bigint(20) NOT NULL COMMENT '更新时间',
|
||||||
|
`vadmin` int(11) NOT NULL COMMENT '创建人',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 辅助SEO优化模块
|
||||||
|
|
||||||
|
#### 5. SEO规划(www_seoplan)
|
||||||
|
**功能**:制定SEO优化计划,管理不同阶段的推广策略
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_seoplan` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`starttimes` bigint(20) NOT NULL COMMENT '开始日期',
|
||||||
|
`endtimes` bigint(20) NOT NULL COMMENT '结束日期',
|
||||||
|
`promptseo` text NOT NULL COMMENT '推广方向提示词',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用场景**:
|
||||||
|
- 制定月度SEO计划
|
||||||
|
- 定义阶段性推广主题
|
||||||
|
- 指导AI生成文章方向
|
||||||
|
|
||||||
|
#### 6. 关键词库(www_keyword)
|
||||||
|
**功能**:存储SEO关键词,供AI生成文章时使用
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_keyword` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '关键词',
|
||||||
|
`usetime` int(11) NOT NULL COMMENT '使用次数',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '添加时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键词管理策略**:
|
||||||
|
- 从百度指数、Google Trends等工具获取热门关键词
|
||||||
|
- 使用长尾关键词提高转化率
|
||||||
|
- 定期更新关键词库
|
||||||
|
|
||||||
|
#### 7. 锚内关键词(www_seoword)
|
||||||
|
**功能**:在文章中自动插入的关键词链接,提升内链权重
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_seoword` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '关键词',
|
||||||
|
`url` varchar(180) NOT NULL COMMENT '链接地址',
|
||||||
|
`rank` int(11) NOT NULL COMMENT '权重(0-100)',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `title` (`name`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 8. 文章模版(www_tmplart)
|
||||||
|
**功能**:SEO自动生成的栏目专用。
|
||||||
|
文章模板主要是在顶部设置全图落地页。
|
||||||
|
SEO自动生成的文章,用户阅读质量较差,顶部放置全图片落地页吸引用户浏览。(一般用户从搜索引擎直达本页)
|
||||||
|
底部AI自动生成的文字,主要给搜索引擎收录用。
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_tmplart` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '模版主题',
|
||||||
|
`content` text NOT NULL COMMENT '模版内容(Markdown格式)',
|
||||||
|
`qutime` int(11) NOT NULL COMMENT '引用次数',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '添加时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
**模版示例**:
|
||||||
|
```markdown
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
!图片链接
|
||||||
|
{{text}}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9. 浓缩知识(www_content)
|
||||||
|
**功能**:主要是与网站相关产品、服务有关的信息,浓缩成不同方向描述。
|
||||||
|
AI随机抽取几个浓缩知识,结合SEO规划的推广方向提示词,生成可发布的文字,再套用文章模版,替换{{text}},完成生成。
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_content` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`cateid` int(11) NOT NULL COMMENT '所属栏目ID',
|
||||||
|
`name` varchar(180) NOT NULL COMMENT '内容主题',
|
||||||
|
`content` text NOT NULL COMMENT '浓缩内容',
|
||||||
|
`qutime` int(11) NOT NULL COMMENT '引用次数',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '添加时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 10. 用户线索(www_customer)
|
||||||
|
**功能**:收集网站访客的咨询和需求信息
|
||||||
|
|
||||||
|
**核心字段**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `www_customer` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`fromurl` varchar(180) NOT NULL COMMENT '来源页面',
|
||||||
|
`mobile` varchar(50) NOT NULL COMMENT '手机号',
|
||||||
|
`demandinfo` text NOT NULL COMMENT '需求信息',
|
||||||
|
`addtimes` bigint(20) NOT NULL COMMENT '提交时间',
|
||||||
|
`contacttimes` bigint(20) NOT NULL COMMENT '接待时间',
|
||||||
|
`memo` varchar(180) NOT NULL COMMENT '接待备注',
|
||||||
|
`contactadmin` int(11) NOT NULL COMMENT '接待人',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
```
|
||||||
|
|
||||||
|
## AI自动生成文章系统
|
||||||
|
|
||||||
|
### 定时任务配置
|
||||||
|
|
||||||
|
**创建自动化任务**:
|
||||||
|
```php
|
||||||
|
// 插入任务到 zc_autotask 表
|
||||||
|
$db->insert('zc_autotask', [
|
||||||
|
'name' => 'SEO文章生成',
|
||||||
|
'runfunc' => 'web\admin\autotask\seo::generate_articles',
|
||||||
|
'runparam' => '',
|
||||||
|
'nexttimes' => time() + 3600, // 1小时后执行
|
||||||
|
'runcycle' => 3600, // 每小时执行一次
|
||||||
|
'autotaskstatus' => 20, // 等待执行
|
||||||
|
'runtimes' => 0
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
**任务执行函数**:
|
||||||
|
```php
|
||||||
|
namespace web\admin\autotask;
|
||||||
|
|
||||||
|
class seo {
|
||||||
|
// 生成SEO文章
|
||||||
|
static function generate_articles() {
|
||||||
|
// 1. 读取所有需要自动生成的栏目,一般文章储备不足开始生成
|
||||||
|
$cates = $db->get("SELECT * FROM www_list_cate WHERE precnt < 5");
|
||||||
|
|
||||||
|
foreach ($cates as $cate) {
|
||||||
|
// 2. 读取SEO规划
|
||||||
|
$promptseo = $db->get1("SELECT promptseo FROM www_seoplan WHERE cateid = {$cate['id']} and starttimes>{$now} and endtimes<{$now}");
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
// 生成文章
|
||||||
|
self::generate_one_article($cate, $promptseo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['code' => 0, 'errmsg' => '文章生成完成'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成单篇文章
|
||||||
|
static function generate_one_article($cate, $promptseo) {
|
||||||
|
// 1. 如果有,则按$promptseo提示词,用AI从www_keyword中提取几个相关关键词。
|
||||||
|
// 2. 如果$promptseo为空,则随机提取几个关键词。
|
||||||
|
// 3. 用$promptseo + $cate['prompt'] + 关键词作为提示词,调用call_ai接口生成文章内容。
|
||||||
|
// 4. 随机取出一个文章模板,将模板内容与文章内容结合,保存到待发文章表。
|
||||||
|
// 5. 更新栏目的待发文章数量。
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用AI接口
|
||||||
|
static function call_ai($ai_key, $prompt) {
|
||||||
|
// 使用框架的AI接口
|
||||||
|
$result = \ciy\openai::chat([
|
||||||
|
'model' => $ai_key['model'],
|
||||||
|
'messages' => [
|
||||||
|
['role' => 'system', 'content' => '你是一个专业的SEO文章写作助手'],
|
||||||
|
['role' => 'user', 'content' => $prompt]
|
||||||
|
],
|
||||||
|
'api_key' => $ai_key['aikey'],
|
||||||
|
'base_url' => $ai_key['baseurl']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GEO生成式引擎优化(Generative Engine Optimization)
|
||||||
|
|
||||||
|
### 概念说明
|
||||||
|
|
||||||
|
**GEO vs SEO**:
|
||||||
|
- **SEO(Search Engine Optimization)**:针对传统搜索引擎(Google、百度)优化,目标是提高在搜索结果中的排名
|
||||||
|
- **GEO(Generative Engine Optimization)**:针对AI搜索引擎(ChatGPT、Claude、Bing AI)优化,目标是让AI训练爬虫收录内容,在用户提问时引用和推荐
|
||||||
|
|
||||||
|
**AI爬虫的喜好特点**:
|
||||||
|
1. **结构化内容**:清晰的标题、段落、列表结构
|
||||||
|
2. **权威性**:引用数据、案例、专家观点
|
||||||
|
3. **完整性**:全面覆盖主题,提供深入分析
|
||||||
|
4. **原创性**:独特见解和原创内容
|
||||||
|
5. **时效性**:更新及时,信息准确
|
||||||
|
6. **可验证性**:提供来源链接
|
||||||
|
7. **实用性**:解决实际问题,提供可操作建议
|
||||||
|
|
||||||
|
|
||||||
|
### 1. AI收录优化策略
|
||||||
|
|
||||||
|
#### A. 内容结构优化
|
||||||
|
|
||||||
|
**AI友好的文章结构**:
|
||||||
|
```markdown
|
||||||
|
# 主标题(明确、具体、包含核心关键词)
|
||||||
|
|
||||||
|
## 摘要
|
||||||
|
提供文章概要,帮助AI快速理解内容要点
|
||||||
|
|
||||||
|
## 背景介绍
|
||||||
|
说明问题的背景和重要性,建立上下文
|
||||||
|
|
||||||
|
## 核心概念
|
||||||
|
### 概念1
|
||||||
|
- 定义
|
||||||
|
- 特点
|
||||||
|
- 应用场景
|
||||||
|
|
||||||
|
### 概念2
|
||||||
|
- 定义
|
||||||
|
- 特点
|
||||||
|
- 应用场景
|
||||||
|
|
||||||
|
## 实战案例
|
||||||
|
### 案例一:xxx公司实施xxx
|
||||||
|
- 背景
|
||||||
|
- 挑战
|
||||||
|
- 解决方案
|
||||||
|
- 结果
|
||||||
|
|
||||||
|
### 案例二:xxx项目实践
|
||||||
|
- 背景
|
||||||
|
- 挑战
|
||||||
|
- 解决方案
|
||||||
|
- 结果
|
||||||
|
|
||||||
|
## 实施步骤
|
||||||
|
1. 第一步:xxx
|
||||||
|
2. 第二步:xxx
|
||||||
|
3. 第三步:xxx
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
### Q1: xxx?
|
||||||
|
**A**: 详细解答...
|
||||||
|
|
||||||
|
### Q2: xxx?
|
||||||
|
**A**: 详细解答...
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
总结文章要点,提供核心结论
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**GEO栏目配置**:
|
||||||
|
```php
|
||||||
|
{
|
||||||
|
'name' => '技术教程',
|
||||||
|
'precnt' => 50,
|
||||||
|
'daysent' => 5,
|
||||||
|
'bprenow' => 0,
|
||||||
|
'promptcute' => '生成一篇关于{关键词}的深度技术文章,要求:1.结构清晰,包含背景、概念、案例、步骤、问答、总结 2.提供可操作的实施建议 3.引用实际数据和案例 4.内容原创且有独到见解 5.字数2000-3000字',
|
||||||
|
'seotitle' => '{关键词} - 全栈开发技术教程',
|
||||||
|
'keyw' => '{关键词},技术教程,实战案例,解决方案',
|
||||||
|
'descs' => '深入讲解{关键词}的技术原理、实施步骤和实战案例,提供可操作的建议和最佳实践'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**更多GEO优化提示词示例**:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// 1. 行业分析类文章
|
||||||
|
{
|
||||||
|
'name' => '行业洞察',
|
||||||
|
'promptcute' => '生成一篇关于{关键词}的行业分析文章,要求:1.包含市场数据、趋势分析、竞争格局 2.引用权威数据源和行业报告 3.提供未来3-5年的发展预测 4.分析对企业和从业者的启示 5.字数2500-3500字',
|
||||||
|
'seotitle' => '{关键词}行业分析与发展趋势',
|
||||||
|
'keyw' => '{关键词},行业分析,市场趋势,发展预测'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 最佳实践类文章
|
||||||
|
{
|
||||||
|
'name' => '最佳实践',
|
||||||
|
'promptcute' => '生成一篇关于{关键词}的最佳实践文章,要求:1.基于真实项目经验 2.列出常见错误和避坑指南 3.提供可复制的成功模式 4.包含检查清单和工具推荐 5.字数2000-3000字',
|
||||||
|
'seotitle' => '{关键词}最佳实践指南',
|
||||||
|
'keyw' => '{关键词},最佳实践,经验总结,避坑指南'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 问题解决类文章
|
||||||
|
{
|
||||||
|
'name' => '解决方案',
|
||||||
|
'promptcute' => '生成一篇关于{关键词}的问题解决方案文章,要求:1.明确问题描述和影响范围 2.分析根本原因 3.提供多种解决方案对比 4.给出实施步骤和预期效果 5.包含预防措施 6.字数2000-3000字',
|
||||||
|
'seotitle' => '{关键词}问题解决方案',
|
||||||
|
'keyw' => '{关键词},问题解决,方案对比,实施指南'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 工具评测类文章
|
||||||
|
{
|
||||||
|
'name' => '工具评测',
|
||||||
|
'promptcute' => '生成一篇关于{关键词}的工具评测文章,要求:1.评测5-8个主流工具 2.从功能、性能、成本、易用性等多维度对比 3.提供选择建议和适用场景 4.包含实际使用体验 5.字数2500-3500字',
|
||||||
|
'seotitle' => '{关键词}工具评测与选择指南',
|
||||||
|
'keyw' => '{关键词},工具评测,对比分析,选择建议'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 让AI引用和推荐的核心策略
|
||||||
|
|
||||||
|
#### A. 建立内容权威性
|
||||||
|
|
||||||
|
**成为领域专家的必备要素**:
|
||||||
|
1. **内容深度**:每个主题提供全面深入的分析,而非浅尝辄止
|
||||||
|
2. **原创见解**:提供独特的观点和见解,避免人云亦云
|
||||||
|
3. **数据支撑**:引用真实数据、案例、研究报告
|
||||||
|
4. **持续更新**:定期更新内容,保持信息的准确性和时效性
|
||||||
|
5. **专业审阅**:邀请行业专家审阅内容,确保专业准确性
|
||||||
|
|
||||||
|
#### B. 提升内容可引用性
|
||||||
|
|
||||||
|
**让AI更容易引用的内容特征**:
|
||||||
|
1. **结构化格式**:使用清晰的标题、列表、段落结构
|
||||||
|
2. **明确观点**:直接陈述观点,避免模糊表达
|
||||||
|
3. **可操作建议**:提供具体的实施步骤和检查清单
|
||||||
|
4. **案例验证**:用实际案例验证观点的有效性
|
||||||
|
5. **引用来源**:提供权威来源链接,增强可信度
|
||||||
|
|
||||||
|
#### C. 品牌价值植入
|
||||||
|
|
||||||
|
**在内容中自然植入品牌价值**:
|
||||||
|
1. **解决方案提及**:在讨论解决方案时提及品牌方案
|
||||||
|
2. **经验分享**:分享品牌在相关领域的实践经验
|
||||||
|
3. **数据证明**:用品牌相关的数据证明观点
|
||||||
|
4. **客户案例**:引用品牌客户的成功案例
|
||||||
|
5. **行业地位**:在行业分析中提及品牌的行业地位
|
||||||
|
|
||||||
|
#### D. 多维度覆盖
|
||||||
|
|
||||||
|
**覆盖AI可能询问的各种问题**:
|
||||||
|
1. **是什么**:概念定义、基本原理
|
||||||
|
2. **为什么**:重要性、必要性、价值
|
||||||
|
3. **怎么做**:实施步骤、最佳实践、工具推荐
|
||||||
|
4. **常见问题**:FAQ、错误处理、避坑指南
|
||||||
|
5. **未来趋势**:发展方向、预测、建议
|
||||||
|
|
||||||
|
### 6. GEO最佳实践总结
|
||||||
|
|
||||||
|
**内容创作原则**:
|
||||||
|
1. **深度优先**:每个主题提供2000+字的深度分析
|
||||||
|
2. **结构清晰**:使用标准化的文章结构
|
||||||
|
3. **数据支撑**:引用真实数据和案例
|
||||||
|
4. **专家背书**:邀请行业专家撰写或审阅
|
||||||
|
5. **持续更新**:定期更新内容,保持时效性
|
||||||
|
|
||||||
|
**品牌植入技巧**:
|
||||||
|
1. **自然植入**:在解决方案、最佳实践等部分自然提及
|
||||||
|
2. **价值导向**:强调品牌带来的价值,而非硬性推销
|
||||||
|
3. **证据支持**:提供案例、数据、客户证言等证据
|
||||||
|
4. **多样化表达**:从不同角度、场景展示品牌价值
|
||||||
|
|
||||||
|
**AI收录策略**:
|
||||||
|
1. **结构化标记**:使用Schema.org等标准格式
|
||||||
|
2. **知识图谱**:构建领域知识图谱,明确概念关系
|
||||||
|
3. **版本控制**:记录内容演进,帮助AI理解更新
|
||||||
|
4. **跨平台分发**:在多个平台发布,增加AI训练数据来源
|
||||||
|
|
||||||
|
## 前台页面开发
|
||||||
|
|
||||||
|
### 1. 首页(www/index.php)
|
||||||
|
```php
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>xxx</title>
|
||||||
|
<meta name="keywords" content="aa,bb,cc" />
|
||||||
|
<meta name="description" content="xxxxx" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="stylesheet" href="/jscss/web.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<a href="/">首页</a>
|
||||||
|
<?php
|
||||||
|
$cates = $db->get("SELECT * FROM www_list_cate ORDER BY id");
|
||||||
|
foreach ($cates as $cate) {
|
||||||
|
echo '<a href="/wlist/' . enid($cate['id']) . '">' . $cate['name'] . '</a>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="hero">
|
||||||
|
<h1>xxx</h1>
|
||||||
|
<p>xxx</p>
|
||||||
|
</section>
|
||||||
|
<section class="latest-articles">
|
||||||
|
<h2>最新文章</h2>
|
||||||
|
<?php
|
||||||
|
$articles = $db->get("SELECT * FROM www_list_art ORDER BY uptimes DESC LIMIT 10");
|
||||||
|
foreach ($articles as $art) {
|
||||||
|
echo '<article>';
|
||||||
|
echo '<h3><a href="/wlist/' . enid($art['cateid']) . '/art/' . enid($art['id']) . '">' . $art['name'] . '</a></h3>';
|
||||||
|
echo '<p>' . $art['descs'] . '</p>';
|
||||||
|
echo '</article>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© <?php echo date('Y'); ?> 众产科技. All Rights Reserved. 网站备案号</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 栏目列表页(www/listpage.php)
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
$cateid = deid(get('cate'));
|
||||||
|
$pageno = getint('pageno', 1);
|
||||||
|
$pagecount = 20;
|
||||||
|
|
||||||
|
// 读取栏目信息
|
||||||
|
$cate = $db->getone("SELECT * FROM www_list_cate WHERE id = {$cateid}");
|
||||||
|
|
||||||
|
// 读取文章列表
|
||||||
|
$csql = new \ciy\sql('www_list_art');
|
||||||
|
$csql->where('cateid', $cateid);
|
||||||
|
$csql->limit(($pageno - 1) * $pagecount, $pagecount);
|
||||||
|
$csql->order('uptimes desc');
|
||||||
|
$csql->column('id,name,descs,uptimes');
|
||||||
|
$count = -1;
|
||||||
|
$articles = $db->get($csql, $count);
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title><?php echo $cate['seotitle']; ?></title>
|
||||||
|
<meta name="keywords" content="<?php echo $cate['keyw']; ?>" />
|
||||||
|
<meta name="description" content="<?php echo $cate['descs']; ?>" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1><?php echo $cate['name']; ?></h1>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<?php foreach ($articles as $art): ?>
|
||||||
|
<article>
|
||||||
|
<h2><a href="/wlist/<?php echo enid($cateid); ?>/art/<?php echo enid($art['id']); ?>">
|
||||||
|
<?php echo $art['name']; ?>
|
||||||
|
</a></h2>
|
||||||
|
<p><?php echo $art['descs']; ?></p>
|
||||||
|
<time><?php echo date('Y-m-d', $art['uptimes']); ?></time>
|
||||||
|
</article>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<?php
|
||||||
|
\web\cwebcomon::www_showpage(
|
||||||
|
$count,
|
||||||
|
$pageno,
|
||||||
|
$pagecount,
|
||||||
|
'/wlist/' . enid($cateid),
|
||||||
|
function($pageno) {
|
||||||
|
if ($pageno < 2) return '';
|
||||||
|
return '/p/' . $pageno;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 文章详情页(www/listart.php)
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
$id = deid(get('id'));
|
||||||
|
$cateid = deid(get('cate'));
|
||||||
|
|
||||||
|
// 读取文章
|
||||||
|
$article = $db->getone("SELECT * FROM www_list_art WHERE id = {$id}");
|
||||||
|
|
||||||
|
// 更新点击数
|
||||||
|
$db->update("UPDATE www_list_art SET clickcnt = clickcnt + 1 WHERE id = {$id}");
|
||||||
|
|
||||||
|
// 读取SEO关键词
|
||||||
|
$seowords = $db->get("SELECT * FROM www_seoword WHERE cateid = {$cateid}");
|
||||||
|
|
||||||
|
// 转换内容(SEO关键词+Markdown)
|
||||||
|
$content = \web\cwebcomon::www_convertseoword(
|
||||||
|
$seowords,
|
||||||
|
\ciy\web::markdown_convert($article['content']),
|
||||||
|
$article['keyw']
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title><?php echo $article['seotitle']; ?></title>
|
||||||
|
<meta name="keywords" content="<?php echo $article['keyw']; ?>" />
|
||||||
|
<meta name="description" content="<?php echo $article['descs']; ?>" />
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Article",
|
||||||
|
"headline": "<?php echo $article['name']; ?>",
|
||||||
|
"datePublished": "<?php echo date('c', $article['uptimes']); ?>",
|
||||||
|
"author": {
|
||||||
|
"@type": "Person",
|
||||||
|
"name": "<?php echo $article['author']; ?>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<article>
|
||||||
|
<h1><?php echo $article['name']; ?></h1>
|
||||||
|
<div class="meta">
|
||||||
|
<time><?php echo date('Y-m-d', $article['uptimes']); ?></time>
|
||||||
|
<span>阅读:<?php echo $article['clickcnt']; ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<?php echo $content; ?>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- 相关文章 -->
|
||||||
|
<section class="related">
|
||||||
|
<h3>相关文章</h3>
|
||||||
|
<?php
|
||||||
|
$related = $db->get("SELECT * FROM www_list_art WHERE cateid = {$cateid} AND id != {$id} ORDER BY RAND() LIMIT 5");
|
||||||
|
foreach ($related as $art) {
|
||||||
|
echo '<a href="/wlist/' . enid($cateid) . '/art/' . enid($art['id']) . '">' . $art['name'] . '</a>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发规范
|
||||||
|
|
||||||
|
### 1. 数据库操作规范
|
||||||
|
- 使用 `\ciy\sql` 类进行数据库操作
|
||||||
|
- 所有输入必须过滤:`get()`, `post()`, `deid()`, `enid()`
|
||||||
|
- 避免SQL注入,使用参数化查询
|
||||||
|
|
||||||
|
### 2. 安全规范
|
||||||
|
- XSS防护:输出时使用 `htmlspecialchars()`
|
||||||
|
- CSRF防护:表单添加token验证
|
||||||
|
- 文件上传:验证文件类型和大小
|
||||||
|
|
||||||
|
### 3. 性能规范
|
||||||
|
- 合理使用索引:`cateid`, `uptimes`, `preartstatus`
|
||||||
|
- 避免N+1查询,使用JOIN优化
|
||||||
|
- 启用页面缓存和CDN
|
||||||
|
|
||||||
|
### 4. SEO规范
|
||||||
|
- 每个页面必须有title和meta标签
|
||||||
|
- URL必须静态化,使用 `webpoint.php` 路由
|
||||||
|
- 图片必须添加alt属性
|
||||||
|
|
||||||
|
## 检查清单
|
||||||
|
|
||||||
|
### SEO检查项
|
||||||
|
- [ ] 所有页面都有title和meta标签
|
||||||
|
- [ ] URL结构清晰且静态化
|
||||||
|
- [ ] 图片添加alt和title属性
|
||||||
|
- [ ] 使用语义化HTML标签
|
||||||
|
- [ ] 实现面包屑导航
|
||||||
|
- [ ] 配置robots.txt
|
||||||
|
- [ ] 实现结构化数据
|
||||||
|
- [ ] 移动端适配良好
|
||||||
|
- [ ] 页面加载速度<3秒
|
||||||
|
|
||||||
|
### GEO检查项
|
||||||
|
- [ ] 文章结构清晰(包含标题、摘要、背景、概念、案例、步骤、问答、总结)
|
||||||
|
- [ ] 内容长度充足(2000字以上)
|
||||||
|
- [ ] 提供真实案例和数据支撑
|
||||||
|
- [ ] 添加结构化数据标记(Schema.org)
|
||||||
|
- [ ] 建立知识图谱,明确概念关系
|
||||||
|
- [ ] 自然植入品牌信息(解决方案、最佳实践)
|
||||||
|
- [ ] 引用专家观点和行业报告
|
||||||
|
- [ ] 提供可操作的实施建议
|
||||||
|
|
||||||
|
### AI自动化检查项
|
||||||
|
- [ ] 配置定时任务
|
||||||
|
- [ ] 栏目配置AI提示词
|
||||||
|
- [ ] 关键词库维护
|
||||||
|
- [ ] 待发文章池充足
|
||||||
|
- [ ] 自动发布流程正常
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
1. **内容为王**:AI生成内容+人工审核,确保内容质量和原创性
|
||||||
|
2. **定期更新**:配置日发布量,保持网站活跃度
|
||||||
|
3. **关键词优化**:使用长尾关键词,提高转化率
|
||||||
|
4. **内链建设**:自动插入关键词链接,提升权重
|
||||||
|
5. **数据分析**:监控文章点击量,优化热门内容
|
||||||
|
6. **GEO优化**:针对AI搜索引擎优化,建立品牌权威,让AI在用户提问时引用和推荐
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
Ciyon框架的网站开发核心是:
|
||||||
|
- **AI驱动**:自动生成文章,减少人工工作量
|
||||||
|
- **SEO优先**:所有开发决策都以SEO为出发点
|
||||||
|
- **GEO优化**:生成式引擎优化,让AI训练爬虫收录内容,在用户提问时引用和推荐网站内容
|
||||||
|
- **自动化**:定时任务自动发布,保持网站活跃度
|
||||||
|
- **可扩展**:模块化设计,易于扩展功能
|
||||||
|
|
||||||
|
通过以上规范和最佳实践,可以快速搭建一个SEO友好、性能优秀、自动更新的网站。
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
# Ciyon框架 - AI开发指导入口
|
||||||
|
|
||||||
|
> 本文档为AI助手开发Ciyon框架应用的详细设计指导入口,整合了PC后台、移动端、数据大屏、Web3D、网站SEO/GEO等全栈开发技术。
|
||||||
|
> 禁止修改任何 ciyon-*.md 文档。
|
||||||
|
|
||||||
|
## 产品详细设计文档规划
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
通过开发者的简单描述,AI规划详细的产品设计文档,包括:
|
||||||
|
- 功能模块划分
|
||||||
|
- 数据表及字段设计
|
||||||
|
- 字典及字典项编码设计
|
||||||
|
- PC端菜单设计(如有)
|
||||||
|
- 移动端界面结构设计(如有)
|
||||||
|
- API接口函数设计
|
||||||
|
|
||||||
|
### 输出文档名称
|
||||||
|
/产品设计文档.md
|
||||||
|
|
||||||
|
输出的标题和内容,不要用大小写数字编号。
|
||||||
|
|
||||||
|
|
||||||
|
### Ciyon框架已具备功能
|
||||||
|
#### PC端
|
||||||
|
/web/admin/login.* 登录页面
|
||||||
|
/web/admin/index.* 主体页面
|
||||||
|
/web/admin/welcome.* 首页面
|
||||||
|
/web/api/* 三方应用接入
|
||||||
|
/web/admin/ap/* 平台用户管理、财务票据、积分、充值、提现、个税、认证、意见建议、收货地址、工单等通用功能
|
||||||
|
/web/admin/autotask/* 定时任务函数业务逻辑。可按分钟、小时、天、月、年执行
|
||||||
|
/web/admin/datasse/* 数据计算。可视化长时间运行,一般用于一次性执行的意外修复函数。和偶然执行的函数。
|
||||||
|
/web/admin/rigger/* 总控后台相关功能,管理员管理、角色管理、组织管理、业务日志、程序日志、配置管理、字典管理、自动化任务、菜单管理等通用功能
|
||||||
|
/web/admin/www/* 网站相关功能,单页管理、栏目页管理、栏目文章生成、栏目文章发布、关键词库、内链管理等SEO通用功能
|
||||||
|
/web/admin/cemap/* Web3D数字孪生地编器及开发示例代码
|
||||||
|
/web/admin/upload 本地上传API函数,云存储前端授权函数,云存储本地中转函数
|
||||||
|
/web/admin/demo/* 各类开发参考的示例代码
|
||||||
|
/web/admin/common.js 定义支持多种语言列表、指定默认云存储、上传API、登录页跳转、本地token存储key、密钥盐值、云存储资源、图片缩略图url拼接
|
||||||
|
/web/admin/lang/*.json 多语言翻译对照表。默认以中文为key,省去中文对照json。
|
||||||
|
|
||||||
|
|
||||||
|
#### 移动端
|
||||||
|
/web/ampap/* 移动端API接口函数
|
||||||
|
/components/ciy-auth/ 登陆注册组件。微信小程序静默授权,无需注册。
|
||||||
|
/pages/me/* 用户积分、充值、提现、个税、财务票据、认证、意见建议、收货地址、工单等常用功能管理
|
||||||
|
/pages/main/* 首页、我的示例页面
|
||||||
|
/pages/pub/* 公共页面,拍照透传、单页显示、栏目文章、h5页面套壳等
|
||||||
|
/util/langload.js 多语言定义
|
||||||
|
/util/lang/*.json 多语言翻译对照表
|
||||||
|
/pages/demo/* 移动端示例代码、组件示例文档等
|
||||||
|
|
||||||
|
|
||||||
|
### 输出内容(AI生成)
|
||||||
|
**产品概述**
|
||||||
|
- 产品定位
|
||||||
|
- 核心价值
|
||||||
|
- 目标用户画像
|
||||||
|
|
||||||
|
**功能模块**
|
||||||
|
- 功能列表
|
||||||
|
- 按开发优先级排序
|
||||||
|
|
||||||
|
**数据表设计**
|
||||||
|
- 数据表中文名、英文表名
|
||||||
|
- 表字段设计
|
||||||
|
|
||||||
|
**字典设计**
|
||||||
|
- 字典名称及英文代码
|
||||||
|
- 字典的数据项名称及数字编码
|
||||||
|
- 数据项的clas样式,支持dag/warn/succ/def/man
|
||||||
|
|
||||||
|
**PC端设计**
|
||||||
|
- PC菜单设计
|
||||||
|
- 登录页设计
|
||||||
|
- 首页设计
|
||||||
|
- PC端前后端文件/目录规划
|
||||||
|
|
||||||
|
**移动端界面设计**
|
||||||
|
- 页面结构
|
||||||
|
- 交互流程
|
||||||
|
- 页面文件规划
|
||||||
|
|
||||||
|
**移动端API接口设计**
|
||||||
|
- 接口文件规划/路径
|
||||||
|
- 接口方法名及功能描述
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本**:v1.0
|
||||||
|
**更新日期**:2026-03-13
|
||||||
|
**官网**:https://ciyon.ciy.cn/
|
||||||
|
|
@ -0,0 +1,912 @@
|
||||||
|
# Ciyon 后台管理系统开发框架 - 后端开发指南
|
||||||
|
|
||||||
|
## 框架概述
|
||||||
|
|
||||||
|
Ciyon 是一个基于 Golang 开发的轻量级、高性能的后台管理系统开发框架,提供完整的用户权限管理、数据操作、文件上传、日志记录等功能。
|
||||||
|
|
||||||
|
**核心特点:**
|
||||||
|
- 轻量级:核心库代码精简,依赖少
|
||||||
|
- 高性能:原生 Golang 编写,充分利用 Go 协程优势
|
||||||
|
- 易扩展:模块化设计,组件可独立使用
|
||||||
|
- RESTful API 设计:支持多种前端框架对接
|
||||||
|
- 完整权限体系:基于角色的权限控制(RBAC)
|
||||||
|
- 多租户支持:支持 SaaS 模式部署
|
||||||
|
|
||||||
|
**技术栈:**
|
||||||
|
- 后端:Go 1.22+、MySQL
|
||||||
|
- 存储:本地存储 + S3 云存储(腾讯云、阿里云、Cloudflare R2)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
golang/
|
||||||
|
├── main.go # 程序入口
|
||||||
|
├── route_adm.go # 路由配置
|
||||||
|
├── go.mod # Go 模块配置
|
||||||
|
├── go.sum # 依赖版本锁定
|
||||||
|
├── gobuild.bat # Windows 编译脚本
|
||||||
|
├── web.ini # 配置文件
|
||||||
|
├── zciyon/ # 核心库
|
||||||
|
│ ├── web.go # Web 服务器
|
||||||
|
│ ├── mysql.go # MySQL 数据库
|
||||||
|
│ ├── sql.go # SQL 构建器
|
||||||
|
│ ├── db.go # 数据库接口
|
||||||
|
│ ├── upload.go # 文件上传
|
||||||
|
│ ├── redis.go # Redis 接口
|
||||||
|
│ ├── log.go # 日志系统
|
||||||
|
│ ├── excel.go # Excel 导出
|
||||||
|
│ ├── ws.go # WebSocket
|
||||||
|
│ ├── sse.go # Server-Sent Events
|
||||||
|
│ ├── i18n.go # 国际化
|
||||||
|
│ ├── c.go # 通用工具函数
|
||||||
|
│ ├── http.go # HTTP 客户端
|
||||||
|
│ ├── json.go # JSON 处理
|
||||||
|
│ ├── ini.go # 配置文件解析
|
||||||
|
│ ├── memkv.go # 内存 KV 存储
|
||||||
|
│ ├── mqtt.go # MQTT 客户端
|
||||||
|
│ ├── post.go # POST 数据处理
|
||||||
|
│ ├── tcpclient.go # TCP 客户端
|
||||||
|
│ ├── tcpserver.go # TCP 服务器
|
||||||
|
│ ├── udpclient.go # UDP 客户端
|
||||||
|
│ ├── udpserver.go # UDP 服务器
|
||||||
|
│ ├── grpc.go # gRPC 服务
|
||||||
|
│ ├── sys_linux.go # Linux 系统调用
|
||||||
|
│ └── sys_win.go # Windows 系统调用
|
||||||
|
├── web/ # Web 资源(静态文件)
|
||||||
|
│ ├── admin/ # 管理后台页面
|
||||||
|
│ └── jscss/ # 前端库
|
||||||
|
└── test/ # 测试文件
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心架构
|
||||||
|
|
||||||
|
### 1. 请求处理流程
|
||||||
|
|
||||||
|
```
|
||||||
|
客户端请求
|
||||||
|
↓
|
||||||
|
Nginx (可选,反向代理)
|
||||||
|
↓
|
||||||
|
Ciyon Web Server
|
||||||
|
↓
|
||||||
|
路由解析 (/admin/xxx.action)
|
||||||
|
↓
|
||||||
|
业务处理函数 (execFunc)
|
||||||
|
↓ (失败)
|
||||||
|
Mock 数据 (execMock)
|
||||||
|
↓ (失败)
|
||||||
|
转发到 PHP 接口 (execPHP)
|
||||||
|
↓ (失败)
|
||||||
|
返回错误 JSON
|
||||||
|
```
|
||||||
|
|
||||||
|
**详细说明:**
|
||||||
|
|
||||||
|
1. **路由解析**:根据 URL 路径解析出对应的业务函数
|
||||||
|
2. **业务处理函数**:优先执行 Golang 业务函数
|
||||||
|
- 成功:返回 JSON 响应
|
||||||
|
- 失败:继续下一步
|
||||||
|
3. **Mock 数据**:如果业务函数不存在,尝试从 Mock 数据返回
|
||||||
|
- 成功:返回 Mock 数据
|
||||||
|
- 失败:继续下一步
|
||||||
|
4. **转发到 PHP 接口**:如果 Mock 也不存在,转发请求到 PHP 接口
|
||||||
|
- 成功:返回 PHP 接口的响应
|
||||||
|
- 失败(未找到函数):返回 "未找到业务函数" 错误
|
||||||
|
5. **返回错误**:所有尝试都失败,返回错误信息
|
||||||
|
|
||||||
|
### 2. 模块化设计
|
||||||
|
|
||||||
|
#### zciyon 核心库模块
|
||||||
|
|
||||||
|
| 模块 | 文件 | 功能描述 |
|
||||||
|
|------|------|----------|
|
||||||
|
| Web 服务器 | web.go | HTTP 服务器、路由、静态文件服务 |
|
||||||
|
| 数据库 | mysql.go | MySQL 连接池、增删改查操作 |
|
||||||
|
| SQL 构建器 | sql.go | 链式 SQL 构建器 |
|
||||||
|
| 数据库接口 | db.go | 数据库操作抽象接口 |
|
||||||
|
| 文件上传 | upload.go | 本地文件上传处理 |
|
||||||
|
| Redis | redis.go | Redis 客户端接口 |
|
||||||
|
| 日志 | log.go | 文件日志、TCP 日志 |
|
||||||
|
| Excel | excel.go | Excel 导出功能 |
|
||||||
|
| WebSocket | ws.go | WebSocket 服务器 |
|
||||||
|
| SSE | sse.go | Server-Sent Events |
|
||||||
|
| 国际化 | i18n.go | 多语言支持 |
|
||||||
|
| HTTP 客户端 | http.go | HTTP 请求客户端 |
|
||||||
|
| JSON 处理 | json.go | JSON 编解码 |
|
||||||
|
| 配置文件 | ini.go | INI 配置文件解析 |
|
||||||
|
| 内存 KV | memkv.go | 内存键值存储 |
|
||||||
|
| MQTT | mqtt.go | MQTT 协议支持 |
|
||||||
|
| gRPC | grpc.go | gRPC 服务支持 |
|
||||||
|
| TCP/UDP | tcp*.go, udp*.go | TCP/UDP 网络通信 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 环境准备
|
||||||
|
|
||||||
|
#### 配置文件 (web.ini)
|
||||||
|
```ini
|
||||||
|
[db]
|
||||||
|
host=127.0.0.1
|
||||||
|
port=3306
|
||||||
|
user=root
|
||||||
|
pass=your_password
|
||||||
|
name=your_database
|
||||||
|
maxopenconn=0
|
||||||
|
maxidelconn=0
|
||||||
|
maxlifesec=0
|
||||||
|
|
||||||
|
[main]
|
||||||
|
runmode=dev # dev 或 prod
|
||||||
|
tasksec=5 # 自动任务执行间隔(秒)
|
||||||
|
|
||||||
|
[log]
|
||||||
|
logfile=log/ciyon.log
|
||||||
|
logtcp=
|
||||||
|
logfilelevel=1 # 1-5,数字越小级别越高
|
||||||
|
logtcplevel=3
|
||||||
|
|
||||||
|
[web]
|
||||||
|
webmode=http
|
||||||
|
webipsk=127.0.0.1:4003
|
||||||
|
webhttp2= # HTTP2配置:端口,证书.crt,证书.key
|
||||||
|
|
||||||
|
[php]
|
||||||
|
host= # PHP代理地址(可选)
|
||||||
|
|
||||||
|
[mock]
|
||||||
|
target= # Mock数据库表名
|
||||||
|
docpass=
|
||||||
|
|
||||||
|
[s3A] # Cloudflare R2
|
||||||
|
access=
|
||||||
|
secret=
|
||||||
|
endpoint=1d486c90526e9c65512a35642f26d0c3.r2.cloudflarestorage.com
|
||||||
|
region=us-east-1
|
||||||
|
bucket=ciy5
|
||||||
|
acl=public-read
|
||||||
|
url=https://dao.ciy.cn/ud/
|
||||||
|
|
||||||
|
[s3B] # 腾讯云COS
|
||||||
|
access=
|
||||||
|
secret=
|
||||||
|
endpoint=tob-1322789299.cos.ap-nanjing.myqcloud.com
|
||||||
|
region=ap-nanjing
|
||||||
|
bucket=tob-1322789299
|
||||||
|
acl=public-read
|
||||||
|
url=https://tob-1322789299.cos.ap-nanjing.myqcloud.com/ud/
|
||||||
|
|
||||||
|
[s3C] # 阿里云OSS
|
||||||
|
access=
|
||||||
|
secret=
|
||||||
|
endpoint=expn.oss-cn-hangzhou.aliyuncs.com
|
||||||
|
region=oss-cn-hangzhou
|
||||||
|
bucket=expn
|
||||||
|
acl=public-read
|
||||||
|
url=https://expn.oss-cn-hangzhou.aliyuncs.com/ud/
|
||||||
|
|
||||||
|
[cdn]
|
||||||
|
weburl=https://ciyon.ciy.cn
|
||||||
|
files=.html;.js;.css
|
||||||
|
provider=cloud.tencent.com
|
||||||
|
secretId=
|
||||||
|
secretKey=
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 创建业务模块
|
||||||
|
|
||||||
|
#### 创建后端处理函数
|
||||||
|
|
||||||
|
**文件:web/admin/demo.go**
|
||||||
|
```go
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
c "ciyon/zciyon"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
func Demo_init(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
_, userid := Verifyfast(r, c.CiyDB, post)
|
||||||
|
if userid == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
csql := c.NewCiySQL("zc_demo")
|
||||||
|
csql.Where("status", 1).Order("id desc").Limit(1, 10)
|
||||||
|
list, total, err := c.CiyDB.Get(csql)
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrJSON(w, "查询失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回数据
|
||||||
|
return c.SuccJSON(w, r, map[string]any{
|
||||||
|
"list": list,
|
||||||
|
"total": total,
|
||||||
|
"status": c.Getcatas(c.CiyDB, "status"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新数据
|
||||||
|
func Demo_update(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
_, userid := Verifyfast(r, c.CiyDB, post)
|
||||||
|
if userid == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
id := post.Getint("id")
|
||||||
|
name := post.Get("name")
|
||||||
|
|
||||||
|
// 更新数据
|
||||||
|
csql := c.NewCiySQL("zc_demo")
|
||||||
|
csql.Where("id", id)
|
||||||
|
_, err := c.CiyDB.Update(csql, map[string]any{
|
||||||
|
"name": name,
|
||||||
|
"updatetime": c.Tostamp(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrJSON(w, "更新失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
SaveLogDB(c.CiyDB, "DEMO", nil, map[string]any{"id": id, "name": name})
|
||||||
|
|
||||||
|
return c.SuccJSON(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除数据
|
||||||
|
func Demo_del(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
_, userid := Verifyfast(r, c.CiyDB, post)
|
||||||
|
if userid == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ids := post.Get("ids")
|
||||||
|
|
||||||
|
// 删除数据
|
||||||
|
csql := c.NewCiySQL("zc_demo")
|
||||||
|
csql.Where("id in", ids)
|
||||||
|
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_TABLE)
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrJSON(w, "删除失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
SaveLog(c.CiyDB, "DEMO", "删除记录 IDs: "+ids)
|
||||||
|
|
||||||
|
return c.SuccJSON(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出数据
|
||||||
|
func Demo_exportxls(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
_, userid := Verifyfast(r, c.CiyDB, post)
|
||||||
|
if userid == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
csql := c.NewCiySQL("zc_demo")
|
||||||
|
csql.Where("status", 1)
|
||||||
|
list, _, err := c.CiyDB.Get(csql)
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrJSON(w, "查询失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成Excel
|
||||||
|
fields := []map[string]string{
|
||||||
|
{"name": "ID", "width": "50"},
|
||||||
|
{"name": "名称", "width": "100"},
|
||||||
|
{"name": "创建时间", "type": "dt", "width": "120"},
|
||||||
|
}
|
||||||
|
|
||||||
|
datas := [][]string{}
|
||||||
|
for _, row := range list {
|
||||||
|
datas = append(datas, []string{
|
||||||
|
c.Tostr(row["id"]),
|
||||||
|
c.Tostr(row["name"]),
|
||||||
|
c.Todate(c.Toint(row["createtime"]), "Y-m-d H:i"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
xml := c.General_excel_xml(fields, datas, map[string]any{
|
||||||
|
"toptitle": "数据列表",
|
||||||
|
"sheetname": "Sheet1",
|
||||||
|
})
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/vnd.ms-excel")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment; filename=demo.xls")
|
||||||
|
w.Write([]byte(xml))
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 注册路由
|
||||||
|
|
||||||
|
在 `route_adm.go` 中添加路由:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func setWebRoute_adm(web *c.CiyWebServer) {
|
||||||
|
web.RouterFunc("/admin/demo", map[string]map[string]func(http.ResponseWriter, *http.Request) bool{
|
||||||
|
"normal": {
|
||||||
|
"init": demo.Normal_init,
|
||||||
|
"update": demo.Normal_update,
|
||||||
|
"del": demo.Normal_del,
|
||||||
|
"getdata": demo.Normal_getdata,
|
||||||
|
"exportxls": demo.Normal_exportxls,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后端开发
|
||||||
|
|
||||||
|
### 1. 数据库操作
|
||||||
|
|
||||||
|
#### CiySQL 链式查询
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 基本查询
|
||||||
|
csql := c.NewCiySQL("user")
|
||||||
|
csql.Where("name like", "张").Where("age>", 18)
|
||||||
|
csql.Order("id desc").Limit(1, 10)
|
||||||
|
list, total, err := c.CiyDB.Get(csql)
|
||||||
|
|
||||||
|
// 日期区间查询
|
||||||
|
csql.Where_daterange("createtime", "2024-01-01~2024-12-31")
|
||||||
|
|
||||||
|
// 相对日期查询
|
||||||
|
csql.Where_dayrange("createtime", "-30~0") // 最近30天
|
||||||
|
csql.Where_dayrange("createtime", "0") // 今天
|
||||||
|
csql.Where_dayrange("createtime", "-1") // 昨天
|
||||||
|
|
||||||
|
// 月份区间查询
|
||||||
|
csql.Where_monthrange("createtime", "2024-1") // 本月
|
||||||
|
csql.Where_monthrange("createtime", "2024-1~2024-6") // 月份区间
|
||||||
|
|
||||||
|
// 数值区间查询
|
||||||
|
csql.Where_numrange("price", 100, 1000, 100) // 10000~100000
|
||||||
|
|
||||||
|
// 原始SQL
|
||||||
|
csql.RawSQL("select * from user where id=?", 123)
|
||||||
|
|
||||||
|
// 字段排除
|
||||||
|
csql.Column("!id,password") // 排除id和password字段
|
||||||
|
|
||||||
|
// JOIN查询
|
||||||
|
csql.Join("role", "user.roleid=role.id", "left")
|
||||||
|
|
||||||
|
// 分组查询
|
||||||
|
csql.Group("department").Having("count(*)>10")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 数据库CRUD操作
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 插入
|
||||||
|
csql := c.NewCiySQL("user")
|
||||||
|
lastid, err := c.CiyDB.Insert(csql, map[string]any{
|
||||||
|
"name": "张三",
|
||||||
|
"age": 25,
|
||||||
|
"createtime": c.Tostamp(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新
|
||||||
|
csql := c.NewCiySQL("user")
|
||||||
|
csql.Where("id", 123)
|
||||||
|
_, err := c.CiyDB.Update(csql, map[string]any{
|
||||||
|
"name": "李四",
|
||||||
|
"age": []string{"age+1"}, // SQL表达式:age+1
|
||||||
|
"updatetime": c.Tostamp(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// 删除(三种模式)
|
||||||
|
csql := c.NewCiySQL("user")
|
||||||
|
csql.Where("id", 123)
|
||||||
|
|
||||||
|
// 直接删除
|
||||||
|
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_NONE)
|
||||||
|
|
||||||
|
// 备份到_bak表
|
||||||
|
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_TABLE)
|
||||||
|
|
||||||
|
// 标记删除(设置deltimes字段)
|
||||||
|
_, err := c.CiyDB.Delete(csql, c.CIYDB_DELETE_BACKUP_FIELD)
|
||||||
|
|
||||||
|
// 事务处理
|
||||||
|
err := c.CiyDB.Tran(func() error {
|
||||||
|
// 扣款
|
||||||
|
csql1 := c.NewCiySQL("account")
|
||||||
|
csql1.Where("id", 123)
|
||||||
|
c.CiyDB.Update(csql1, map[string]any{"balance": []string{"balance-100"}})
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
csql2 := c.NewCiySQL("log")
|
||||||
|
c.CiyDB.Insert(csql2, map[string]any{"msg": "扣款100"})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 权限验证
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 完整验证(带用户信息)
|
||||||
|
func Verifyuser(r *http.Request, db *c.CiyMysql, post *c.CiyPost) (map[string]any, error)
|
||||||
|
|
||||||
|
// 快速验证(仅返回用户ID)
|
||||||
|
func Verifyfast(r *http.Request, db *c.CiyMysql, post *c.CiyPost) (map[string]any, int)
|
||||||
|
|
||||||
|
// 权限检查
|
||||||
|
func Nopower(db *c.CiyMysql, userid int, chkpower string) bool
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
func Demo_init(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
rsuser, userid := Verifyfast(r, c.CiyDB, post)
|
||||||
|
if userid == 0 {
|
||||||
|
return false // 自动返回登录错误
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查权限(p123v表示菜单ID 123的查看权限)
|
||||||
|
if Nopower(c.CiyDB, userid, "p123v") {
|
||||||
|
return c.ErrJSON(w, "您未被授权操作")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 业务逻辑
|
||||||
|
return c.SuccJSON(w, r)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 文件上传
|
||||||
|
|
||||||
|
**本地上传:**
|
||||||
|
```go
|
||||||
|
func Upload_upload(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
_, userid := Verifyfast(r, c.CiyDB, post)
|
||||||
|
if userid == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
path := post.Get("pathfile")
|
||||||
|
file := post.Getfile()
|
||||||
|
|
||||||
|
// 保存文件
|
||||||
|
json, err := c.SaveUploadFile(path, file)
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrJSON(w, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SuccJSON(w, r, json)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**S3上传(生成签名):**
|
||||||
|
```go
|
||||||
|
func Upload_s3(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
post := c.NewCiyPost(w, r)
|
||||||
|
storselect := post.Get("storselect") // A/B/C
|
||||||
|
path := post.Get("pathfile")
|
||||||
|
|
||||||
|
// 获取S3配置
|
||||||
|
accessKey := c.CiyVars.Ini.GetKey("s3"+storselect, "access", "")
|
||||||
|
secretKey := c.CiyVars.Ini.GetKey("s3"+storselect, "secret", "")
|
||||||
|
endpoint := c.CiyVars.Ini.GetKey("s3"+storselect, "endpoint", "")
|
||||||
|
region := c.CiyVars.Ini.GetKey("s3"+storselect, "region", "")
|
||||||
|
bucket := c.CiyVars.Ini.GetKey("s3"+storselect, "bucket", "")
|
||||||
|
|
||||||
|
// 生成S3签名(示例代码)
|
||||||
|
// 返回签名信息,前端直接上传到S3
|
||||||
|
|
||||||
|
return c.SuccJSON(w, r, ret)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 日志记录
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 记录操作日志
|
||||||
|
SaveLog(db *c.CiyMysql, types string, msg string)
|
||||||
|
|
||||||
|
// 记录数据变更日志
|
||||||
|
SaveLogDB(db *c.CiyMysql, types string, oldrow map[string]any, newrow map[string]any)
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
func Demo_update(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
// 获取旧数据
|
||||||
|
csql := c.NewCiySQL("zc_demo")
|
||||||
|
csql.Where("id", id)
|
||||||
|
oldrow, _ := c.CiyDB.Getone(csql)
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
SaveLog(c.CiyDB, "DEMO", "更新记录 ID: "+c.Tostr(id))
|
||||||
|
|
||||||
|
// 记录数据变更
|
||||||
|
SaveLogDB(c.CiyDB, "DEMO", oldrow, newrow)
|
||||||
|
|
||||||
|
return c.SuccJSON(w, r)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. WebSocket
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Wsdemo(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
ws, err := c.NewCiyWebsocket(w, r)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收消息
|
||||||
|
ws.OnMessageJSON(func(code int, id int, json map[string]any) {
|
||||||
|
// 处理消息
|
||||||
|
ws.SendSucc(id, map[string]any{
|
||||||
|
"msg": "收到消息",
|
||||||
|
"data": json,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
ws.OnError(func(err error) {
|
||||||
|
c.Log.Error("WS", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
// 关闭处理
|
||||||
|
ws.OnClose(func() {
|
||||||
|
c.Log.Info("WS", "连接关闭")
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. SSE (Server-Sent Events)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SSE_get(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
if !c.SSEInit(w) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
c.SSESend_data(w, "消息 "+c.Tostr(i))
|
||||||
|
c.Sleep(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. HTTP 客户端
|
||||||
|
|
||||||
|
```go
|
||||||
|
// GET 请求
|
||||||
|
resp, err := c.HttpGet("https://api.example.com/data")
|
||||||
|
|
||||||
|
// POST 请求
|
||||||
|
resp, err := c.HttpPost("https://api.example.com/api", map[string]any{
|
||||||
|
"name": "张三",
|
||||||
|
"age": 25,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 带Header的请求
|
||||||
|
headers := map[string]string{
|
||||||
|
"Authorization": "Bearer token",
|
||||||
|
}
|
||||||
|
resp, err := c.HttpGet("https://api.example.com/data", headers)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. JSON 处理
|
||||||
|
|
||||||
|
```go
|
||||||
|
// JSON 编码
|
||||||
|
jsonStr, err := c.JsonEncode(map[string]any{
|
||||||
|
"name": "张三",
|
||||||
|
"age": 25,
|
||||||
|
})
|
||||||
|
|
||||||
|
// JSON 解码
|
||||||
|
var data map[string]any
|
||||||
|
err := c.JsonDecode(jsonStr, &data)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. 配置文件读取
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 读取配置值
|
||||||
|
value := c.CiyVars.Ini.GetKey("db", "host", "")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. 内存 KV 存储
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 设置值
|
||||||
|
c.CiyVars.MemKV.Set("key", "value", 3600) // 3600秒过期
|
||||||
|
|
||||||
|
// 获取值
|
||||||
|
value, exists := c.CiyVars.MemKV.Get("key")
|
||||||
|
|
||||||
|
// 删除值
|
||||||
|
c.CiyVars.MemKV.Delete("key")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 权限体系
|
||||||
|
|
||||||
|
### 权限编码规范
|
||||||
|
|
||||||
|
**权限编码格式:**
|
||||||
|
```
|
||||||
|
p{菜单ID}{操作类型}
|
||||||
|
```
|
||||||
|
|
||||||
|
**操作类型:**
|
||||||
|
- `v` - 查看
|
||||||
|
- `e` - 编辑
|
||||||
|
- `d` - 删除
|
||||||
|
- `a` - 添加
|
||||||
|
- `s` - 审批
|
||||||
|
- `x` - 自定义
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```
|
||||||
|
p123v - 菜单ID 123 的查看权限
|
||||||
|
p123e - 菜单ID 123 的编辑权限
|
||||||
|
p123d - 菜单ID 123 的删除权限
|
||||||
|
```
|
||||||
|
|
||||||
|
### 权限验证
|
||||||
|
|
||||||
|
**后端验证:**
|
||||||
|
```go
|
||||||
|
if Nopower(c.CiyDB, userid, "p123v") {
|
||||||
|
return c.ErrJSON(w, "您未被授权操作")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 部署指南
|
||||||
|
|
||||||
|
### 编译
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows
|
||||||
|
gobuild.bat
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
GOOS=linux GOARCH=amd64 go build -o zgo main.go
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
GOOS=darwin GOARCH=amd64 go build -o zgo main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nginx 配置
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name yourdomain.com;
|
||||||
|
|
||||||
|
# 静态文件
|
||||||
|
location / {
|
||||||
|
root /path/to/web;
|
||||||
|
index index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API 代理
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:4003;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
}
|
||||||
|
|
||||||
|
# WebSocket
|
||||||
|
location /ws/ {
|
||||||
|
proxy_pass http://127.0.0.1:4003;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Systemd 服务
|
||||||
|
|
||||||
|
**创建服务文件:/etc/systemd/system/ciyon.service**
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Ciyon Web Server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/path/to/golang
|
||||||
|
ExecStart=/path/to/golang/zgo
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
**启动服务:**
|
||||||
|
```bash
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl start ciyon
|
||||||
|
systemctl enable ciyon
|
||||||
|
systemctl status ciyon
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 1. 数据库连接失败
|
||||||
|
|
||||||
|
**问题:** 数据库连接失败
|
||||||
|
**解决:**
|
||||||
|
1. 检查 `web.ini` 中数据库配置是否正确
|
||||||
|
2. 检查 MySQL 服务是否启动
|
||||||
|
3. 检查数据库用户权限
|
||||||
|
|
||||||
|
### 2. 权限验证失败
|
||||||
|
|
||||||
|
**问题:** 提示"请重新登录"
|
||||||
|
**解决:**
|
||||||
|
1. 检查 `zc_online` 表中会话是否存在
|
||||||
|
2. 检查会话是否过期
|
||||||
|
3. 检查 `Gtokenswapsec` 配置
|
||||||
|
4. 检查 Token 加密密钥是否一致
|
||||||
|
|
||||||
|
### 3. 文件上传失败
|
||||||
|
|
||||||
|
**问题:** 文件上传失败
|
||||||
|
**解决:**
|
||||||
|
1. 检查 `web/ud/` 目录是否存在
|
||||||
|
2. 检查目录写入权限
|
||||||
|
3. 检查文件大小限制
|
||||||
|
4. 检查文件类型是否在允许列表中
|
||||||
|
|
||||||
|
### 4. 日志不输出
|
||||||
|
|
||||||
|
**问题:** 日志不输出到文件
|
||||||
|
**解决:**
|
||||||
|
1. 检查 `log/ciyon.log` 文件是否存在
|
||||||
|
2. 检查文件写入权限
|
||||||
|
3. 检查 `logfilelevel` 配置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 代码规范
|
||||||
|
|
||||||
|
**命名规范:**
|
||||||
|
- 包名:小写单词,如 `admin`
|
||||||
|
- 文件名:小写单词+下划线,如 `demo.go`
|
||||||
|
- 函数名:大写开头(导出)或小写开头(私有)
|
||||||
|
- 变量名:尽量小写,如 `userid`
|
||||||
|
- 常量名:大写+下划线,如 `MAX_COUNT`
|
||||||
|
|
||||||
|
**注释规范:**
|
||||||
|
```go
|
||||||
|
// 函数功能说明
|
||||||
|
// 参数说明
|
||||||
|
// 返回值说明
|
||||||
|
func Demo_init(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误处理
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 统一错误返回
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrJSON(w, "操作失败", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录错误日志
|
||||||
|
if err != nil {
|
||||||
|
c.Log.Error("DEMO", "操作失败: "+err.Error())
|
||||||
|
return c.ErrJSON(w, "操作失败", err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 安全建议
|
||||||
|
|
||||||
|
1. **SQL 注入防护:** 使用参数化查询
|
||||||
|
2. **XSS 防护:** 对输出进行转义
|
||||||
|
3. **CSRF 防护:** 使用 Token 验证
|
||||||
|
4. **密码加密:** 使用 SHA256 加密
|
||||||
|
5. **权限控制:** 严格的权限验证
|
||||||
|
6. **日志记录:** 记录所有操作日志
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附录
|
||||||
|
|
||||||
|
### A. 配置参数说明
|
||||||
|
|
||||||
|
| 参数 | 说明 | 默认值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| runmode | 运行模式 | dev |
|
||||||
|
| logfile | 日志文件路径 | log/ciyon.log |
|
||||||
|
| logfilelevel | 日志级别 | 3 |
|
||||||
|
| webmode | Web 模式 | http |
|
||||||
|
| webipsk | 监听地址 | 127.0.0.1:4003 |
|
||||||
|
| dbhost | 数据库地址 | 127.0.0.1 |
|
||||||
|
| dbport | 数据库端口 | 3306 |
|
||||||
|
| dbuser | 数据库用户 | root |
|
||||||
|
| dbpass | 数据库密码 | - |
|
||||||
|
| dbname | 数据库名称 | - |
|
||||||
|
|
||||||
|
### B. 工具函数速查
|
||||||
|
|
||||||
|
| 函数 | 说明 | 示例 |
|
||||||
|
|------|------|------|
|
||||||
|
| Tostamp() | 获取当前时间戳 | c.Tostamp() |
|
||||||
|
| Todate() | 时间格式化 | c.Todate(c.Tostamp(), "Y-m-d H:i:s") |
|
||||||
|
| Tostr() | 转字符串 | c.Tostr(123) |
|
||||||
|
| Toint() | 转整数 | c.Toint("123") |
|
||||||
|
| Tofloat() | 转浮点数 | c.Tofloat("123.45") |
|
||||||
|
| MD5() | MD5 加密 | c.MD5("password") |
|
||||||
|
| Sha256() | SHA256 加密 | c.Sha256("password") |
|
||||||
|
| Encrypt() | 字符串加密 | c.Encrypt("text", "E", "key") |
|
||||||
|
| Uniqid() | 生成唯一ID | c.Uniqid(10) |
|
||||||
|
| Randstr() | 生成随机字符串 | c.Randstr(10) |
|
||||||
|
|
||||||
|
### C. 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| 1 | 成功 |
|
||||||
|
| 2 | 未登录 |
|
||||||
|
| 3 | 权限不足 |
|
||||||
|
| 4 | 参数错误 |
|
||||||
|
| 9 | 操作失败 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
Ciyon 框架是一个轻量级、高性能的后台管理系统开发框架,提供了完整的用户权限管理、数据操作、文件上传、日志记录等功能。开发者可以根据本文档快速上手开发,并根据实际需求进行扩展。
|
||||||
|
|
||||||
|
**开发建议:**
|
||||||
|
1. 先熟悉核心库的使用方法
|
||||||
|
2. 参考示例代码进行开发
|
||||||
|
3. 遵循代码规范和最佳实践
|
||||||
|
4. 注重安全性和性能优化
|
||||||
|
5. 做好日志记录和错误处理
|
||||||
|
|
||||||
|
**技术支持:**
|
||||||
|
- 官网:https://ciy.cn/code
|
||||||
|
- 文档:本文档
|
||||||
|
- 示例:web/admin/ 目录下的示例代码
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本:** v2.0
|
||||||
|
**更新日期:** 2026-03-18
|
||||||
|
**作者:** AI Assistant
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
// launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||||
|
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||||
|
"version" : "0.0",
|
||||||
|
"configurations" : [
|
||||||
|
{
|
||||||
|
"app-plus" : {
|
||||||
|
"launchtype" : "local"
|
||||||
|
},
|
||||||
|
"default" : {
|
||||||
|
"launchtype" : "local"
|
||||||
|
},
|
||||||
|
"mp-weixin" : {
|
||||||
|
"launchtype" : "local"
|
||||||
|
},
|
||||||
|
"type" : "uniCloud"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"openVueDevtools" : true,
|
||||||
|
"type" : "uni-app:app-ios"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"customPlaygroundType" : "device",
|
||||||
|
"openVueDevtools" : true,
|
||||||
|
"playground" : "standard",
|
||||||
|
"type" : "uni-app:app-android"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"openVueDevtools" : false,
|
||||||
|
"type" : "uni-app:h5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
globalData: {},
|
||||||
|
onLaunch: function(lopn) {
|
||||||
|
var app = this;
|
||||||
|
app.globalData.launchopn = lopn;
|
||||||
|
console.log('launchopn', lopn);
|
||||||
|
app.launch();
|
||||||
|
|
||||||
|
app.globalData.srv = 't'; //默认的独立微服务集群标识。
|
||||||
|
app.globalData.jsnurl = {};
|
||||||
|
app.globalData.jsnurl.t = 'https://ciyon.ciy.cn/ambap/';
|
||||||
|
app.globalData.tokenfield = "ciyap"; //header授权名称。H5同域名多个移动端项目需区分。
|
||||||
|
app.globalData.tokensalt = "ast34h$3"; //用户密码加密盐值。
|
||||||
|
app.globalData.mainpage = '/pages/main/index'; //入口页面。一般为tabbar第一个页面。
|
||||||
|
|
||||||
|
app.globalData.share_backmainpage = false; //分享如需从首页跳转,则true。用户返回后不退出小程序而是进入首页。
|
||||||
|
app.globalData.dupsec = 60; //防重复点击的间隔秒数。
|
||||||
|
app.globalData.stordefault = '/'; //默认全局存储路径。 / 为本地存储(用于单web服务器项目),A-Z 可定义成多种云存储(阿里云OSS/腾讯云COS/Cloudflare R2等)
|
||||||
|
app.globalData.storlist = { //上传文件需补全的显示链接
|
||||||
|
'/': 'https://ciyon.ciy.cn/ud/',
|
||||||
|
'A': 'https://cf5.nyyzsoft.cn/ud/',
|
||||||
|
'B': 'https://tob-1322789299.cos.ap-nanjing.myqcloud.com/ud/',
|
||||||
|
'C': 'https://expn.oss-cn-hangzhou.aliyuncs.com/ud/',
|
||||||
|
};
|
||||||
|
app.globalData.storthumb = { //图片文件缩略图配置。默认100px高度,宽度自适应。
|
||||||
|
'/': '?100',
|
||||||
|
'A': 'https://cf5.nyyzsoft.cn/cdn-cgi/image/height=100/ud/#img#', //开启媒体Images转换
|
||||||
|
'B': '?imageMogr2/thumbnail/x100',
|
||||||
|
'C': '?x-oss-process=image/resize,h_100',
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
//#ifdef H5
|
||||||
|
app.globalData.jsnurl.t = 'https://ciyon.local.ciy.cn/ambap/';
|
||||||
|
app.globalData.storlist['/'] = 'https://ciyon.local.ciy.cn/ud/';
|
||||||
|
|
||||||
|
//golang
|
||||||
|
// app.globalData.jsnurl.t = 'https://ciyongo.local.ciy.cn/';
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
var bggray1 = '#dfdfdf'; //底部导航按钮未选颜色1
|
||||||
|
var bggray2 = '#bbbbbb'; //底部导航按钮未选颜色2
|
||||||
|
var bgsel1 = '#ffdc72'; //底部导航按钮选中颜色1
|
||||||
|
var bgsel2 = '#e65411'; //底部导航按钮选中颜色2
|
||||||
|
app.globalData.tabbarArr = []; //最底部导航按钮。双色svg
|
||||||
|
var svg = '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M10,515c0,277,225,503,503,503s503-225,503-503l0,0c0-277-225-503-503-503S9,238,10,515L10,515z" fill="{{bg2}}"></path><path d="M777,322L547,178c-28-18-64-18-91,0L226,322c-25,16-40,43-40,73v263c0,76,61,137,137,137h61V633l0,0c0-66,53-119,119-119l0,0c66,0,119,53,119,119v162h61l0,0c76,0,137-61,137-137V395c-1-29-17-56-42-73H777z" fill="{{bg1}}"></path></svg>';
|
||||||
|
app.globalData.tabbarArr.push({
|
||||||
|
name: 'tabbar.index',
|
||||||
|
fullpath: '/pages/main/index',
|
||||||
|
selecticon: svg.replaceAll(/{{bg1}}/g, bgsel1).replaceAll(/{{bg2}}/g, bgsel2),
|
||||||
|
icon: svg.replaceAll(/{{bg1}}/g, bggray1).replaceAll(/{{bg2}}/g, bggray2)
|
||||||
|
});
|
||||||
|
// svg = '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M969,956L913,810c51-81,107-209,103-313C1008,230,789,15,522,10C237,5,5,237,9,522c4,274,223,494,497,494c69,0,208-38,265-75L932,997C954,998,972,979,969,956L969,956z" fill="{{bg2}}"></path><path d="M715,299l-22,133c-3,16,3,32,15,43l99,94c20,19,20,49,1,69c-7,7-17,12-28,15l-134,21c-16,3-30,12-37,27l-59,122c-12,25-42,35-65,22c-10-5-17-12-22-22l-62-121c-7-15-21-25-37-27l-134-19c-27-4-46-28-42-55c1-11,6-21,14-28l96-96c11-11,17-27,14-43l-23-134c-5-27,14-52,39-57c11-1,22,0,31,5l121,63c15,7,32,7,46,0l119-64c23-12,54-4,67,20C715,277,716,288,715,299z" fill="{{bg1}}"></path></svg>';
|
||||||
|
// app.globalData.tabbarArr.push({
|
||||||
|
// name: 'tabbar.zh',
|
||||||
|
// fullpath: '/pages/expo',
|
||||||
|
// selecticon: svg.replaceAll(/{{bg1}}/g, bgsel1).replaceAll(/{{bg2}}/g, bgsel2),
|
||||||
|
// icon: svg.replaceAll(/{{bg1}}/g, bggray1).replaceAll(/{{bg2}}/g, bggray2)
|
||||||
|
// });
|
||||||
|
// svg = '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M788,950h-551c-80,0-144-64-144-144V281h839v524C933,886,869,950,788,950L788,950z" fill="{{bg2}}"></path><path d="M685,842H352c-33,0-60-27-60-60s27-60,60-60h333c33,0,60,27,60,60S718,842,685,842z M946,322H80c-41,0-75-33-75-75V136c0-41,33-75,75-75h866c41,0,75,33,75,75v111C1021,288,988,322,946,322z" fill="{{bg1}}"></path></svg>';
|
||||||
|
// app.globalData.tabbarArr.push({
|
||||||
|
// name: 'tabbar.sq',
|
||||||
|
// fullpath: '/pages/socg',
|
||||||
|
// selecticon: svg.replaceAll(/{{bg1}}/g, bgsel1).replaceAll(/{{bg2}}/g, bgsel2),
|
||||||
|
// icon: svg.replaceAll(/{{bg1}}/g, bggray1).replaceAll(/{{bg2}}/g, bggray2)
|
||||||
|
// });
|
||||||
|
// svg = '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M207,110h614c109,0,197,88,197,197v416c0,109-88,197-197,197H207c-109,0-197-88-197-197V308C9,198,97,110,207,110z" fill="{{bg2}}"></path><path d="M865,819H118c-10,0-19-9-19-19c0-3,1-7,2-10l26-35c3-6,10-9,17-9h748c10,0,19,9,19,19c0,3-1,7-2,10l-26,35C878,815,872,819,865,819z M451,285c0-8-6-14-14-14h-246c-8,0-14,6-14,14v246c0,8,6,14,14,14h246c8,0,14-6,14-14V285z M909,503c0-8-6-14-14-14H562c-8,0-14,6-14,14v25c0,8,6,14,14,14h333c8,0,14-6,14-14V503z" fill="{{bg1}}"></path></svg>';
|
||||||
|
// app.globalData.tabbarArr.push({
|
||||||
|
// name: 'tabbar.cd',
|
||||||
|
// fullpath: '/pages/card',
|
||||||
|
// selecticon: svg.replaceAll(/{{bg1}}/g, bgsel1).replaceAll(/{{bg2}}/g, bgsel2),
|
||||||
|
// icon: svg.replaceAll(/{{bg1}}/g, bggray1).replaceAll(/{{bg2}}/g, bggray2)
|
||||||
|
// });
|
||||||
|
svg = '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M706,460c64-38,107-104,107-179c0-118-106-213-237-213c-131,0-237,95-237,213c0,75,43,141,107,179c-181,51-311,206-311,385c0,39,35,70,78,70H938c43,0,78-32,78-70v-5C1017,661,886,511,706,460L706,460z" fill="{{bg1}}"/><path d="M580,472c64-42,107-115,107-197c0-131-106-237-237-237c-131,0-237,106-237,237c0,83,43,155,107,199c-181,57-311,228-311,427c0,43,14,76,57,76l745,1c43,0,78-35,78-78v-6C891,696,761,528,580,472L580,472z" fill="{{bg2}}"/></svg>';
|
||||||
|
app.globalData.tabbarArr.push({
|
||||||
|
name: 'tabbar.me',
|
||||||
|
fullpath: '/pages/main/me',
|
||||||
|
selecticon: svg.replaceAll(/{{bg1}}/g, bgsel1).replaceAll(/{{bg2}}/g, bgsel2),
|
||||||
|
icon: svg.replaceAll(/{{bg1}}/g, bggray1).replaceAll(/{{bg2}}/g, bggray2)
|
||||||
|
});
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
getnewnotice();
|
||||||
|
}, 120000); //2分钟请求一次notice
|
||||||
|
getnewnotice();
|
||||||
|
//lopn 结合me,将数据上传到平台
|
||||||
|
function getnewnotice() {
|
||||||
|
return;
|
||||||
|
app.callfunc({
|
||||||
|
func: 'me.notice_new',
|
||||||
|
showload: false,
|
||||||
|
success: json => {
|
||||||
|
app.setTabbar({
|
||||||
|
'index.detail': {
|
||||||
|
reddot: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
plus.runtime.getProperty(plus.runtime.appid, widgetInfo => {
|
||||||
|
app.globalData._version = widgetInfo.version;
|
||||||
|
});
|
||||||
|
app.appupdate('app');
|
||||||
|
uni.getPushClientId({
|
||||||
|
success: (res) => {
|
||||||
|
console.log('客户端推送标识:', res);
|
||||||
|
app.globalData._appcid = res.cid;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
uni.onPushMessage((res) => {
|
||||||
|
this.alert(JSON.stringify(res));
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
var sysinfo = app.globalData._sysinfo;
|
||||||
|
if (sysinfo.model == 'k71v1_64_bsp') {
|
||||||
|
app.device_rfid = uni.requireNativePlugin("UhfGModule"); // 133左/134枪/135右
|
||||||
|
app.device_rfid_gunkey = 134;
|
||||||
|
} else if (sysinfo.model == 'k62v1_6c') {
|
||||||
|
app.device_rfid = uni.requireNativePlugin(
|
||||||
|
"UhfGModule"); //C61型号,手柄按键137,左侧135,右侧是136 F1-F4对应131-134
|
||||||
|
app.device_rfid_gunkey = 137;
|
||||||
|
}
|
||||||
|
console.log('device_rfid', app.device_rfid);
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
app.globalData.dev_bt = {};
|
||||||
|
//自动连接蓝牙
|
||||||
|
this.info = uni.getStorageInfoSync();
|
||||||
|
this.info.kv = {};
|
||||||
|
this.info.total = 0;
|
||||||
|
for (var i in this.info.keys) {
|
||||||
|
var key = this.info.keys[i];
|
||||||
|
if (key.indexOf('dev_bt_') !== 0)
|
||||||
|
continue;
|
||||||
|
var savedev = app.getstorage(key);
|
||||||
|
var devup = key.substr(7);
|
||||||
|
console.log('auto', savedev, devup);
|
||||||
|
if (devup != savedev.devup) {
|
||||||
|
console.log('蓝牙自动连接设置错误', devup, savedev.devup);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
app.connectbt(savedev.devup, savedev.devtype, savedev.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.onBLEConnectionStateChange(res => {
|
||||||
|
//设置dev_bt,重连。
|
||||||
|
console.log('statechanged', res);
|
||||||
|
for (var dup in app.globalData.dev_bt) {
|
||||||
|
var devbt = app.globalData.dev_bt[dup];
|
||||||
|
if (devbt.deviceid != res.deviceId)
|
||||||
|
continue;
|
||||||
|
devbt.opened = res.connected ? 10 : 9;
|
||||||
|
if (typeof(devbt.onmsg) == 'function')
|
||||||
|
devbt.onmsg(res);
|
||||||
|
if (res.connected)
|
||||||
|
return;
|
||||||
|
if (devbt.enableclose)
|
||||||
|
return;
|
||||||
|
console.log('re devopen' + devbt.deviceid);
|
||||||
|
devbt.bt_devopen(devbt.deviceid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
uni.onBLECharacteristicValueChange(res => {
|
||||||
|
console.log('onBLECharacteristicValueChange', res);
|
||||||
|
for (var dup in app.globalData.dev_bt) {
|
||||||
|
var devbt = app.globalData.dev_bt[dup];
|
||||||
|
if (devbt.deviceid != res.deviceId)
|
||||||
|
continue;
|
||||||
|
var dat = devbt.convertmsg(res);
|
||||||
|
res.data = dat;
|
||||||
|
if (typeof(devbt.onmsg) == 'function')
|
||||||
|
devbt.onmsg(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
},
|
||||||
|
onShow: function() {},
|
||||||
|
onHide: function() {},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,272 @@
|
||||||
|
<template>
|
||||||
|
<view class="_vocr">
|
||||||
|
<view>
|
||||||
|
<view v-if="workstep == 1" class="rel">
|
||||||
|
<cover-image v-if="maskpng" :src="file_stor(maskpng)" class="abs t0 l0" :style="{opacity:0.8,width: '100%', height: height + 'vw'}"></cover-image>
|
||||||
|
<camera device-position="back" flash="off" :style="{width: '100%', height: height + 'vw'}"></camera>
|
||||||
|
</view>
|
||||||
|
<view v-if="workstep == 2" class="rel">
|
||||||
|
<image :src="src" :style="{width: '100%', height: height + 'vw',display:'block'}"></image>
|
||||||
|
<view v-for="txtpo in txtpos" class='abs' @tap="boxclick(txtpo)" :style="{top:txtpo.top,left:txtpo.left,width:txtpo.width,height:txtpo.height,minWidth:'0.7em',minHeight:'0.7em',border:'1px solid ' + bordercolor,borderRadius:'3px'}"></view>
|
||||||
|
<view v-if="txtpos.length == 0" class='abs b0 r0 _noocr'>无文字</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex px2" style="justify-content: space-between;height:3em;">
|
||||||
|
<view>
|
||||||
|
<ciy-svgimg v-if="workstep==0" @tap="workstep=1" :src="svg.opencamera" ciystyle="width:2em;height:2em;"></ciy-svgimg>
|
||||||
|
<ciy-svgimg v-else @tap="workstep=0" :src="svg.closecamera" ciystyle="width:2em;height:2em;"></ciy-svgimg>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<button v-if="workstep==1" class="btn lg cc" @tap="ocrnow">拍摄识别</button>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<ciy-svgimg v-if="workstep == 2" @tap="workstep=1" :src="svg.recamera" ciystyle="width:2em;height:2em;"></ciy-svgimg>
|
||||||
|
<view v-else style="width:2em;height:2em;"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change', 'textclick'],
|
||||||
|
props: {
|
||||||
|
maskpng: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '66'
|
||||||
|
},
|
||||||
|
bordercolor: {
|
||||||
|
type: String,
|
||||||
|
default: '#00e112'
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'text' //idcard身份证自动校正,none 无文字不ocr,text ocr有文字(无文字5秒超时)
|
||||||
|
},
|
||||||
|
checkidcard: {
|
||||||
|
type: String,
|
||||||
|
default: '' //front人像,back国徽
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
txtpos: [],
|
||||||
|
src: '',
|
||||||
|
svg:{
|
||||||
|
opencamera:'<svg viewBox="0 0 1024 1024" version="1" xmlns="http://www.w3.org/2000/svg"><path d="M868 288a64 64 0 0 1 101 52l3 303a64 64 0 0 1-103 51l-207-158a64 64 0 0 1 2-103l204-145z" fill="#1296db"></path><path d="M144 192h456a96 96 0 0 1 96 96v417a96 96 0 0 1-96 96H144a96 96 0 0 1-96-96V288a96 96 0 0 1 96-96z" fill="#1296db"></path></svg>',
|
||||||
|
closecamera:'<svg viewBox="0 0 1024 1024" version="1" xmlns="http://www.w3.org/2000/svg"><path d="M107 152A32 32 0 1 1 149 104l768 672a32 32 0 0 1-42 48l-768-672z" fill="#1296db"></path><path d="M733 462l-37-52 172-122a64 64 0 0 1 101 52l3 303a64 64 0 0 1-20 47l-44-47-3-303-172 122z m-35-54l36 53c-11 7-24 12-37 12a64 64 0 0 1-64-64V288a32 32 0 0 0-32-32h-206V192h206a96 96 0 0 1 96 96v121c0-0 1-1 2-1zM632 608h64v97a96 96 0 0 1-96 96H144a96 96 0 0 1-96-96V288a96 96 0 0 1 96-96h96v64h-96a32 32 0 0 0-32 32v417a32 32 0 0 0 32 32h456a32 32 0 0 0 32-32V608z" fill="#1296db"></path></svg>',
|
||||||
|
recamera:'<svg viewBox="0 0 1024 1024" version="1" xmlns="http://www.w3.org/2000/svg"><path d="M533 175v-62l-228 143 228 143v-107c114 26 200 128 200 249 0 141-116 257-257 257s-257-116-257-257c0-32-26-57-57-57-32 0-57 26-57 57 0 204 167 371 371 371s371-167 371-371c0-185-137-339-314-366z" fill="#1296db"></path></svg>'
|
||||||
|
},
|
||||||
|
workstep: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {
|
||||||
|
var vkopn = {};
|
||||||
|
vkopn.version = 'v1';
|
||||||
|
vkopn.track = {};
|
||||||
|
vkopn.track.IDCard = {};
|
||||||
|
vkopn.track.IDCard.mode = 2;
|
||||||
|
vkopn.track.OCR = {};
|
||||||
|
vkopn.track.OCR.mode = 2;
|
||||||
|
vkopn.gl = this.gl;
|
||||||
|
this.session = wx.createVKSession(vkopn);
|
||||||
|
this.session.start(err => {
|
||||||
|
this.session.on('updateAnchors', this.onanchor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
this.session.off('updateAnchors', this.onanchor);
|
||||||
|
this.session.stop();
|
||||||
|
this.session.destroy();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
boxclick(po) {
|
||||||
|
this.$emit('textclick', po);
|
||||||
|
},
|
||||||
|
onanchor(anchors) {
|
||||||
|
if (typeof(this.auchorcb) == 'function')
|
||||||
|
this.auchorcb(anchors);
|
||||||
|
},
|
||||||
|
Step(step) {
|
||||||
|
this.workstep = step;
|
||||||
|
},
|
||||||
|
//摄像头开关在下,且用图标占位。
|
||||||
|
//重新拍摄在下右。方便点击。
|
||||||
|
//拍摄识别在中。
|
||||||
|
|
||||||
|
|
||||||
|
//按拍摄后,自动识别
|
||||||
|
//无文字,在图片旁边标注即可。
|
||||||
|
//拍照完成,上面有文字。
|
||||||
|
//用户点门头,上传门头。
|
||||||
|
//用户点企业,再点文字,文字进企业框。
|
||||||
|
//用户点展位号,
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//拍照,拍照+识别
|
||||||
|
//在摄像头正常的时候,点一下门头,拍照,上传。
|
||||||
|
//在摄像头正常的时候,点一下企业,拍照识别,点框
|
||||||
|
//在摄像头正常的时候,点一下企业,拍照识别,点框
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async runvk(mode, file) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
var _time = setTimeout(() => {
|
||||||
|
reject('timeout');
|
||||||
|
}, 5000);
|
||||||
|
this.auchorcb = anchors => {
|
||||||
|
clearTimeout(_time);
|
||||||
|
resolve(anchors);
|
||||||
|
};
|
||||||
|
if (mode == 'idcard') {
|
||||||
|
this.session.detectIDCard({
|
||||||
|
frameBuffer: file.buffer,
|
||||||
|
width: file.width,
|
||||||
|
height: file.height,
|
||||||
|
getAffineImg: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.session.runOCR({
|
||||||
|
frameBuffer: file.buffer,
|
||||||
|
width: file.width,
|
||||||
|
height: file.height,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error('vk error', e);
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ocrnow() {
|
||||||
|
const ctx = wx.createCameraContext();
|
||||||
|
ctx.takePhoto({
|
||||||
|
quality: 'high',
|
||||||
|
success: async (res) => {
|
||||||
|
this.workstep = 2;
|
||||||
|
this.txtpos = [];
|
||||||
|
this.src = res.tempImagePath;
|
||||||
|
res.buffer = await this.getimgbuffer(res);
|
||||||
|
var ret = {};
|
||||||
|
ret.tempimg = res.tempImagePath;
|
||||||
|
ret.width = res.width;
|
||||||
|
ret.height = res.height;
|
||||||
|
if (this.mode == 'idcard') {
|
||||||
|
var anchors = await this.runvk('idcard', res);
|
||||||
|
var anchor = anchors[0];
|
||||||
|
if (anchor.isComplete != 1)
|
||||||
|
return this.alert('身份证拍摄不完整');
|
||||||
|
if (this.checkidcard == 'front') {
|
||||||
|
if (anchor.label != 0)
|
||||||
|
return this.alert('请拍摄身份证人像面');
|
||||||
|
if (anchor.orientation != 0)
|
||||||
|
return this.alert('请朝上放正拍摄身份证');
|
||||||
|
}
|
||||||
|
if (this.checkidcard == 'back') {
|
||||||
|
if (anchor.label != 1)
|
||||||
|
return this.alert('请拍摄身份证国徽面');
|
||||||
|
if (anchor.orientation != 0)
|
||||||
|
return this.alert('请朝上放正拍摄身份证');
|
||||||
|
}
|
||||||
|
ret.idcardface = anchor.label; //0 照片面 / 1 国徽面
|
||||||
|
ret.orientation = anchor.orientation; // 身份证朝向 (0 朝上 1 朝下 2 朝下 3 朝左)
|
||||||
|
|
||||||
|
const canvas = wx.createOffscreenCanvas({
|
||||||
|
type: '2d',
|
||||||
|
width: anchor.affineImgWidth,
|
||||||
|
height: anchor.affineImgHeight,
|
||||||
|
});
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
context.clearRect(0, 0, anchor.affineImgWidth, anchor.affineImgHeight);
|
||||||
|
|
||||||
|
context.setTransform(
|
||||||
|
Number(anchor.affineMat[0]), Number(anchor.affineMat[3]), Number(anchor.affineMat[1]),
|
||||||
|
Number(anchor.affineMat[4]), Number(anchor.affineMat[2]), Number(anchor.affineMat[5])
|
||||||
|
);
|
||||||
|
context.drawImage(this._img, 0, 0, res.width, res.height);
|
||||||
|
const imageData = context.getImageData(0, 0, anchor.affineImgWidth, anchor.affineImgHeight);
|
||||||
|
res.buffer = imageData.data.buffer;
|
||||||
|
res.width = anchor.affineImgWidth;
|
||||||
|
res.height = anchor.affineImgHeight;
|
||||||
|
this.src = canvas.toDataURL();
|
||||||
|
}
|
||||||
|
ret.txts = [];
|
||||||
|
ret.txtall = '';
|
||||||
|
if (this.mode != 'none') { //无文字时会有直接卡死bug
|
||||||
|
try {
|
||||||
|
var anchors = await this.runvk('ocr', res);
|
||||||
|
ret.anchors = anchors;
|
||||||
|
for (var i in anchors) {
|
||||||
|
if (anchors[i].text)
|
||||||
|
ret.txtall = anchors[i].text;
|
||||||
|
if (!anchors[i].subtext)
|
||||||
|
continue;
|
||||||
|
ret.txts.push(anchors[i].subtext);
|
||||||
|
var pos = anchors[i].box;
|
||||||
|
this.txtpos.push({
|
||||||
|
text: anchors[i].subtext,
|
||||||
|
alltext: anchors[i].text,
|
||||||
|
pos: pos,
|
||||||
|
top: (pos[0].y * 100) + '%',
|
||||||
|
left: (pos[0].x * 100) + '%',
|
||||||
|
width: ((pos[1].x - pos[0].x) * 100) + '%',
|
||||||
|
height: ((pos[2].y - pos[0].y) * 100) + '%',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
//this.toast('无文字,请重新拍摄');
|
||||||
|
//this.workstep = 1;
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit('change', ret);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async getimgbuffer(file) {
|
||||||
|
const canvas = wx.createOffscreenCanvas({
|
||||||
|
type: '2d',
|
||||||
|
width: file.width,
|
||||||
|
height: file.height,
|
||||||
|
});
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
this._img = canvas.createImage();
|
||||||
|
this._img.src = file.tempImagePath;
|
||||||
|
var err = await this.goe(this.go_load(this._img));
|
||||||
|
if (err)
|
||||||
|
return reject('Image Load Error');
|
||||||
|
|
||||||
|
context.clearRect(0, 0, file.width, file.height);
|
||||||
|
context.drawImage(this._img, 0, 0, file.width, file.height);
|
||||||
|
|
||||||
|
var imgData = context.getImageData(0, 0, file.width, file.height);
|
||||||
|
return imgData.data.buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._vocr {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._noocr {
|
||||||
|
background: #00000044;
|
||||||
|
color: #000000;
|
||||||
|
text-shadow: 1px 1px 0 #ffffff88;
|
||||||
|
padding: 0.3em 0.8em;
|
||||||
|
border-radius: 0.5em 0 0 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<view class="_voice" @touchstart="start" @touchend="stop" v-if="benable">
|
||||||
|
<ciy-ani class="_txt" ref="ani">{{txt}}</ciy-ani>
|
||||||
|
<ciy-svgimg :src="svg" class="_img" :style="{filter:'hue-rotate('+deg+'deg)'}"></ciy-svgimg>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
maskpng: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
benable: true,
|
||||||
|
bst: false,
|
||||||
|
txt: '',
|
||||||
|
deg: 0, //150 红
|
||||||
|
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" version="1"><path fill="#1989d8" d="M1006 520c0 269-218 486-486 486-56 0-110-10-161-28-13 10-28 18-46 18-41 0-74-33-74-74 0-41 33-74 74-74 33 0 61 23 72 54 44 15 90 23 136 23 225 0 407-182 407-407 0-79-23-154-61-215-3-5-3-10-3-15 0-20 5-28 20-38 13-8 23-5 38-5 54 79 84 174 84 276z m-266-159v317c0 20-15 36-36 36-20 0-36-15-36-36V361c0-20 15-36 36-36 18 0 36 15 36 36z m-133 343h-8l-20 8c-8 0-18-13-20-20l-38-102h-146l-56 102c-3 8-13 20-20 20l-26-8c-10 0-18-8-18-18v-8L394 333c3-8 10-10 15-10h46c8 0 13 5 15 10L614 681c5 10 0 20-8 23zM435 404l-61 115h123L435 404z m269-238c-26 0-49-15-61-36-38-13-79-18-120-18-225 0-407 182-407 407 0 46 8 92 23 133 5 18 13 38 15 49 8 18-15 36-36 36-33 0-44-26-44-26-26-59-41-125-41-195 0-269 218-486 486-486 44 0 84 5 123 18 13-18 36-31 59-31 41 0 74 33 74 74 0 41-33 74-72 74z"/></svg>'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {
|
||||||
|
var app = getApp();
|
||||||
|
if (app.globalData.plugin_wechatsi_manager) {
|
||||||
|
app.globalData.plugin_wechatsi_manager.onStop = res => {
|
||||||
|
this.$emit('change', {
|
||||||
|
txt: res.result,
|
||||||
|
data: res
|
||||||
|
});
|
||||||
|
this.getrefsSync('ani', this).Doani('op0|op1,200');
|
||||||
|
this.txt = res.result;
|
||||||
|
if (this._t)
|
||||||
|
clearTimeout(this._t);
|
||||||
|
this._t = setTimeout(() => {
|
||||||
|
this.getrefsSync('ani', this).Doani('op1|op0,sa1.5,300|hide');
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
app.globalData.plugin_wechatsi_manager.onStart = res => {
|
||||||
|
console.log("成功开始录音识别", res)
|
||||||
|
}
|
||||||
|
app.globalData.plugin_wechatsi_manager.onError = res => {
|
||||||
|
clearInterval(this._an);
|
||||||
|
this.deg = 150; //红
|
||||||
|
console.error("error msg", res.msg)
|
||||||
|
}
|
||||||
|
this._an = setInterval(() => {
|
||||||
|
this.deg += 10;
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
this.benable = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
clearInterval(this._an);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
test() {
|
||||||
|
this.getrefsSync('ani', this).Doani('op0|op1,200');
|
||||||
|
this.txt = 'res.result';
|
||||||
|
if (this._t)
|
||||||
|
clearTimeout(this._t);
|
||||||
|
this._t = setTimeout(() => {
|
||||||
|
this.getrefsSync('ani', this).Doani('op1|op0,sa1.5,300|hide');
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
},
|
||||||
|
start() {
|
||||||
|
this.bst = true;
|
||||||
|
var app = getApp();
|
||||||
|
app.globalData.plugin_wechatsi_manager.start({
|
||||||
|
duration: 60000
|
||||||
|
});
|
||||||
|
},
|
||||||
|
stop() {
|
||||||
|
this.bst = false;
|
||||||
|
var app = getApp();
|
||||||
|
app.globalData.plugin_wechatsi_manager.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._voice ._img {
|
||||||
|
width: 3em;
|
||||||
|
height: 3em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
._voice ._txt {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 7em;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
opacity: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
<template>
|
||||||
|
<view :animation="anidatamask" class="_mask" @tap="close('mask')" v-if="popsh" :style="{background:'#00000044',zIndex:50020,opacity:0}"></view>
|
||||||
|
<view :animation="anidatapop" v-if="popsh" class="_dialog" :style="dialogstyle" @tap="nobtnclose" style="z-index:50020">
|
||||||
|
<view class="_title" v-if="title">{{title}}</view>
|
||||||
|
<view class="_content" :style="{maxHeight:maxheight,height:height}">
|
||||||
|
<view v-if="html" v-html="html"></view>
|
||||||
|
<view v-if="ele" style="padding:1em;">
|
||||||
|
<view v-if="content" v-html="tobr(content)" style="padding-bottom:1em;"></view>
|
||||||
|
<ciy-input v-if="ele == 'input'" bb v-model="inputtxt"></ciy-input>
|
||||||
|
<view v-else>
|
||||||
|
<ciy-textarea bb v-model="inputtxt"></ciy-textarea>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="content" v-html="tobr(content)" style="padding:1.5em 0.5em;" :style="{textAlign:align}"></view>
|
||||||
|
<view style="display: flex;gap: 0.5em;justify-content: flex-end;padding: 0.5em 1em;" v-if="btns.length > 0">
|
||||||
|
<view v-for="(item,index) in btns" :key="index" class="btn" :class="item.cls" @tap="chkbtn(item.btn)">{{item.name}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog {
|
||||||
|
position: fixed;
|
||||||
|
left: 1.5em;
|
||||||
|
right: 1.5em;
|
||||||
|
border: 1px solid var(--bg6);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
background: var(--bg1);
|
||||||
|
transform: scale(0.8);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._title {
|
||||||
|
line-height: 1.5em;
|
||||||
|
background: linear-gradient(150deg, var(--bg2), var(--bg4));
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-radius: 0.5em 0.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._content {
|
||||||
|
overflow: scroll;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
popsh: false,
|
||||||
|
dialogstyle: {},
|
||||||
|
anidatamask: {},
|
||||||
|
anidatapop: {},
|
||||||
|
maxheight: 'auto',
|
||||||
|
height: 'auto',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
align: '',
|
||||||
|
ele: null,
|
||||||
|
inputtxt: '',
|
||||||
|
html: '',
|
||||||
|
btns: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async Open(res) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
if (this.popsh) {
|
||||||
|
this.popsh = false;
|
||||||
|
await this.sleep(500);
|
||||||
|
}
|
||||||
|
this.cb = resolve;
|
||||||
|
res = res || {};
|
||||||
|
if (typeof(res) == 'string') {
|
||||||
|
res = {
|
||||||
|
content: res
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.title = res.title === undefined ? this.lang('alert.deftitle') : res.title;
|
||||||
|
this.align = res.align || 'center';
|
||||||
|
this.inputtxt = res.value ? res.value : '';
|
||||||
|
this.ele = res.ele;
|
||||||
|
if (res.content && res.content[0] == '<') {
|
||||||
|
this.html = res.content;
|
||||||
|
this.content = '';
|
||||||
|
} else {
|
||||||
|
this.html = '';
|
||||||
|
this.content = res.content;
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
var app = getApp();
|
||||||
|
if (res.height) {
|
||||||
|
this.height = res.height;
|
||||||
|
this.maxheight = 'auto';
|
||||||
|
} else {
|
||||||
|
this.height = 'auto';
|
||||||
|
var height = app.globalData._sysinfo.screenHeight - 80;
|
||||||
|
this.maxheight = height + 'px';
|
||||||
|
}
|
||||||
|
this.btns = [];
|
||||||
|
if (res.btns) {
|
||||||
|
if (typeof(res.btns) == 'string') {
|
||||||
|
var btns = res.btns.split(',');
|
||||||
|
for (var i in btns) {
|
||||||
|
this.btns.push({
|
||||||
|
name: this.lang(btns[i]),
|
||||||
|
btn: btns[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i in res.btns) {
|
||||||
|
this.btns.push(res.btns[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var top = (app.globalData._sysinfo.windowHeight / 4);
|
||||||
|
if (top < headerheight + 20)
|
||||||
|
top = headerheight + 20;
|
||||||
|
this.dialogstyle.marginTop = top + 'px';
|
||||||
|
this.popsh = true;
|
||||||
|
this.goani('sa0.8,op0|sa1,op1,400', data => this.anidatapop = data);
|
||||||
|
this.goani('op0|op1,400', data => this.anidatamask = data);
|
||||||
|
}).catch(e => {
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
chkbtn(btn) {
|
||||||
|
if (!this.ele)
|
||||||
|
return this.close(btn);
|
||||||
|
if (btn == 'cancel')
|
||||||
|
return this.close({
|
||||||
|
text: '',
|
||||||
|
btn
|
||||||
|
});
|
||||||
|
this.close({
|
||||||
|
text: this.inputtxt,
|
||||||
|
btn
|
||||||
|
});
|
||||||
|
this.inputtxt = '';
|
||||||
|
},
|
||||||
|
nobtnclose() {
|
||||||
|
if (this.btns.length > 0)
|
||||||
|
return;
|
||||||
|
this.close('nobtnclose');
|
||||||
|
},
|
||||||
|
async close(btn) {
|
||||||
|
this.goani('sa1,op1|sa0.8,op0,400', data => this.anidatapop = data);
|
||||||
|
await this.goani('op0,400', data => this.anidatamask = data);
|
||||||
|
this.popsh = false;
|
||||||
|
this.cb(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<template>
|
||||||
|
<view :animation="animationData" class="_refani" v-if="show" :style="cstyle">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
virtualHost: true
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
ani: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: true,
|
||||||
|
mastyle: {height:'auto'},
|
||||||
|
animationData: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
ani(newD, oldD) {
|
||||||
|
this.Doani(newD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
cstyle() {
|
||||||
|
this.mastyle.overflow = 'hidden';
|
||||||
|
var sty = this.ciystyle;
|
||||||
|
if(typeof(sty) == 'string')
|
||||||
|
sty = this.style2obj(sty, this.mastyle);
|
||||||
|
return sty;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.rect = {};
|
||||||
|
if (this.ani)
|
||||||
|
this.Doani(this.ani);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async Doani(opn) {
|
||||||
|
if (this._aniing)
|
||||||
|
return;
|
||||||
|
//opn,string=anis
|
||||||
|
//{anis:string/array, init:obj}
|
||||||
|
//in out show,先show,如果是out,show=false,其他不变
|
||||||
|
//多个step执行,微信小程序会出现合并执行的bug
|
||||||
|
//设置初始style,部分低版本浏览器无效,用16ms单帧替代
|
||||||
|
//init参数希望不同step表现不同,用anis[array],step单独传参
|
||||||
|
//matrix,xx3d等,anis[string]未定义,需anis[array]。
|
||||||
|
this.show = true;
|
||||||
|
if (typeof(opn) == 'string') {
|
||||||
|
//ResizeObserver微信小程序不支持
|
||||||
|
if (opn.indexOf('hhauto') > -1) {
|
||||||
|
this.mastyle.height = 'auto';
|
||||||
|
this.mastyle.display = 'block';
|
||||||
|
await this.$nextTick();
|
||||||
|
var rect = await this.getrect('._refani');
|
||||||
|
//console.log('rect.height',rect.height,this.rect.height);
|
||||||
|
if (rect.width != 0 && rect.height != 0)
|
||||||
|
this.rect = rect;
|
||||||
|
if(this.rect.height)
|
||||||
|
opn = opn.replace('hhauto', 'hh' + this.rect.height);
|
||||||
|
else
|
||||||
|
opn = opn.replace('hhauto', 'hh0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._aniing = true;
|
||||||
|
await this.goani(opn, data => this.animationData = data, (key, val) => {
|
||||||
|
this.show = false;
|
||||||
|
});
|
||||||
|
this._aniing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
<template>
|
||||||
|
<view class="_refani" v-if="anishow" :style="cstyle">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
virtualHost: true
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
speedms: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 500
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
anishow: false,
|
||||||
|
height: -1
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
show(newD, oldD) {
|
||||||
|
this.Showani(newD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
cstyle() {
|
||||||
|
var sty = this.ciystyle;
|
||||||
|
var mastyle = {};
|
||||||
|
mastyle.overflow = 'hidden';
|
||||||
|
if(this.height == -1){
|
||||||
|
mastyle.height = 'auto';
|
||||||
|
if(this.op == 0)
|
||||||
|
mastyle.opacity = 0;
|
||||||
|
}else{
|
||||||
|
mastyle.height = this.height + 'px';
|
||||||
|
mastyle.opacity = 1;
|
||||||
|
}
|
||||||
|
sty = this.style2obj(sty, mastyle);
|
||||||
|
return sty;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.rect = {};
|
||||||
|
if (this.show)
|
||||||
|
this.Showani(this.show);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async Showani(bshow) {
|
||||||
|
if(this.height == 0)
|
||||||
|
this.op = 0;
|
||||||
|
else
|
||||||
|
this.op = 1;
|
||||||
|
this.height = -1;
|
||||||
|
this.anishow = true;
|
||||||
|
var rect = await this.getrect('._refani');
|
||||||
|
if (rect && rect.height != 0)
|
||||||
|
this.rect = rect;
|
||||||
|
clearInterval(this.anitimeout);
|
||||||
|
//cancelAnimationFrame(this.animationFrameId);
|
||||||
|
if (bshow) {
|
||||||
|
this.animateHeight(0, this.rect.height, this.toint(this.speedms));
|
||||||
|
} else {
|
||||||
|
this.animateHeight(this.rect.height, 0, this.toint(this.speedms));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animateHeight(startHeight, targetHeight, duration) {
|
||||||
|
this.height = startHeight;
|
||||||
|
const startTime = Date.now();//performance.now();
|
||||||
|
this.anitimeout = setInterval(() => {
|
||||||
|
const elapsed = Date.now() - startTime;
|
||||||
|
const progress = Math.min(elapsed / duration, 1);
|
||||||
|
this.height = startHeight + (targetHeight - startHeight) * progress;
|
||||||
|
if (progress >= 1)
|
||||||
|
clearInterval(this.anitimeout);
|
||||||
|
}, 16);
|
||||||
|
//this.animationFrameId = uni.requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
<template>
|
||||||
|
<view :animation="anidatamask" class="_mask" @tap="close('mask')" v-if="show" :style="{background:maskbg,zIndex:zindex,opacity:0}"></view>
|
||||||
|
<view :animation="anidatapop" ref="_anipop" class="_anipop" v-if="show" :style="popstyle">
|
||||||
|
<view class="_anicontent">
|
||||||
|
<view v-if="title" class="ciy-caption">
|
||||||
|
{{title}}
|
||||||
|
<view class="_close" @tap="close('closebtn')">×</view>
|
||||||
|
</view>
|
||||||
|
<view style="overflow: auto;" :style="{maxHeight:maxheight+'px'}">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
<view class="footer_safe" :style="{height:footer_safe_height+'px'}"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
._close {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.3em;
|
||||||
|
font-size: 2em;
|
||||||
|
color: var(--txt4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._anipop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
opacity: 0;
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
noclose: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: String,
|
||||||
|
default: 'bottom'
|
||||||
|
},
|
||||||
|
edge: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
maskbg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
bg: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
zindex: {
|
||||||
|
type: Number,
|
||||||
|
default: 992
|
||||||
|
},
|
||||||
|
anispeed: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 300
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
maxheight: 0,
|
||||||
|
popstyle: {},
|
||||||
|
anidatapop: {},
|
||||||
|
anidatamask: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(newD, oldD) {
|
||||||
|
if (newD) {
|
||||||
|
this.Open();
|
||||||
|
} else {
|
||||||
|
this.close('user');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
async Open() {
|
||||||
|
this.bclose = false;
|
||||||
|
this.pagenoscroll(true);
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
this.show = true;
|
||||||
|
var app = getApp();
|
||||||
|
var edge = this.toint(this.edge);
|
||||||
|
var totalms = this.toint(this.anispeed);
|
||||||
|
this.maxheight = (app.globalData._sysinfo.windowHeight - headerheight - this.footer_safe_height);
|
||||||
|
if(this.direction != 'left' && this.direction != 'right')
|
||||||
|
this.maxheight -= this.edge;
|
||||||
|
if (this.title)
|
||||||
|
this.maxheight -= 55;
|
||||||
|
var mainrect = await this.getrect('._anicontent');
|
||||||
|
if (!mainrect)
|
||||||
|
return;
|
||||||
|
this.popstyle = {
|
||||||
|
zIndex: this.zindex
|
||||||
|
};
|
||||||
|
if (this.direction == 'left') {
|
||||||
|
//this.popstyle.transform = 'translateX(-100vw)';
|
||||||
|
this.popstyle.background = this.bg;
|
||||||
|
this.popstyle.marginTop = headerheight + 'px';
|
||||||
|
this.popstyle.marginRight = this.edge + 'px';
|
||||||
|
var top = 0;
|
||||||
|
this.goani('tx-100vh,op0|tx' + top + 'px,op1,' + totalms, data => this.anidatapop = data);
|
||||||
|
} else if (this.direction == 'right') {
|
||||||
|
//this.popstyle.transform = 'translateX(100vw)';
|
||||||
|
this.popstyle.background = this.bg;
|
||||||
|
this.popstyle.marginTop = headerheight + 'px';
|
||||||
|
this.popstyle.marginLeft = this.edge + 'px';
|
||||||
|
var top = 0;
|
||||||
|
this.goani('tx100vh,op0|tx' + top + 'px,op1,' + totalms, data => this.anidatapop = data);
|
||||||
|
} else if (this.direction == 'top') {
|
||||||
|
//this.popstyle.transform = 'translateY(-100vh)';
|
||||||
|
this.popstyle.height = mainrect.height + 'px';
|
||||||
|
var top = headerheight;
|
||||||
|
this.goani('ty-100vh,op0|ty' + top + 'px,op1,' + totalms, data => this.anidatapop = data);
|
||||||
|
} else {
|
||||||
|
//this.popstyle.transform = 'translateY(100vh)'; //selcas在异步处理数据时,出现冲突。原因不明
|
||||||
|
var top = app.globalData._sysinfo.windowHeight - mainrect.top - mainrect.height - this.footer_safe_height;
|
||||||
|
if (top < headerheight + edge) {
|
||||||
|
top = headerheight + edge;
|
||||||
|
}
|
||||||
|
this.goani('ty100vh,op0|ty' + top + 'px,op1,' + totalms, data => this.anidatapop = data);
|
||||||
|
}
|
||||||
|
this.goani('op0|op0,100|op1,' + totalms, data => this.anidatamask = data);
|
||||||
|
this.$emit('change', {
|
||||||
|
from: 'open',
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close(from) {
|
||||||
|
if (this.noclose && from == 'mask')
|
||||||
|
return;
|
||||||
|
if (from != 'user') {
|
||||||
|
this.$emit('update:modelValue', false);
|
||||||
|
}
|
||||||
|
if (!this.show)
|
||||||
|
return;
|
||||||
|
if (this.bclose)
|
||||||
|
return;
|
||||||
|
this.bclose = true;
|
||||||
|
this.pagenoscroll(false);
|
||||||
|
var totalms = this.toint(this.anispeed);
|
||||||
|
if (this.direction == 'left') {
|
||||||
|
this.goani('tx-100vw,op0,' + totalms + '|tx0', data => this.anidatapop = data);
|
||||||
|
} else if (this.direction == 'right') {
|
||||||
|
this.goani('tx100vw,op0,' + totalms + '|tx0', data => this.anidatapop = data);
|
||||||
|
} else if (this.direction == 'top') {
|
||||||
|
this.goani('ty-100vh,op0,' + totalms + '|ty0', data => this.anidatapop = data);
|
||||||
|
} else {
|
||||||
|
this.goani('ty100vh,op0,' + totalms + '|ty0', data => this.anidatapop = data);
|
||||||
|
}
|
||||||
|
this.goani('op0,' + totalms, data => this.anidatamask = data);
|
||||||
|
|
||||||
|
this.$emit('change', {
|
||||||
|
from: from,
|
||||||
|
value: false
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.show = false;
|
||||||
|
}, totalms + 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
<template>
|
||||||
|
<view class="_audio" v-if="!nonedisplay">
|
||||||
|
<view class="_main">
|
||||||
|
<view style="align-self: center;margin-right:0.5em;">
|
||||||
|
<view class="_icon" :class="btncls" @tap="play"></view>
|
||||||
|
</view>
|
||||||
|
<view class="flex1 rel">
|
||||||
|
<view style="text-align:left;font-weight:bold;margin-bottom:0.5em;letter-spacing: 2px;">{{title}}</view>
|
||||||
|
<view class="flex flex-center">
|
||||||
|
<view class="txt-smm">{{statxt}}</view>
|
||||||
|
<view class="flex1 _timepct">
|
||||||
|
<view class="itm" :style="{width:percent + '%'}"></view>
|
||||||
|
</view>
|
||||||
|
<view class="txt-smm">{{endtxt}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="abs txt-right txt-smm" style="right:0;top:0;">
|
||||||
|
{{lang('audio.rate')}} <text class="kbd" @tap="setrate()">{{rates[rateidx].name}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._main {
|
||||||
|
display: flex;
|
||||||
|
border-top: 1px solid var(--bg3);
|
||||||
|
border-bottom: 3px solid var(--bg5);
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._timepct {
|
||||||
|
background: var(--bg6);
|
||||||
|
margin: 0 0.5em;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._timepct>.itm {
|
||||||
|
background: var(--txt7);
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._audio {
|
||||||
|
color: var(--txt7);
|
||||||
|
border: 1px solid var(--bg7);
|
||||||
|
border-radius: 0.8em;
|
||||||
|
background: linear-gradient(0deg, var(--bg3), var(--bg5));
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon {
|
||||||
|
width: 3em;
|
||||||
|
height: 3em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon.play {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTUxMiA4OTZjMjEyLjA3NDY2NyAwIDM4NC0xNzEuOTI1MzMzIDM4NC0zODRTNzI0LjA3NDY2NyAxMjggNTEyIDEyOCAxMjggMjk5LjkyNTMzMyAxMjggNTEyczE3MS45MjUzMzMgMzg0IDM4NCAzODR6IiBmaWxsPSIjMDAwMDAwIj48L3BhdGg+PHBhdGggZD0iTTg1LjMzMzMzMyA1MTJDODUuMzMzMzMzIDI3Ni4zNTIgMjc2LjM1MiA4NS4zMzMzMzMgNTEyIDg1LjMzMzMzM3M0MjYuNjY2NjY3IDE5MS4wMTg2NjcgNDI2LjY2NjY2NyA0MjYuNjY2NjY3LTE5MS4wMTg2NjcgNDI2LjY2NjY2Ny00MjYuNjY2NjY3IDQyNi42NjY2NjdTODUuMzMzMzMzIDc0Ny42NDggODUuMzMzMzMzIDUxMnpNNTEyIDE3MC42NjY2NjdDMzIzLjQ3NzMzMyAxNzAuNjY2NjY3IDE3MC42NjY2NjcgMzIzLjQ3NzMzMyAxNzAuNjY2NjY3IDUxMnMxNTIuODEwNjY3IDM0MS4zMzMzMzMgMzQxLjMzMzMzMyAzNDEuMzMzMzMzIDM0MS4zMzMzMzMtMTUyLjgxMDY2NyAzNDEuMzMzMzMzLTM0MS4zMzMzMzNTNzAwLjUyMjY2NyAxNzAuNjY2NjY3IDUxMiAxNzAuNjY2NjY3eiIgZmlsbD0iIzAwMDAwMCI+PC9wYXRoPjxwYXRoIGQ9Ik00MjYuNjY2NjY3IDUxMnYtMTQ5LjMzMzMzM2wxMTcuMzMzMzMzIDc0LjY2NjY2Nkw2NjEuMzMzMzMzIDUxMmwtMTE3LjMzMzMzMyA3NC42NjY2NjdMNDI2LjY2NjY2NyA2NjEuMzMzMzMzdi0xNDkuMzMzMzMzeiIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPjxwYXRoIGQ9Ik00MDYuMTQ0IDMyNS4yNjkzMzNhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0My40MzQ2NjcgMS40MDhsMjM0LjY2NjY2NiAxNDkuMzMzMzM0YTQyLjY2NjY2NyA0Mi42NjY2NjcgMCAwIDEgMCA3MS45Nzg2NjZsLTIzNC42NjY2NjYgMTQ5LjMzMzMzNEE0Mi42NjY2NjcgNDIuNjY2NjY3IDAgMCAxIDM4NCA2NjEuMzMzMzMzVjM2Mi42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSAyMi4xNDQtMzcuMzk3MzM0ek00NjkuMzMzMzMzIDQ0MC4zODR2MTQzLjIzMkw1ODEuODY2NjY3IDUxMiA0NjkuMzMzMzMzIDQ0MC4zODR6IiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+PC9zdmc+");
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon.pause {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTUxNCAxMTQuM2MtMjE5LjkgMC0zOTguOSAxNzguOS0zOTguOSAzOTguOCAwLjEgMjIwIDE3OSAzOTguOSAzOTguOSAzOTguOSAyMTkuOSAwIDM5OC44LTE3OC45IDM5OC44LTM5OC45IDAtMjE5LjgtMTc4LjktMzk4LjgtMzk4LjgtMzk4Ljh6IG0tMzUuNiA1MzEuNWMwIDMyLjUtMjYuMyA1OC44LTU4LjggNTguOHMtNTguOC0yNi4zLTU4LjgtNTguOFYzODEuNGMwLTMyLjUgMjYuMy01OC44IDU4LjgtNTguOHM1OC44IDI2LjMgNTguOCA1OC44djI2NC40eiBtMTg4LjcgMGMwIDMyLjUtMjYuMyA1OC44LTU4LjggNTguOHMtNTguOC0yNi4zLTU4LjgtNTguOFYzODEuNGMwLTMyLjUgMjYuMy01OC44IDU4LjgtNTguOHM1OC44IDI2LjMgNTguOCA1OC44djI2NC40eiIgZmlsbD0iIzBDMEMwQyI+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '无题'
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
nonedisplay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
coverimg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
epname: { //专辑名
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
singer: { //歌手名
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
btncls: 'play',
|
||||||
|
percent: 0,
|
||||||
|
rateidx: 1,
|
||||||
|
rates: [{
|
||||||
|
rate: 0.5,
|
||||||
|
name: 'x0.5'
|
||||||
|
}, {
|
||||||
|
rate: 1,
|
||||||
|
name: 'x1'
|
||||||
|
}, {
|
||||||
|
rate: 1.25,
|
||||||
|
name: 'x1.25'
|
||||||
|
}, {
|
||||||
|
rate: 1.5,
|
||||||
|
name: 'x1.5'
|
||||||
|
}, {
|
||||||
|
rate: 2,
|
||||||
|
name: 'x2'
|
||||||
|
}],
|
||||||
|
statxt: '00:00',
|
||||||
|
endtxt: '00:00'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
src(newD, oldD) {
|
||||||
|
this.sesrc(newD);
|
||||||
|
},
|
||||||
|
title(newD, oldD) {
|
||||||
|
this.aud.title = newD;
|
||||||
|
},
|
||||||
|
coverimg(newD, oldD) {
|
||||||
|
this.aud.coverImgUrl = newD;
|
||||||
|
},
|
||||||
|
epname(newD, oldD) {
|
||||||
|
this.aud.epname = newD;
|
||||||
|
},
|
||||||
|
singer(newD, oldD) {
|
||||||
|
this.aud.singer = newD;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (!this.aud) {
|
||||||
|
if (this.background)
|
||||||
|
this.aud = wx.getBackgroundAudioManager();
|
||||||
|
else
|
||||||
|
this.aud = uni.createInnerAudioContext();
|
||||||
|
}
|
||||||
|
this.aud.title = this.title;
|
||||||
|
if (this.background) {
|
||||||
|
this.aud.epname = this.epname;
|
||||||
|
this.aud.singer = this.singer;
|
||||||
|
this.aud.coverImgUrl = this.coverimg;
|
||||||
|
}
|
||||||
|
this.setsrc(this.src);
|
||||||
|
this.aud.onPlay(e => {
|
||||||
|
this.btncls = 'pause';
|
||||||
|
this.$emit('change', {
|
||||||
|
from: 'play',
|
||||||
|
value: this.aud
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.aud.onEnded(e => {
|
||||||
|
this.percent = 100;
|
||||||
|
this.statxt = this.endtxt;
|
||||||
|
this.btncls = 'play';
|
||||||
|
this.$emit('change', {
|
||||||
|
from: 'stop',
|
||||||
|
value: this.aud
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.aud.onPause(e => {
|
||||||
|
this.btncls = 'play';
|
||||||
|
this.$emit('change', {
|
||||||
|
from: 'pause',
|
||||||
|
value: this.aud
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.aud.onTimeUpdate(e => {
|
||||||
|
this.endtxt = this.sttime(this.aud.duration);
|
||||||
|
this.statxt = this.sttime(this.aud.currentTime);
|
||||||
|
this.percent = this.aud.currentTime / this.aud.duration * 100;
|
||||||
|
this.btncls = 'pause';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
this.aud.stop();
|
||||||
|
this.aud.destroy();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setsrc(src) {
|
||||||
|
if (!this.aud)
|
||||||
|
return;
|
||||||
|
this.aud.src = src;
|
||||||
|
//this.aud.protocol = 'hls';
|
||||||
|
},
|
||||||
|
setrate() {
|
||||||
|
this.rateidx++;
|
||||||
|
if (this.rateidx >= this.rates.length)
|
||||||
|
this.rateidx = 0;
|
||||||
|
this.aud.playbackRate = this.rates[this.rateidx].rate;
|
||||||
|
},
|
||||||
|
sttime(s) {
|
||||||
|
var m = parseInt(s / 60);
|
||||||
|
var ss = parseInt(s - m * 60);
|
||||||
|
if (ss < 10)
|
||||||
|
ss = '0' + ss;
|
||||||
|
return m + ':' + ss;
|
||||||
|
},
|
||||||
|
play() {
|
||||||
|
if (this.btncls == 'play')
|
||||||
|
this.aud.play();
|
||||||
|
else
|
||||||
|
this.aud.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,418 @@
|
||||||
|
<template>
|
||||||
|
<view :animation="anidataauth" class="auth">
|
||||||
|
<view class="swiper" :style="{transform: 'translateX(' + pg + 'vw)',height:height}">
|
||||||
|
<view class="content">
|
||||||
|
<view class="title">
|
||||||
|
<ciy-gesture @toleft="gopg(1)" class="mid" style="letter-spacing: 1em;">{{lang('login.tabreg')}}</ciy-gesture>
|
||||||
|
<view class="itm" @tap="gopg(1)">{{lang('login.tablogin')}}</view>
|
||||||
|
<view class="itm" @tap="gopg(2)">{{lang('login.tabforget')}}</view>
|
||||||
|
</view>
|
||||||
|
<form @submit="submitreg">
|
||||||
|
<view style="width:600rpx;margin:0.5em auto;">
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>{{lang('login.form_mobile')}}</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input type="number" name="user" placeholder="请输入手机号"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>{{lang('login.form_setpass')}}</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input name="pass" type="password" placeholder="请输入登录密码"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>{{lang('login.form_repass')}}</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input name="pass2" type="password" placeholder="再次输入登录密码"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="margin:1em 0;">
|
||||||
|
<ciy-checkitem sq v-model="xieyi">
|
||||||
|
已阅读并同意
|
||||||
|
<text @tap="gourl" :data-url="lang('login.xieyi')" style="color:#0000FF;">
|
||||||
|
用户协议
|
||||||
|
</text>
|
||||||
|
<text @tap="gourl" :data-url="lang('login.yinsi')" style="color:#0000FF;">
|
||||||
|
隐私协议
|
||||||
|
</text>
|
||||||
|
</ciy-checkitem>
|
||||||
|
</view>
|
||||||
|
<view style="text-align: center;padding-top:1em;">
|
||||||
|
<button class="btn lg cc" form-type="submit">{{lang('login.btn_reg')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</form>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="title">
|
||||||
|
<view class="itm" @tap="gopg(0)" style="padding-right:2em;">{{lang('login.tabreg')}}</view>
|
||||||
|
<ciy-gesture @todown="close" class="mid" style="letter-spacing: 1em;padding-left: 0.5em;" @toright="gopg(0)" @toleft="gopg(2)">{{lang('login.tablogin')}}</ciy-gesture>
|
||||||
|
<view class="itm" @tap="gopg(2)">{{lang('login.tabforget')}}</view>
|
||||||
|
</view>
|
||||||
|
<form @submit="submitlogin">
|
||||||
|
<view style="width:600rpx;margin:0.5em auto;">
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label @tap="showver">{{lang('login.form_mobile')}}</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input :value="user" type="number" name="user" placeholder="请输入手机号"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>{{lang('login.form_pass')}}</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input :value="pass" name="pass" type="password" placeholder="请输入密码"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="margin:1em 0;">
|
||||||
|
<ciy-checkitem sq v-model="xieyi">
|
||||||
|
已阅读并同意
|
||||||
|
<text @tap="gourl" :data-url="lang('login.xieyi')" style="color:#0000FF;">
|
||||||
|
用户协议
|
||||||
|
</text>
|
||||||
|
<text @tap="gourl" :data-url="lang('login.yinsi')" style="color:#0000FF;">
|
||||||
|
隐私协议
|
||||||
|
</text>
|
||||||
|
</ciy-checkitem>
|
||||||
|
</view>
|
||||||
|
<view style="text-align: center;padding-top:1em;">
|
||||||
|
<button class="btn lg cc" style="width: 100%;" form-type="submit">{{lang('login.btn_login')}}</button>
|
||||||
|
</view>
|
||||||
|
<view style="display:inline-block;min-width:2em;min-height:2em;">
|
||||||
|
<view v-if="tusers.length > 0" class="cuser">
|
||||||
|
<view class="itm code" @tap="setdbg(index)" v-for="(item,index) in tusers" :key="index">
|
||||||
|
{{item.name}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="ver<-6" style="text-align: center;color:var(--txt1)">众产(杭州)科技有限公司</view>
|
||||||
|
</view>
|
||||||
|
</form>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="title">
|
||||||
|
<view class="itm" @tap="gopg(0)">{{lang('login.tabreg')}}</view>
|
||||||
|
<view class="itm" @tap="gopg(1)">{{lang('login.tablogin')}}</view>
|
||||||
|
<ciy-gesture @toright="gopg(1)" class="mid">{{lang('login.tabforget')}}</ciy-gesture>
|
||||||
|
</view>
|
||||||
|
<form @submit="submitforget">
|
||||||
|
<view style="width:600rpx;margin:0.5em auto;">
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>{{lang('login.form_mobile')}}</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input v-model="forgetmobile" name="user" type="number" placeholder="请输入手机号"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>验证码</label>
|
||||||
|
<view>
|
||||||
|
<ciy-capcode hasmore name="capsms" btntxt="发送短信" :account="forgetmobile" :func="smsfunc" placeholder="请输入验证码"></ciy-capcode>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>新密码</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input name="pass" type="password" placeholder="请输入新密码"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>再次输入</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input name="pass2" type="password" placeholder="再次输入新密码"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="text-align: center;padding-top:1em;">
|
||||||
|
<button class="btn lg cc" form-type="submit">{{lang('login.btn_forget')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</form>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view :animation="anidatabg" class="authbg" @tap="close"></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cuser {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cuser>.itm {
|
||||||
|
margin: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1em;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title>.itm {
|
||||||
|
text-decoration: underline;
|
||||||
|
padding: 0 1em;
|
||||||
|
min-width: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title .mid {
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 1.6em;
|
||||||
|
padding: 0;
|
||||||
|
flex: 1;
|
||||||
|
background: linear-gradient(30deg, var(--man5), var(--man7));
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 50002;
|
||||||
|
/*51*/
|
||||||
|
bottom: -2em;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transform: translateY(28em)
|
||||||
|
}
|
||||||
|
|
||||||
|
.authbg {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 50001;
|
||||||
|
/*50*/
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: -0.5em;
|
||||||
|
right: -0.5em;
|
||||||
|
touch-action: none;
|
||||||
|
background: linear-gradient(0deg, var(--bg2), transparent);
|
||||||
|
transform: translateY(100vh);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth .swiper {
|
||||||
|
display: flex;
|
||||||
|
width: 300vw;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth .content {
|
||||||
|
width: 100vw;
|
||||||
|
margin: 0 0.5em;
|
||||||
|
border-radius: 1em 1em 0 0;
|
||||||
|
background: radial-gradient(at center 5em, var(--bg1), var(--bg3));
|
||||||
|
overflow: auto;
|
||||||
|
box-shadow: 2px 2px 20px -10px var(--bg9);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import md5 from '@/util/md5.js';
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
forgetmobile: '',
|
||||||
|
smsfunc: '',
|
||||||
|
user: '',
|
||||||
|
pass: '',
|
||||||
|
xieyi: false,
|
||||||
|
pg: -100, //-100
|
||||||
|
ver: 6,
|
||||||
|
height: '28em',
|
||||||
|
tusers: [],
|
||||||
|
anidataauth: {},
|
||||||
|
anidatabg: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
virtualHost: true
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
async Open(authcb, must) {
|
||||||
|
this.authcb = authcb;
|
||||||
|
if (!must) {
|
||||||
|
var me = this.getme();
|
||||||
|
if (me.id > 0) {
|
||||||
|
authcb({
|
||||||
|
me: me
|
||||||
|
});
|
||||||
|
this.authcb = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//#ifdef MP-WEIXIN
|
||||||
|
var upid = this.toint(this.getstorage('upid'));
|
||||||
|
var res = await uni.login({
|
||||||
|
provider: 'weixin',
|
||||||
|
scopes: 'auth_base',
|
||||||
|
onlyAuthorize: true
|
||||||
|
});
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.wx_autouser',
|
||||||
|
loadhide: true,
|
||||||
|
data: {
|
||||||
|
code: res.code,
|
||||||
|
upid: upid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return;
|
||||||
|
this.tologin(retjson);
|
||||||
|
return;
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
var animation = uni.createAnimation({
|
||||||
|
timingFunction: 'ease'
|
||||||
|
});
|
||||||
|
animation.translateY(0);
|
||||||
|
animation.step({
|
||||||
|
duration: 700
|
||||||
|
});
|
||||||
|
this.anidataauth = animation.export();
|
||||||
|
var animation = uni.createAnimation({
|
||||||
|
timingFunction: 'ease'
|
||||||
|
});
|
||||||
|
animation.translateY(0);
|
||||||
|
animation.step({
|
||||||
|
duration: 400
|
||||||
|
});
|
||||||
|
this.anidatabg = animation.export();
|
||||||
|
this.user = this.getstorage('login_mb');
|
||||||
|
this.smsfunc = 'login.sendsms';
|
||||||
|
},
|
||||||
|
async submitlogin(e) {
|
||||||
|
var app = getApp();
|
||||||
|
var post = e.detail.value;
|
||||||
|
if (post.user.length > 0)
|
||||||
|
this.setstorage('login_mb', post.user);
|
||||||
|
if (post.user == '')
|
||||||
|
return this.toast('请填写手机号');
|
||||||
|
if (post.pass == '')
|
||||||
|
return this.toast('请填写密码');
|
||||||
|
if (!this.xieyi && await this.askmsg('是否阅读并同意协议?', '同意') != 'ok')
|
||||||
|
return;
|
||||||
|
post.auth = (new Date()).getTime();
|
||||||
|
post.appcid = app.globalData._appcid;
|
||||||
|
var epass = md5.md5(post.pass + app.globalData.tokensalt);
|
||||||
|
post.pass = md5.md5(epass + post.auth);
|
||||||
|
//._from = app.globalData._sysinfo;
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.login_mobile', // login.login
|
||||||
|
data: post
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return this.toast(retjson.errmsg);
|
||||||
|
this.setstorage('_dbgs', retjson.dbgs);
|
||||||
|
this.tologin(retjson);
|
||||||
|
},
|
||||||
|
async submitreg(e) {
|
||||||
|
var app = getApp();
|
||||||
|
var post = e.detail.value;
|
||||||
|
if (post.user == '')
|
||||||
|
return this.toast('请填写手机号');
|
||||||
|
if (post.pass == '')
|
||||||
|
return this.toast('请填写密码');
|
||||||
|
if (post.pass != post.pass2)
|
||||||
|
return this.toast('两次密码输入不同');
|
||||||
|
if (!this.xieyi && await this.askmsg('是否阅读并同意协议?', '同意') != 'ok')
|
||||||
|
return;
|
||||||
|
post.upid = app.getstorage('upid');
|
||||||
|
post.appcid = app.globalData._appcid;
|
||||||
|
post.pass = md5.md5(post.pass + app.globalData.tokensalt);
|
||||||
|
post.pass2 = '';
|
||||||
|
//._from = app.globalData._sysinfo;
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.reg_mobile', // login.reg
|
||||||
|
data: post
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return this.toast(retjson.errmsg);
|
||||||
|
this.setstorage('login_mb', post.user);
|
||||||
|
this.tologin(retjson);
|
||||||
|
this.toast('注册成功,已自动登录');
|
||||||
|
},
|
||||||
|
async submitforget(e) {
|
||||||
|
var app = getApp();
|
||||||
|
var post = e.detail.value;
|
||||||
|
if (post.user == '')
|
||||||
|
return this.toast('请填写手机号');
|
||||||
|
if (post.captcha == '')
|
||||||
|
return this.toast('请填写验证码');
|
||||||
|
if (post.pass == '')
|
||||||
|
return this.toast('请填写密码');
|
||||||
|
if (post.pass != post.pass2)
|
||||||
|
return this.toast('两次密码输入不同');
|
||||||
|
post.pass = md5.md5(post.pass + app.globalData.tokensalt);
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.forgetpass', // login.reg
|
||||||
|
data: post
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return this.toast(retjson.errmsg);
|
||||||
|
this.tologin(retjson);
|
||||||
|
this.toast('密码找回成功,已自动登录');
|
||||||
|
},
|
||||||
|
tologin(json) {
|
||||||
|
var app = getApp();
|
||||||
|
var auth = app.setuserstorage(json);
|
||||||
|
if (this.authcb != null)
|
||||||
|
this.authcb(auth);
|
||||||
|
this.authcb = null;
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
gopg(idx) {
|
||||||
|
this.pg = idx * -100;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
if (this.authcb != null)
|
||||||
|
this.authcb({
|
||||||
|
me: {
|
||||||
|
id: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.authcb = null;
|
||||||
|
var animation = uni.createAnimation({
|
||||||
|
timingFunction: 'ease'
|
||||||
|
});
|
||||||
|
animation.translateY(this.height);
|
||||||
|
animation.step({
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
this.anidataauth = animation.export();
|
||||||
|
var animation = uni.createAnimation({
|
||||||
|
timingFunction: 'ease'
|
||||||
|
});
|
||||||
|
animation.translateY('100vh');
|
||||||
|
animation.step({
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
this.anidatabg = animation.export();
|
||||||
|
},
|
||||||
|
async showver(e) {
|
||||||
|
this.ver--;
|
||||||
|
if (this.ver !== 0)
|
||||||
|
return;
|
||||||
|
var app = getApp();
|
||||||
|
if (app.globalData._wxenv == 'release')
|
||||||
|
return;
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.debug_list',
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
this.tusers = retjson.list;
|
||||||
|
},
|
||||||
|
setdbg(idx) {
|
||||||
|
this.xieyi = true;
|
||||||
|
this.user = this.tusers[idx].user;
|
||||||
|
this.pass = this.tusers[idx].pass;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,187 @@
|
||||||
|
<template>
|
||||||
|
暂未完成
|
||||||
|
<view>
|
||||||
|
<view class="vtopmsg" v-if="btmsg" :style="{background:btmsg == '蓝牙阅读器正常'?'':'#cc0000'}">{{btmsg}}</view>
|
||||||
|
|
||||||
|
<view class="_bg" v-if="bshow">
|
||||||
|
<view class="_dialog">
|
||||||
|
<view class="_title">选择目标</view>
|
||||||
|
<view class="_close" @tap="close()"></view>
|
||||||
|
<view class="_content" :style="{maxHeight:maxheight}">
|
||||||
|
<view style="text-align: center;margin:1em 0;">
|
||||||
|
<ciy-qrcode-show :value="epc"></ciy-qrcode-show>
|
||||||
|
</view>
|
||||||
|
<view v-for="(item,index) in sels" :key="index" @tap="sendme(item)" class="selbtn">
|
||||||
|
{{item}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._bg {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog {
|
||||||
|
position: fixed;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
/* #ifdef MP-WEIXIN */
|
||||||
|
top: 1em;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifndef MP-WEIXIN */
|
||||||
|
top: 4em;
|
||||||
|
/* #endif */
|
||||||
|
left: 1em;
|
||||||
|
right: 1em;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._title {
|
||||||
|
line-height: 1.5em;
|
||||||
|
background: #fafafa;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-radius: 0.5em 0.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._content {
|
||||||
|
overflow: scroll;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._close {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5em;
|
||||||
|
top: 0.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PHBhdGggZD0nTTUxLjI4NTk0ODA3IDUyMC4wMTYwMTM1NGMwIDI1Ni40ODg5MDI4MyAyMDcuNTg2OTEzMzUgNDY0LjA3NTgxNjIgNDY0LjA3NTgxNjE3IDQ2NC4wNzU4MTYxN3M0NjQuMDc1ODE2Mi0yMDcuNTg2OTEzMzUgNDY0LjA3NTgxNjItNDY0LjA3NTgxNjE3Uzc3MS44NTA2NjcwOCA1NS45NDAxOTczMyA1MTUuMzYxNzY0MjQgNTUuOTQwMTk3MzNzLTQ2NC4wNzU4MTYyIDIwNy41ODY5MTMzNS00NjQuMDc1ODE2MTcgNDY0LjA3NTgxNjIxeicgZmlsbD0nI2Q4MWUwNic+PC9wYXRoPjxwYXRoIGQ9J001NjAuMjYxMDk5MDIgNTE5LjU1MTkzNzU5bDE3OC4zNzkxNDI5MSAxNzguMzc5MTQxNDZjMTEuODkxOTQyNTcgMTEuODkxOTQyNTcgMTEuODkxOTQyNTcgMzIuODkxMzczNTkgMCA0NC44MTIzMjE5LTExLjg5MTk0MjU3IDExLjg5MTk0MjU3LTMyLjg5MTM3MzU5IDExLjg5MTk0MjU3LTQ0LjgxMjMyMTkxIDBsLTE3OC4zNzkxNDE0NS0xNzguMzc5MTQyOS0xNzguMzc5MTQxNDMgMTc4LjM3OTE0MjljLTExLjg5MTk0MjU3IDExLjg5MTk0MjU3LTMyLjg5MTM3MzU5IDExLjg5MTk0MjU3LTQ0LjgxMjMyMTkxIDAtMTEuODkxOTQyNTctMTEuOTIwOTQ2ODYtMTEuODkxOTQyNTctMzIuOTIwMzc3ODkgMC00NC44MTIzMjE5bDE3OC4zNzkxNDI5LTE3OC4zNzkxNDE0Ni0xNzcuNzk5MDQ2OS0xNzcuODI4MDUyNjRjLTExLjkyMDk0Njg2LTExLjg5MTk0MjU3LTExLjkyMDk0Njg2LTMyLjg5MTM3MzU5IDAtNDQuODEyMzIwNDUgMTEuODkxOTQyNTctMTEuODkxOTQyNTcgMzIuODkxMzczNTktMTEuODkxOTQyNTcgNDQuNzgzMzE2MTYgMGwxNzcuODI4MDUxMTggMTc3Ljc5OTA0Njg5IDE3Ny43OTkwNDY5MS0xNzcuNzk5MDQ2ODljMTIuNTAxMDQyODctMTEuODkxOTQyNTcgMzIuOTIwMzc3ODktMTEuODkxOTQyNTcgNDQuODQxMzI2MjEgMCAxMS44OTE5NDI1NyAxMS44OTE5NDI1NyAxMS44OTE5NDI1NyAzMi44OTEzNzM1OSAwIDQ0LjgxMjMyMDQ1bC0xNzcuODI4MDUyNjcgMTc3Ljc5OTA0ODM2eicgZmlsbD0nI2ZmZmZmZic+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
|
||||||
|
.selbtn {
|
||||||
|
margin: 1em;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #0c59a9;
|
||||||
|
padding: 0.5em;
|
||||||
|
background: #007aff;
|
||||||
|
font-size:1.5em;
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ciyQrcodeShow from '@/components/ciy-qrcode-show/ciy-qrcode-show'
|
||||||
|
var app = getApp();
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
select: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, data() {
|
||||||
|
return {
|
||||||
|
bshow: false
|
||||||
|
, btmsg: ''
|
||||||
|
, sels: []
|
||||||
|
, maxheight: '30em'
|
||||||
|
, epc: ''
|
||||||
|
, };
|
||||||
|
}
|
||||||
|
, destroyed() {
|
||||||
|
console.log('unmounted');
|
||||||
|
}
|
||||||
|
, mounted() {
|
||||||
|
console.log('mounte');
|
||||||
|
|
||||||
|
}
|
||||||
|
, methods: {
|
||||||
|
open() {
|
||||||
|
this.bshow = true;
|
||||||
|
var app = getApp();
|
||||||
|
var height = app.globalData._sysinfo.screenHeight - 80;
|
||||||
|
this.maxheight = height + 'px';
|
||||||
|
}
|
||||||
|
, sendme(select) {
|
||||||
|
console.log('sendme', select);
|
||||||
|
this.$emit('scan', {
|
||||||
|
select: select
|
||||||
|
, value: this.epc
|
||||||
|
});
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
, unmonitor() {
|
||||||
|
var devbt = app.globalData.dev_bt.reader;
|
||||||
|
if (!devbt)
|
||||||
|
return;
|
||||||
|
devbt.onmsg = null;
|
||||||
|
}
|
||||||
|
, monitor() {
|
||||||
|
console.log('monitor');
|
||||||
|
this.btmsg = '';
|
||||||
|
// setTimeout(() => {
|
||||||
|
// var epc = '372120220009998';
|
||||||
|
// this.sels = this.select.split(',');
|
||||||
|
// if (this.sels.length == 1) {
|
||||||
|
// this.$emit('scan', {
|
||||||
|
// select: this.select
|
||||||
|
// , value: epc
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// this.epc = epc;
|
||||||
|
// this.open();
|
||||||
|
// }
|
||||||
|
// }, 500);
|
||||||
|
var devbt = app.globalData.dev_bt.reader;
|
||||||
|
if (!devbt)
|
||||||
|
return;
|
||||||
|
this.btmsg = '蓝牙阅读器未连接!';
|
||||||
|
if (devbt.opened == 10)
|
||||||
|
this.btmsg = '蓝牙阅读器正常';
|
||||||
|
devbt.onmsg = res => {
|
||||||
|
if (res.connected !== undefined) {
|
||||||
|
if (res.connected)
|
||||||
|
this.btmsg = '蓝牙阅读器正常';
|
||||||
|
else
|
||||||
|
this.btmsg = '蓝牙阅读器已断开';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.btmsg = '蓝牙阅读器正常';
|
||||||
|
var epc = res.data;
|
||||||
|
if (!epc)
|
||||||
|
return;
|
||||||
|
if (!this.isfront())
|
||||||
|
return;
|
||||||
|
this.sels = this.select.split(',');
|
||||||
|
if (this.sels.length == 1) {
|
||||||
|
this.$emit('scan', {
|
||||||
|
select: this.select
|
||||||
|
, value: epc
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.epc = epc;
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
, isfront() {
|
||||||
|
var ps = getCurrentPages();
|
||||||
|
var ftroute = ps[ps.length - 1].route || ps[ps.length - 1].__route__;
|
||||||
|
var cproute = this.$parent.__route__ || this.$parent.$parent.route;
|
||||||
|
//console.log(this.select, ftroute,cproute);
|
||||||
|
return ftroute == cproute;
|
||||||
|
}
|
||||||
|
, close() {
|
||||||
|
this.bshow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,562 @@
|
||||||
|
<template>
|
||||||
|
<view style="width: 100%;" :style="{height}">
|
||||||
|
<input type="hidden" :name="name" :value="tostamp(tvalue)" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_date'" :value="todatetime(tvalue,'d')" style="display:none;" />
|
||||||
|
<view class="yearmonth" :style="{padding:selectmonth?'0 1.5em':''}">
|
||||||
|
<view class="itm">
|
||||||
|
<view v-if="selectmonth" @tap="asyear(-10)" class="flex" style="padding-right:2em;">
|
||||||
|
<view class="arrow left ciy-icon-arrow" style="margin-right:-1em;"></view>
|
||||||
|
<view class="arrow left ciy-icon-arrow" style="margin-right:-1em;"></view>
|
||||||
|
</view>
|
||||||
|
<view class="arrow left ciy-icon-arrow" @tap="asyear(-1)"></view>
|
||||||
|
<view class="maintxt" @tap="chgpage(1)">{{year}} {{lang('calendar.year')}}</view>
|
||||||
|
<view class="arrow right ciy-icon-arrow" @tap="asyear(1)"></view>
|
||||||
|
|
||||||
|
<view v-if="selectmonth" @tap="asyear(10)" class="flex" style="padding-left:2em;">
|
||||||
|
<view class="arrow right ciy-icon-arrow" style="margin-left:-1em;"></view>
|
||||||
|
<view class="arrow right ciy-icon-arrow" style="margin-left:-1em;"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="itm" v-if="!selectmonth">
|
||||||
|
<view class="arrow left ciy-icon-arrow" @tap="asmonth(-1)"></view>
|
||||||
|
<view class="maintxt" @tap="chgpage(2)">{{month+1}} {{lang('calendar.month')}}</view>
|
||||||
|
<view class="arrow right ciy-icon-arrow" @tap="asmonth(1)"></view>
|
||||||
|
</view>
|
||||||
|
<view class="itm" v-else>
|
||||||
|
</view>
|
||||||
|
<view v-if="!selectmonth" class="itm today" @tap="today">{{lang('calendar.today')}}</view>
|
||||||
|
<view v-else class="itm today" @tap="today">{{lang('calendar.tomonth')}}</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="cpage == 0" style="padding: 0 0.2em;position: relative;">
|
||||||
|
<view class="week">
|
||||||
|
<view class="itm" v-for="(w,index) in weeks">
|
||||||
|
<slot name="header" :itm="{week:w}">
|
||||||
|
<view class="defweek">
|
||||||
|
<view class="itm" :style="{borderLeftColor:index?bordercolor:''}">
|
||||||
|
{{lang('week.'+w)}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<ciy-gesture @toleft="asmonth(1)" @toright="asmonth(-1)">
|
||||||
|
<view class="days">
|
||||||
|
<view class="itm" v-for="item in dayarr" @tap="clksel(item)">
|
||||||
|
<slot name="data" :itm="{year:year,month:month+1,day:item,date:tvalue,select:cal_valueselect(item),cansel:cal_opminmax(item)}">
|
||||||
|
<view class="defday" :style="cal_valueselect(item)?'color:' + selecttextcolor + ';background:' + selectbg + ';border:1px solid ' + bordercolor:''">
|
||||||
|
<view :style="{opacity:cal_opminmax(item)?1:0.4}">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</ciy-gesture>
|
||||||
|
<view style="position: absolute;bottom:0.8em;right:0.5em;" v-if="clearbtn">
|
||||||
|
<button class="btn def" @tap="clknodate">{{lang('calendar.nodate')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="cpage == 1" class="syear">
|
||||||
|
<view v-if="!selectmonth" class="itm lr" @tap="odyear(-10)">
|
||||||
|
<view class="arrow left ciy-icon-arrow"></view>
|
||||||
|
<view class="arrow left ciy-icon-arrow"></view>
|
||||||
|
</view>
|
||||||
|
<view v-if="!selectmonth" class="itm lr" @tap="odyear(10)">
|
||||||
|
<view class="arrow right ciy-icon-arrow"></view>
|
||||||
|
<view class="arrow right ciy-icon-arrow"></view>
|
||||||
|
</view>
|
||||||
|
<view class="itm" v-for="yy in 12" @tap="clkyear(startyear+yy)" :style="startyear+yy==year?'font-weight:bolder;color:' + selecttextcolor:''">
|
||||||
|
{{startyear+yy}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="cpage == 2" class="smonth">
|
||||||
|
<view class="itm" v-for="mon in 12" @tap="clkmon(mon)" :style="month+1==mon?'font-weight:bolder;color:' + selecttextcolor:''">
|
||||||
|
{{mon}} {{lang('calendar.month')}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'viewchange'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bordercolor: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg6)'
|
||||||
|
},
|
||||||
|
selecttextcolor: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--man5)'
|
||||||
|
},
|
||||||
|
selectbg: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg1)'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '23em'
|
||||||
|
},
|
||||||
|
selectmonth: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
weekmonday: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
mindate: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
maxdate: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
clearbtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
startyear: 0,
|
||||||
|
year: 0,
|
||||||
|
month: 0,
|
||||||
|
cpage: 0 //0日期,1年,2月
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = new Date(this.modelValue * 1000);
|
||||||
|
else if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = new Date(this.value * 1000);
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
} else {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
this._is0 = false;
|
||||||
|
if (!(val instanceof Date)) {
|
||||||
|
if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||||||
|
val = this.str2date(val);
|
||||||
|
} else {
|
||||||
|
val = this.toint(val);
|
||||||
|
if (val == 0) {
|
||||||
|
this._is0 = true;
|
||||||
|
val = new Date();
|
||||||
|
} else {
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (isNaN(val.getTime())) {
|
||||||
|
this._is0 = true;
|
||||||
|
val = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.max && this.max <= val)
|
||||||
|
val = this.max;
|
||||||
|
|
||||||
|
if (this.min && this.min >= val && val.getTime() != 0)
|
||||||
|
val = this.min;
|
||||||
|
if (val.getTime() != 0) {
|
||||||
|
this.year = val.getFullYear();
|
||||||
|
this.month = val.getMonth();
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
max() {
|
||||||
|
var val = this.maxdate;
|
||||||
|
if (val instanceof Date) {
|
||||||
|
if (isNaN(val.getTime()))
|
||||||
|
val = null;
|
||||||
|
} else if (typeof(val) == 'number') {
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
} else if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||||||
|
val = this.str2date(val);
|
||||||
|
} else if (val == 'now') {
|
||||||
|
val = new Date();
|
||||||
|
} else {
|
||||||
|
val = this.toint(val);
|
||||||
|
if (val == 0)
|
||||||
|
val = null;
|
||||||
|
else {
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
min() {
|
||||||
|
var val = this.mindate;
|
||||||
|
if (val instanceof Date) {
|
||||||
|
if (isNaN(val.getTime()))
|
||||||
|
val = null;
|
||||||
|
} else if (typeof(val) == 'number') {
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
} else if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||||||
|
val = new Date(val);
|
||||||
|
} else if (val == 'now') {
|
||||||
|
val = new Date();
|
||||||
|
} else {
|
||||||
|
val = this.toint(val);
|
||||||
|
if (val == 0)
|
||||||
|
val = null;
|
||||||
|
else {
|
||||||
|
val = new Date(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
weeks() {
|
||||||
|
var wks = [];
|
||||||
|
if (!this.weekmonday)
|
||||||
|
wks.push(0);
|
||||||
|
wks.push(1);
|
||||||
|
wks.push(2);
|
||||||
|
wks.push(3);
|
||||||
|
wks.push(4);
|
||||||
|
wks.push(5);
|
||||||
|
wks.push(6);
|
||||||
|
if (this.weekmonday)
|
||||||
|
wks.push(0);
|
||||||
|
return wks;
|
||||||
|
},
|
||||||
|
dayarr() {
|
||||||
|
if (this.year == 0)
|
||||||
|
return;
|
||||||
|
var darr = [];
|
||||||
|
var monthdaycnt = new Date(this.year, this.month + 1, 0).getDate();
|
||||||
|
var day1 = new Date(this.year, this.month, 1);
|
||||||
|
var week = day1.getDay();
|
||||||
|
if (this.weekmonday)
|
||||||
|
week--;
|
||||||
|
for (var i = 0; i < week; i++)
|
||||||
|
darr.push('');
|
||||||
|
for (var i = 1; i <= monthdaycnt; i++)
|
||||||
|
darr.push(i);
|
||||||
|
var nt = 7 - (darr.length % 7);
|
||||||
|
for (var i = darr.length; i < 42; i++)
|
||||||
|
darr.push('');
|
||||||
|
return darr;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.year = this.tvalue.getFullYear();
|
||||||
|
this.month = this.tvalue.getMonth();
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tostamp(this.tvalue),
|
||||||
|
date: this.tvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.selectmonth)
|
||||||
|
this.cpage = 2;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clkyear(y) {
|
||||||
|
if (this.selectmonth) {
|
||||||
|
if (this.year != y)
|
||||||
|
this.month = -1;
|
||||||
|
this.year = y;
|
||||||
|
this.cpage = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.year = y;
|
||||||
|
this.cpage = 0;
|
||||||
|
this.$emit('viewchange', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'year',
|
||||||
|
month: this.month,
|
||||||
|
year: this.year
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clkmon(mon) {
|
||||||
|
this.month = mon - 1;
|
||||||
|
if (this.selectmonth) {
|
||||||
|
this.clksel(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.cpage = 0;
|
||||||
|
this.$emit('viewchange', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'month',
|
||||||
|
month: this.month,
|
||||||
|
year: this.year
|
||||||
|
});
|
||||||
|
},
|
||||||
|
chgpage(p) {
|
||||||
|
var page = this.cpage == p ? (this.selectmonth ? 2 : 0) : p;
|
||||||
|
if (page == 1)
|
||||||
|
this.startyear = parseInt((this.year - 1) / 10) * 10;
|
||||||
|
this.cpage = page;
|
||||||
|
},
|
||||||
|
odyear(od10) {
|
||||||
|
this.startyear += od10;
|
||||||
|
},
|
||||||
|
asyear(od) {
|
||||||
|
this.year += od;
|
||||||
|
if (this.selectmonth) {
|
||||||
|
this.cpage = 2;
|
||||||
|
this.month = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.cpage = 0;
|
||||||
|
this.$emit('viewchange', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'year',
|
||||||
|
month: this.month,
|
||||||
|
year: this.year
|
||||||
|
});
|
||||||
|
},
|
||||||
|
asmonth(od) {
|
||||||
|
this.month += od;
|
||||||
|
if (this.month < 0) {
|
||||||
|
this.year--;
|
||||||
|
this.month = 11;
|
||||||
|
}
|
||||||
|
if (this.month > 11) {
|
||||||
|
this.year++;
|
||||||
|
this.month = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('viewchange', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'month',
|
||||||
|
month: this.month,
|
||||||
|
year: this.year
|
||||||
|
});
|
||||||
|
this.cpage = 0;
|
||||||
|
},
|
||||||
|
today(od) {
|
||||||
|
var val = new Date();
|
||||||
|
if (this.max && this.max <= val)
|
||||||
|
val = this.max;
|
||||||
|
if (this.min && this.min >= val)
|
||||||
|
val = this.min;
|
||||||
|
this.v = val;
|
||||||
|
this.year = val.getFullYear();
|
||||||
|
this.month = val.getMonth();
|
||||||
|
val.setHours(0);
|
||||||
|
val.setMinutes(0); //val.getTimezoneOffset()
|
||||||
|
val.setSeconds(0);
|
||||||
|
//var vt = this.tostamp(val);
|
||||||
|
// this.$emit('update:modelValue', vt);
|
||||||
|
// this.$emit('change', {
|
||||||
|
// name: this.name,
|
||||||
|
// from: 'today',
|
||||||
|
// value: vt,
|
||||||
|
// date: val
|
||||||
|
// });
|
||||||
|
if (this.selectmonth)
|
||||||
|
this.clksel(1);
|
||||||
|
else
|
||||||
|
this.clksel(val.getDate());
|
||||||
|
},
|
||||||
|
cal_opminmax(day) {
|
||||||
|
var date = new Date(this.year, this.month, day);
|
||||||
|
if (this.max) {
|
||||||
|
if (date > this.max)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.min) {
|
||||||
|
if (date < this.min)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
cal_valueselect(day) {
|
||||||
|
if (this._is0)
|
||||||
|
return false;
|
||||||
|
if (this.tvalue.getFullYear() != this.year)
|
||||||
|
return false;
|
||||||
|
if (this.tvalue.getMonth() != this.month)
|
||||||
|
return false;
|
||||||
|
if (this.tvalue.getDate() != day)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
clknodate() {
|
||||||
|
var date = new Date(0);
|
||||||
|
this.$emit('update:modelValue', 0);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'nodate',
|
||||||
|
value: 0,
|
||||||
|
date: date
|
||||||
|
});
|
||||||
|
this.v = date;
|
||||||
|
},
|
||||||
|
clksel(day) {
|
||||||
|
if (!day)
|
||||||
|
return;
|
||||||
|
var date = new Date(this.year, this.month, day);
|
||||||
|
if (this.max) {
|
||||||
|
if (date > this.max)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.min) {
|
||||||
|
if (date < this.min)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var val = this.tostamp(date);
|
||||||
|
this.$emit('update:modelValue', val);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'click',
|
||||||
|
value: val,
|
||||||
|
date: date
|
||||||
|
});
|
||||||
|
this.v = date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.syear {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syear>.itm {
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 25%;
|
||||||
|
line-height: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syear .lr {
|
||||||
|
flex: 0 0 50%;
|
||||||
|
line-height: 2em;
|
||||||
|
margin-bottom: -1em;
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smonth {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
line-height: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smonth>.itm {
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week>.itm {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week .defweek {
|
||||||
|
padding: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week .defweek>.itm {
|
||||||
|
font-weight: bolder;
|
||||||
|
border-left: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.days {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.days .itm {
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 14.28%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.days .defday {
|
||||||
|
height: 3em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yearmonth {
|
||||||
|
display: flex;
|
||||||
|
height: 3em;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yearmonth>.itm {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yearmonth .today {
|
||||||
|
flex: none;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yearmonth .maintxt {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow.left {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow.right {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
<template>
|
||||||
|
<view class="_capmain">
|
||||||
|
<input class="inp flex1" type="number" :name="name" :placeholder="placeholder" :maxlength="codelength" confirm-type="done" cursor-spacing="120" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_id'" :value="dbid" style="display:none;" />
|
||||||
|
<view class="itm">
|
||||||
|
<view v-if="sec>0">{{maxsec-sec}}</view>
|
||||||
|
<button v-else class="btn sm sq" @tap="sendcap">{{btntxt}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
btntxt: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
account: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
func: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
codelength: {
|
||||||
|
type: [String,Number],
|
||||||
|
default: 4
|
||||||
|
},
|
||||||
|
maxsec: {
|
||||||
|
type: [String,Number],
|
||||||
|
default: 60
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sec: 0,
|
||||||
|
dbid: 0,
|
||||||
|
capid: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async sendcap(e) {
|
||||||
|
if(!this.account)
|
||||||
|
return this.toast(this.lang('capcode.noinput'));
|
||||||
|
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: this.func,
|
||||||
|
data:{account:this.account,length:this.codelength}
|
||||||
|
});
|
||||||
|
if(retjson.code != 1)
|
||||||
|
return this.toast(retjson.errmsg);
|
||||||
|
this.dbid = retjson.id;
|
||||||
|
this.sec++;
|
||||||
|
this._sectick = setInterval(() => {
|
||||||
|
this.sec++;
|
||||||
|
if (this.sec < this.toint(this.maxsec))
|
||||||
|
return;
|
||||||
|
this.sec = 0;
|
||||||
|
clearInterval(this._sectick);
|
||||||
|
this.$emit('change', {
|
||||||
|
from: 'tickend',
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
this.$emit('change', {
|
||||||
|
from: 'send',
|
||||||
|
value: retjson
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._capmain {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._capmain>.inp {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._capmain>.itm {
|
||||||
|
min-width: 6em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<view class="pie" :style="{background:tvalue.bg}">
|
||||||
|
<slot>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pie {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: '100|#128dea'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
var colors = ['#4fa6f1', '#57c85b', '#9C27B0', '#FFEB3B', '#2353c3', '#FF5722', '#87b800', '#a66100',
|
||||||
|
'#00796B', '#E91E63', '#a1a1a1'
|
||||||
|
];
|
||||||
|
var dats = [...this.data];
|
||||||
|
if (typeof(this.data) == 'string') {
|
||||||
|
dats = [];
|
||||||
|
var das = this.data.split(',');
|
||||||
|
for (var i in das) {
|
||||||
|
var dc = das[i].split('|');
|
||||||
|
if (dc.length == 1 || dc[1][0] != '#') {
|
||||||
|
dc[1] = colors[i];
|
||||||
|
}
|
||||||
|
dats.push({
|
||||||
|
num: this.tofloat(dc),
|
||||||
|
color: dc[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var total = 0;
|
||||||
|
for (var i in dats) {
|
||||||
|
total += dats[i].num;
|
||||||
|
}
|
||||||
|
var ret = {
|
||||||
|
bg: '#cccccc'
|
||||||
|
};
|
||||||
|
if (total > 0) {
|
||||||
|
ret.bg = 'conic-gradient(from 270deg';
|
||||||
|
var nextdeg = 0;
|
||||||
|
for (var i in dats) {
|
||||||
|
var medeg = dats[i].num * 360 / total
|
||||||
|
ret.bg += ', ' + dats[i].color + ' '+nextdeg+'deg ';
|
||||||
|
nextdeg += medeg;
|
||||||
|
ret.bg += nextdeg+'deg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,301 @@
|
||||||
|
<template>
|
||||||
|
<view style="width:100%;">
|
||||||
|
<input type="hidden" :maxlength="-1" :name="name" :value="tkvs.value" style="display:none;" />
|
||||||
|
<template v-if="hasmore">
|
||||||
|
<checkbox-group :name="name+'_name'" style="display:none;">
|
||||||
|
<checkbox v-for="(item,index) in tkvs.vals" :key="index" :value="item.name+''" checked />
|
||||||
|
</checkbox-group>
|
||||||
|
</template>
|
||||||
|
<template v-if="hasmore && moreno">
|
||||||
|
<checkbox-group :name="name+'_noname'" style="display:none;">
|
||||||
|
<checkbox v-for="(item,index) in tkvs.novals" :key="index" :value="item.name+''" checked />
|
||||||
|
</checkbox-group>
|
||||||
|
</template>
|
||||||
|
<template v-if="moreno">
|
||||||
|
<checkbox-group :name="name+'_id'" style="display:none;">
|
||||||
|
<checkbox v-for="(item,index) in tkvs.vals" :key="index" :value="item.id+''" checked />
|
||||||
|
</checkbox-group>
|
||||||
|
<checkbox-group :name="name+'_no'" style="display:none;">
|
||||||
|
<checkbox v-for="(item,index) in tkvs.novals" :key="index" :value="item.id+''" checked />
|
||||||
|
</checkbox-group>
|
||||||
|
</template>
|
||||||
|
<view v-if="innerrang.length==0" :style="{color:'var(--bg6)',textAlign:left?'left':''}">无选项</view>
|
||||||
|
<radio-group class="_gp" :class="{'_line':line,'_left':left,'_itemright':itemright}">
|
||||||
|
<view @tap="chgitem(item)" class="_item" v-for="(item,index) in innerrang" :key="index">
|
||||||
|
<ciy-checkitem style="pointer-events: none;" sq :disabled="disabled" :tag="(byname?item.name:item.id)+''" :value="tkvs.ids.indexOf((byname?item.name:item.id)+'') > -1"></ciy-checkitem>
|
||||||
|
<view :style="{color:disabled?'var(--txt1)':''}">{{item.name}}</view>
|
||||||
|
</view>
|
||||||
|
</radio-group>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._gp {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._left {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._left ._item {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp ._item {
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
min-width: 7em;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._itemright ._item {
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._line ._item {
|
||||||
|
width: 100%;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
byname: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bin: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
chkuse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
moreno: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
itemright: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
tkvs: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (this.from && newD.value == oldD.value)
|
||||||
|
return;
|
||||||
|
if (this.innerrang.length == 0)
|
||||||
|
return;
|
||||||
|
if (!this.from)
|
||||||
|
this.from = 'init';
|
||||||
|
else if (this.from == 'init')
|
||||||
|
this.from = 'check';
|
||||||
|
|
||||||
|
this.$emit('update:modelValue', newD.value);
|
||||||
|
if (this.from != 'init' || this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: this.from,
|
||||||
|
value: newD.value,
|
||||||
|
idvalue: newD.vals,
|
||||||
|
novalue: newD.novals
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
innerrang() {
|
||||||
|
if (typeof(this.range) == 'string') {
|
||||||
|
const lis = this.range.split(',');
|
||||||
|
var lst = [];
|
||||||
|
for (let i = 0; i < lis.length; i++) {
|
||||||
|
const ls = lis[i].split(':');
|
||||||
|
if (ls.length < 2)
|
||||||
|
continue;
|
||||||
|
lst.push({
|
||||||
|
id: ls[0],
|
||||||
|
name: ls[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
let range = [];
|
||||||
|
for (let i = 0; i < this.range.length; i++) {
|
||||||
|
if (this.chkuse && this.range[i].isuse == 2)
|
||||||
|
continue;
|
||||||
|
range.push(this.range[i]);
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
},
|
||||||
|
tkvs() {
|
||||||
|
var val = ''; //id/name数组
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = this.modelValue + '';
|
||||||
|
else if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = this.value + '';
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
} else if (this.v instanceof Array) {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
if (!(val instanceof Array)) {
|
||||||
|
if (this.bin) {
|
||||||
|
var values = [];
|
||||||
|
var ibin = parseInt(val);
|
||||||
|
for (var tt = 0; tt < 64; tt++) {
|
||||||
|
if (ibin & Math.pow(2, tt))
|
||||||
|
values.push((tt + 1) + '');
|
||||||
|
}
|
||||||
|
val = values;
|
||||||
|
} else {
|
||||||
|
val = val.split(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var kvs = {
|
||||||
|
ids: [],
|
||||||
|
vals: [],
|
||||||
|
novals: []
|
||||||
|
};
|
||||||
|
if (this.byname) {
|
||||||
|
for (var i in this.innerrang) {
|
||||||
|
if (val.indexOf(this.innerrang[i].name + '') > -1) {
|
||||||
|
kvs.ids.push(this.innerrang[i].name + '');
|
||||||
|
kvs.vals.push({
|
||||||
|
...this.innerrang[i]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
kvs.novals.push({
|
||||||
|
...this.innerrang[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i in this.innerrang) {
|
||||||
|
if (val.indexOf(this.innerrang[i].id + '') > -1) {
|
||||||
|
kvs.ids.push(this.innerrang[i].id + '');
|
||||||
|
kvs.vals.push({
|
||||||
|
...this.innerrang[i]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
kvs.novals.push({
|
||||||
|
...this.innerrang[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.bin) {
|
||||||
|
var bval = 0;
|
||||||
|
for (var bi in kvs.ids) {
|
||||||
|
var bc = this.toint(kvs.ids[bi]);
|
||||||
|
if (bc < 1 || bc > 63)
|
||||||
|
continue;
|
||||||
|
bval += Math.pow(2, (bc - 1));
|
||||||
|
}
|
||||||
|
kvs.value = bval;
|
||||||
|
} else {
|
||||||
|
kvs.value = '';
|
||||||
|
if (kvs.ids.length > 0)
|
||||||
|
kvs.value = ',' + kvs.ids.join(',') + ',';
|
||||||
|
}
|
||||||
|
return kvs;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
chgitem(itm) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.v = this.tkvs.ids;
|
||||||
|
if (this.byname) {
|
||||||
|
if (this.tkvs.ids.includes(itm.name + '')) {
|
||||||
|
var idx = this.v.indexOf(itm.name + '');
|
||||||
|
if (idx > -1)
|
||||||
|
delete this.v[idx];
|
||||||
|
} else {
|
||||||
|
this.v.push(itm.name + '');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.tkvs.ids.includes(itm.id + '')) {
|
||||||
|
var idx = this.v.indexOf(itm.id + '');
|
||||||
|
if (idx > -1)
|
||||||
|
delete this.v[idx];
|
||||||
|
} else {
|
||||||
|
this.v.push(itm.id + '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,213 @@
|
||||||
|
<template>
|
||||||
|
<label style="min-width:auto;">
|
||||||
|
<view class="_radio" :class="{_sq:sq,_disabled:disabled}" @tap="clickswitch(!this.tvalue)">
|
||||||
|
<switch :name="name" :checked="tvalue" @change="chg" style="display:none;" />
|
||||||
|
<view class="_bn" :class="{_checked:tvalue}" :animation="anidatabn"></view>
|
||||||
|
</view>
|
||||||
|
<slot></slot>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._radio {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 1.6em;
|
||||||
|
width: 1.6em;
|
||||||
|
margin: 0 0.3em;
|
||||||
|
border-radius: 1em;
|
||||||
|
background: var(--e-switch-bg);
|
||||||
|
box-shadow: var(--e-switch-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
._radio._disabled {
|
||||||
|
background: var(--bg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._radio._sq {
|
||||||
|
border-radius: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._radio._sq ._bn {
|
||||||
|
border-radius: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._radio ._bn {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 1em;
|
||||||
|
background: var(--e-switch-chkbg);
|
||||||
|
opacity: 0.05;
|
||||||
|
transform: scale(0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._radio._disabled ._bn {
|
||||||
|
background: var(--e-switch-chkbgdis);
|
||||||
|
}
|
||||||
|
|
||||||
|
._radio ._bn._checked {
|
||||||
|
box-shadow: var(--e-switch-shadow);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['update:modelValue', 'change'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: -998
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: -998
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ms: { //动画毫秒数
|
||||||
|
type: [String, Number],
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
sq: { //方形
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
anidatabn: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
tvalue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (this.v == 'modelValue' || this.v == 'value')
|
||||||
|
this.ani();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD === -998)
|
||||||
|
return;
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD === -998)
|
||||||
|
return;
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'boolean')
|
||||||
|
return this.modelValue;
|
||||||
|
else if (typeof(this.modelValue) == 'number')
|
||||||
|
return this.modelValue != 0;
|
||||||
|
else if (this.modelValue.toLowerCase() == 'true')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'boolean')
|
||||||
|
return this.value;
|
||||||
|
else if (typeof(this.value) == 'number')
|
||||||
|
return this.value != 0;
|
||||||
|
else if (this.value.toLowerCase() == 'true')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.v;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.tvalue)
|
||||||
|
this.ani();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
ani() {
|
||||||
|
var time = this.toint(this.ms);
|
||||||
|
if (this.tvalue) {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.opacity(0.3);
|
||||||
|
animation.scale(1.1);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.scale(0.6);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
this.anidatabn = animation.export();
|
||||||
|
} else {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.opacity(0.8);
|
||||||
|
animation.scale(0.2);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
animation.scale(0.6);
|
||||||
|
animation.opacity(0.05);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatabn = animation.export();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chg(e) {
|
||||||
|
this.clickswitch(!this.tvalue);
|
||||||
|
},
|
||||||
|
clickswitch(chk) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
if (!chk && !this.sq)
|
||||||
|
return;
|
||||||
|
var time = this.toint(this.ms);
|
||||||
|
if (time < 500)
|
||||||
|
time = 500;
|
||||||
|
if (new Date().getTime() - this._time < time)
|
||||||
|
return;
|
||||||
|
this._time = new Date().getTime();
|
||||||
|
this.v = chk;
|
||||||
|
this.ani();
|
||||||
|
this.$emit('update:modelValue', chk);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
value: chk
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
<template>
|
||||||
|
<view class="_dbg" :style="sty" @tap.stop="showdbglist" v-if="bshow && me.id>0 && dbgs">
|
||||||
|
<view class="_dbgbg">
|
||||||
|
</view>
|
||||||
|
<view class="_dbgtxt">
|
||||||
|
{{me.id}}<br />
|
||||||
|
{{me.name}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._dbg {
|
||||||
|
top: 25em;
|
||||||
|
position: fixed;
|
||||||
|
width: 4em;
|
||||||
|
height: 4em;
|
||||||
|
z-index: 10000000;
|
||||||
|
transition: right 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dbgbg {
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid #9412cc11;
|
||||||
|
background:#ffffff;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dbgtxt {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 0.3em;
|
||||||
|
line-height: 1.3em;
|
||||||
|
text-shadow: 1px 1px #ffffff, -1px -1px #ffffff, -1px 1px #ffffff, 1px -1px #ffffff;
|
||||||
|
top: 0.7em;
|
||||||
|
left: 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sty:{right: '-0.3rem'},
|
||||||
|
dbgs: null,
|
||||||
|
bshow: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {
|
||||||
|
this.me = this.getme();
|
||||||
|
this.dbgs = this.getstorage('_dbgs');
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async chguser(item) {
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.debug_chguser',
|
||||||
|
data: {
|
||||||
|
code: item.data.user
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return this.alert(retjson.errmsg);
|
||||||
|
this.me = this.objdeepmerge(this.me, retjson.me);
|
||||||
|
getApp().setuserstorage(retjson);
|
||||||
|
var page = this.com_getpage();
|
||||||
|
page.me = this.me;
|
||||||
|
if (page.dbgcallback)
|
||||||
|
page.dbgcallback();
|
||||||
|
},
|
||||||
|
async mehide(item) {
|
||||||
|
this.bshow = false;
|
||||||
|
if (item.data > 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.bshow = true;
|
||||||
|
}, item.data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async meusr(item) {
|
||||||
|
var btn = await this.inputmsg({
|
||||||
|
title: '用户ID',
|
||||||
|
ele: 'input'
|
||||||
|
}, [{
|
||||||
|
name: '添加',
|
||||||
|
btn: 'add'
|
||||||
|
}, {
|
||||||
|
name: '删除',
|
||||||
|
btn: 'del',
|
||||||
|
cls: 'dag'
|
||||||
|
}, {
|
||||||
|
name: '取消',
|
||||||
|
btn: 'cancel',
|
||||||
|
cls: 'def'
|
||||||
|
}]);
|
||||||
|
if (btn.btn == 'cancel')
|
||||||
|
return;
|
||||||
|
if (!btn.text)
|
||||||
|
return this.toast('请填写用户ID');
|
||||||
|
var retjson = await this.callfunc({
|
||||||
|
func: 'login.debug_opuser',
|
||||||
|
data: btn
|
||||||
|
});
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return this.alert(retjson.errmsg);
|
||||||
|
if (btn.btn == 'add') {
|
||||||
|
this.dbgs.push(retjson.data);
|
||||||
|
} else {
|
||||||
|
var idx = this.arrayfind(this.dbgs, btn.text, 'user');
|
||||||
|
if (idx > -1)
|
||||||
|
this.dbgs.splice(idx, 1);
|
||||||
|
}
|
||||||
|
this.setstorage('_dbgs', this.dbgs);
|
||||||
|
},
|
||||||
|
async showdbglist() {
|
||||||
|
var items = [];
|
||||||
|
for (var i = 0; i < this.dbgs.length; i++) {
|
||||||
|
items.push({
|
||||||
|
func: 'chguser',
|
||||||
|
name: this.dbgs[i].name,
|
||||||
|
sub: this.dbgs[i].user,
|
||||||
|
data: this.dbgs[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
items.push({
|
||||||
|
br: true
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
func: 'mehide',
|
||||||
|
name: '消失5秒',
|
||||||
|
style: 'color:var(--warn6)',
|
||||||
|
data: 5000
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
func: 'mehide',
|
||||||
|
name: '永久隐藏',
|
||||||
|
style: 'color:var(--dag6)',
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
func: 'meusr',
|
||||||
|
name: '增删用户',
|
||||||
|
style: 'color:var(--man6)',
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
this.sty.right = '-3.3rem';
|
||||||
|
this.popmenu({
|
||||||
|
rowcount: 3,
|
||||||
|
items,
|
||||||
|
closecb: () => {
|
||||||
|
this.sty.right = '-0.3rem';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<template>
|
||||||
|
<view class="_bg" v-if="bshow">
|
||||||
|
<view class="_dialog" :style="{top:top}">
|
||||||
|
<view class="_title">{{title}}</view>
|
||||||
|
<view class="_close" @tap="Close(true)"></view>
|
||||||
|
<view class="_content" :style="{maxHeight:maxheight,height:height}">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._bg {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog {
|
||||||
|
position: fixed;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
left: 1em;
|
||||||
|
right: 1em;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._title {
|
||||||
|
line-height: 1.5em;
|
||||||
|
background: #fafafa;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-radius: 0.5em 0.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._content {
|
||||||
|
overflow: scroll;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._close {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5em;
|
||||||
|
top: 0.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PHBhdGggZD0nTTUxLjI4NTk0ODA3IDUyMC4wMTYwMTM1NGMwIDI1Ni40ODg5MDI4MyAyMDcuNTg2OTEzMzUgNDY0LjA3NTgxNjIgNDY0LjA3NTgxNjE3IDQ2NC4wNzU4MTYxN3M0NjQuMDc1ODE2Mi0yMDcuNTg2OTEzMzUgNDY0LjA3NTgxNjItNDY0LjA3NTgxNjE3Uzc3MS44NTA2NjcwOCA1NS45NDAxOTczMyA1MTUuMzYxNzY0MjQgNTUuOTQwMTk3MzNzLTQ2NC4wNzU4MTYyIDIwNy41ODY5MTMzNS00NjQuMDc1ODE2MTcgNDY0LjA3NTgxNjIxeicgZmlsbD0nI2Q4MWUwNic+PC9wYXRoPjxwYXRoIGQ9J001NjAuMjYxMDk5MDIgNTE5LjU1MTkzNzU5bDE3OC4zNzkxNDI5MSAxNzguMzc5MTQxNDZjMTEuODkxOTQyNTcgMTEuODkxOTQyNTcgMTEuODkxOTQyNTcgMzIuODkxMzczNTkgMCA0NC44MTIzMjE5LTExLjg5MTk0MjU3IDExLjg5MTk0MjU3LTMyLjg5MTM3MzU5IDExLjg5MTk0MjU3LTQ0LjgxMjMyMTkxIDBsLTE3OC4zNzkxNDE0NS0xNzguMzc5MTQyOS0xNzguMzc5MTQxNDMgMTc4LjM3OTE0MjljLTExLjg5MTk0MjU3IDExLjg5MTk0MjU3LTMyLjg5MTM3MzU5IDExLjg5MTk0MjU3LTQ0LjgxMjMyMTkxIDAtMTEuODkxOTQyNTctMTEuOTIwOTQ2ODYtMTEuODkxOTQyNTctMzIuOTIwMzc3ODkgMC00NC44MTIzMjE5bDE3OC4zNzkxNDI5LTE3OC4zNzkxNDE0Ni0xNzcuNzk5MDQ2OS0xNzcuODI4MDUyNjRjLTExLjkyMDk0Njg2LTExLjg5MTk0MjU3LTExLjkyMDk0Njg2LTMyLjg5MTM3MzU5IDAtNDQuODEyMzIwNDUgMTEuODkxOTQyNTctMTEuODkxOTQyNTcgMzIuODkxMzczNTktMTEuODkxOTQyNTcgNDQuNzgzMzE2MTYgMGwxNzcuODI4MDUxMTggMTc3Ljc5OTA0Njg5IDE3Ny43OTkwNDY5MS0xNzcuNzk5MDQ2ODljMTIuNTAxMDQyODctMTEuODkxOTQyNTcgMzIuOTIwMzc3ODktMTEuODkxOTQyNTcgNDQuODQxMzI2MjEgMCAxMS44OTE5NDI1NyAxMS44OTE5NDI1NyAxMS44OTE5NDI1NyAzMi44OTEzNzM1OSAwIDQ0LjgxMjMyMDQ1bC0xNzcuODI4MDUyNjcgMTc3Ljc5OTA0ODM2eicgZmlsbD0nI2ZmZmZmZic+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bshow: false,
|
||||||
|
maxheight: 'auto',
|
||||||
|
top: 0,
|
||||||
|
height: 'auto',
|
||||||
|
title: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async Open(res) {
|
||||||
|
var app = getApp();
|
||||||
|
res = res || {};
|
||||||
|
if (typeof(res) == 'string')
|
||||||
|
res = {
|
||||||
|
title: res
|
||||||
|
};
|
||||||
|
this.title = res.title || '操作';
|
||||||
|
this.cb = res.cb;
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
this.top = (headerheight + 60) + 'px';
|
||||||
|
if (res.height) {
|
||||||
|
this.height = res.height;
|
||||||
|
} else {
|
||||||
|
var height = app.globalData._sysinfo.windowHeight - 100 - this.header_statusbar_height - this.header_title_height;
|
||||||
|
this.maxheight = height + 'px';
|
||||||
|
}
|
||||||
|
this.bshow = true;
|
||||||
|
},
|
||||||
|
Close(mustcb) {
|
||||||
|
this.bshow = false;
|
||||||
|
if (mustcb && typeof(this.cb) == 'function')
|
||||||
|
this.cb('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
<template>
|
||||||
|
<view @touchstart="touchstart" @touchend="touchend" @touchmove="touchmove">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['start', 'toleft', 'toright', 'todown', 'toup', 'end'],
|
||||||
|
props: {
|
||||||
|
pxlen: { //滑动距离超过pxlen px生效
|
||||||
|
type: Number,
|
||||||
|
default: 40
|
||||||
|
},
|
||||||
|
move: { //产生移动过程事件
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
touchstart(e) {
|
||||||
|
this.$emit('start', e.touches[0]);
|
||||||
|
this.startx = e.touches[0].pageX;
|
||||||
|
this.starty = e.touches[0].pageY;
|
||||||
|
this.movex = e.touches[0].pageX;
|
||||||
|
this.movey = e.touches[0].pageY;
|
||||||
|
this.st = true;
|
||||||
|
},
|
||||||
|
touchend(e) {
|
||||||
|
this.st = false;
|
||||||
|
var x = this.movex - this.startx;
|
||||||
|
var y = this.movey - this.starty;
|
||||||
|
var needend = true;
|
||||||
|
if (Math.abs(x) > this.pxlen) {
|
||||||
|
if (x < 0)
|
||||||
|
this.$emit('toleft', {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
});
|
||||||
|
else
|
||||||
|
this.$emit('toright', {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
});
|
||||||
|
needend = false;
|
||||||
|
}
|
||||||
|
if (Math.abs(y) > this.pxlen) {
|
||||||
|
if (y > 0)
|
||||||
|
this.$emit('todown', {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
});
|
||||||
|
else
|
||||||
|
this.$emit('toup', {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
});
|
||||||
|
needend = false;
|
||||||
|
}
|
||||||
|
if (needend) {
|
||||||
|
this.$emit('end', {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
touchmove(e) {
|
||||||
|
if (!this.st)
|
||||||
|
return;
|
||||||
|
this.movex = e.touches[0].pageX;
|
||||||
|
this.movey = e.touches[0].pageY;
|
||||||
|
if (!this.move)
|
||||||
|
return;
|
||||||
|
this.$emit('tomove', {
|
||||||
|
x: this.movex - this.startx,
|
||||||
|
y: this.movey - this.starty
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,499 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<input type="hidden" :name="name" :value="pic" style="display:none;" />
|
||||||
|
<view v-if="doing" class="_vtop" :style="{top:(header_statusbar_height+header_title_height)+'px'}" style="left:0;right:0;bottom:0;background:#ffffff;z-index: 998;">
|
||||||
|
<view style="position: absolute;top:5px;left:5px;bottom:5px;width:4em;">
|
||||||
|
<button @tap="btn_close" class="lbtn" style="top:2em;">{{lang('handsign.close')}}</button>
|
||||||
|
<button @tap="btn_clear" class="lbtn" style="top:8em;">{{lang('handsign.rewrite')}}</button>
|
||||||
|
<button @tap="btn_done" type="primary" class="lbtn" style="bottom:2em;">{{lang('handsign.done')}}</button>
|
||||||
|
</view>
|
||||||
|
<view style="position:absolute;top:5px;left:4.5em;right:5px;bottom:5px;border: 4rpx dashed #e9e9e9;">
|
||||||
|
<canvas class="handsign" canvas-id="handsign" style="background:#ffffff;width:100%;height: 100%;" disable-scroll="true" @touchstart="uploadScaleStart" @touchmove="uploadScaleMove" @touchend="uploadScaleEnd">
|
||||||
|
</canvas>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<image :src="file_stor(pic)" mode="aspectFill" style="width:70vw;height:35vw;border: 1px solid #cccccc;" @tap="showsign"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
uploadurl: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
imgact: {
|
||||||
|
type: String,
|
||||||
|
default: 'cp|300|70'
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#0555ad'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
doing: false,
|
||||||
|
canvasWidth: 0,
|
||||||
|
canvasHeight: 0,
|
||||||
|
lineSize: 1.5 // 笔记倍数
|
||||||
|
,
|
||||||
|
lineMin: 1 // 最小笔画半径
|
||||||
|
,
|
||||||
|
lineMax: 4 // 最大笔画半径
|
||||||
|
,
|
||||||
|
pressure: 1 // 默认压力
|
||||||
|
,
|
||||||
|
smoothness: 60 //顺滑度,用60的距离来计算速度
|
||||||
|
,
|
||||||
|
currentPoint: {},
|
||||||
|
currentLine: [] // 当前线条
|
||||||
|
,
|
||||||
|
firstTouch: true // 第一次触发
|
||||||
|
,
|
||||||
|
radius: 1 //画圆的半径
|
||||||
|
,
|
||||||
|
cutArea: {
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0
|
||||||
|
} //裁剪区域
|
||||||
|
,
|
||||||
|
bethelPoint: [] //保存所有线条 生成的贝塞尔点;
|
||||||
|
,
|
||||||
|
lastPoint: 0,
|
||||||
|
chirography: [] //笔迹
|
||||||
|
,
|
||||||
|
currentChirography: {} //当前笔迹
|
||||||
|
,
|
||||||
|
linePrack: [] //划线轨迹 , 生成线条的实际点
|
||||||
|
,
|
||||||
|
pic: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newD, oldD) {
|
||||||
|
this.showvalue();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.showvalue('created');
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showvalue(frombase) {
|
||||||
|
var val = this.value || '';
|
||||||
|
this.pic = val;
|
||||||
|
if (frombase) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: frombase,
|
||||||
|
value: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uploadScaleStart: function(e) {
|
||||||
|
if (e.type != 'touchstart') return false;
|
||||||
|
this.ctx.setFillStyle(this.color); // 初始线条设置颜色
|
||||||
|
//this.ctx.setGlobalAlpha(this.transparent); // 设置半透明
|
||||||
|
var currentPoint = {
|
||||||
|
x: e.touches[0].x,
|
||||||
|
y: e.touches[0].y
|
||||||
|
}
|
||||||
|
var currentLine = this.currentLine;
|
||||||
|
currentLine.unshift({
|
||||||
|
time: new Date().getTime(),
|
||||||
|
dis: 0,
|
||||||
|
x: currentPoint.x,
|
||||||
|
y: currentPoint.y
|
||||||
|
})
|
||||||
|
this.currentPoint = currentPoint;
|
||||||
|
if (this.firstTouch) {
|
||||||
|
this.cutArea = {
|
||||||
|
top: currentPoint.y,
|
||||||
|
right: currentPoint.x,
|
||||||
|
bottom: currentPoint.y,
|
||||||
|
left: currentPoint.x
|
||||||
|
};
|
||||||
|
this.firstTouch = false;
|
||||||
|
}
|
||||||
|
this.pointToLine(currentLine);
|
||||||
|
}
|
||||||
|
// 笔迹移动
|
||||||
|
,
|
||||||
|
uploadScaleMove: function(e) {
|
||||||
|
if (e.type != 'touchmove')
|
||||||
|
return false;
|
||||||
|
if (e.cancelable) {
|
||||||
|
// 判断默认行为是否已经被禁用
|
||||||
|
if (!e.defaultPrevented) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var point = {
|
||||||
|
x: e.touches[0].x,
|
||||||
|
y: e.touches[0].y
|
||||||
|
}
|
||||||
|
|
||||||
|
//测试裁剪
|
||||||
|
if (point.y < this.cutArea.top) {
|
||||||
|
this.cutArea.top = point.y;
|
||||||
|
}
|
||||||
|
if (point.y < 0) this.cutArea.top = 0;
|
||||||
|
|
||||||
|
if (point.x > this.cutArea.right) {
|
||||||
|
this.cutArea.right = point.x;
|
||||||
|
}
|
||||||
|
if (this.canvasWidth - point.x <= 0) {
|
||||||
|
this.cutArea.right = this.canvasWidth;
|
||||||
|
}
|
||||||
|
if (point.y > this.cutArea.bottom) {
|
||||||
|
this.cutArea.bottom = point.y;
|
||||||
|
}
|
||||||
|
if (this.canvasHeight - point.y <= 0) {
|
||||||
|
this.cutArea.bottom = this.canvasHeight;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (point.x < this.cutArea.left) {
|
||||||
|
this.cutArea.left = point.x;
|
||||||
|
}
|
||||||
|
if (point.x < 0) this.cutArea.left = 0;
|
||||||
|
|
||||||
|
this.lastPoint = this.currentPoint;
|
||||||
|
this.currentPoint = point;
|
||||||
|
var currentLine = this.currentLine;
|
||||||
|
currentLine.unshift({
|
||||||
|
time: new Date().getTime(),
|
||||||
|
dis: this.distance(this.currentPoint, this.lastPoint),
|
||||||
|
x: point.x,
|
||||||
|
y: point.y
|
||||||
|
});
|
||||||
|
this.pointToLine(currentLine);
|
||||||
|
}
|
||||||
|
// 笔迹结束
|
||||||
|
,
|
||||||
|
uploadScaleEnd(e) {
|
||||||
|
if (e.type != 'touchend') return 0;
|
||||||
|
if (e.changedTouches.length == 0)
|
||||||
|
return;
|
||||||
|
var point = {
|
||||||
|
x: e.changedTouches[0].x,
|
||||||
|
y: e.changedTouches[0].y
|
||||||
|
}
|
||||||
|
this.lastPoint = this.currentPoint;
|
||||||
|
this.currentPoint = point;
|
||||||
|
var currentLine = this.currentLine
|
||||||
|
currentLine.unshift({
|
||||||
|
time: new Date().getTime(),
|
||||||
|
dis: this.distance(this.currentPoint, this.lastPoint),
|
||||||
|
x: point.x,
|
||||||
|
y: point.y
|
||||||
|
})
|
||||||
|
if (currentLine.length > 2) {
|
||||||
|
var info = (currentLine[0].time - currentLine[currentLine.length - 1].time) / currentLine.length;
|
||||||
|
}
|
||||||
|
//一笔结束,保存笔迹的坐标点,清空,当前笔迹
|
||||||
|
//增加判断是否在手写区域;
|
||||||
|
this.pointToLine(currentLine);
|
||||||
|
var currentChirography = {
|
||||||
|
lineSize: this.lineSize,
|
||||||
|
lineColor: this.color
|
||||||
|
};
|
||||||
|
this.chirography.unshift(currentChirography);
|
||||||
|
var linePrack = this.linePrack;
|
||||||
|
linePrack.unshift(this.currentLine);
|
||||||
|
this.linePrack = linePrack;
|
||||||
|
this.currentLine = [];
|
||||||
|
}
|
||||||
|
//画两点之间的线条;参数为:line,会绘制最近的开始的两个点;
|
||||||
|
,
|
||||||
|
pointToLine: function(line) {
|
||||||
|
this.calcBethelLine(line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//计算插值的方式;
|
||||||
|
,
|
||||||
|
calcBethelLine: function(line) {
|
||||||
|
if (line.length <= 1) {
|
||||||
|
line[0].r = this.radius;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var x0, x1, x2, y0, y1, y2, r0, r1, r2, len, lastRadius, dis = 0,
|
||||||
|
time = 0,
|
||||||
|
curveValue = 0.5;
|
||||||
|
if (line.length <= 2) {
|
||||||
|
x0 = line[1].x
|
||||||
|
y0 = line[1].y
|
||||||
|
x2 = line[1].x + (line[0].x - line[1].x) * curveValue;
|
||||||
|
y2 = line[1].y + (line[0].y - line[1].y) * curveValue;
|
||||||
|
//x2 = line[1].x;
|
||||||
|
//y2 = line[1].y;
|
||||||
|
x1 = x0 + (x2 - x0) * curveValue;
|
||||||
|
y1 = y0 + (y2 - y0) * curveValue;;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
x0 = line[2].x + (line[1].x - line[2].x) * curveValue;
|
||||||
|
y0 = line[2].y + (line[1].y - line[2].y) * curveValue;
|
||||||
|
x1 = line[1].x;
|
||||||
|
y1 = line[1].y;
|
||||||
|
x2 = x1 + (line[0].x - x1) * curveValue;
|
||||||
|
y2 = y1 + (line[0].y - y1) * curveValue;
|
||||||
|
}
|
||||||
|
//从计算公式看,三个点分别是(x0,y0),(x1,y1),(x2,y2) ;(x1,y1)这个是控制点,控制点不会落在曲线上;实际上,这个点还会手写获取的实际点,却落在曲线上
|
||||||
|
len = this.distance({
|
||||||
|
x: x2,
|
||||||
|
y: y2
|
||||||
|
}, {
|
||||||
|
x: x0,
|
||||||
|
y: y0
|
||||||
|
});
|
||||||
|
lastRadius = this.radius;
|
||||||
|
for (var n = 0; n < line.length - 1; n++) {
|
||||||
|
dis += line[n].dis;
|
||||||
|
time += line[n].time - line[n + 1].time;
|
||||||
|
if (dis > this.smoothness) break;
|
||||||
|
}
|
||||||
|
this.radius = Math.min(time / len * this.pressure + this.lineMin, this.lineMax) * this.lineSize;
|
||||||
|
line[0].r = this.radius;
|
||||||
|
//计算笔迹半径;
|
||||||
|
if (line.length <= 2) {
|
||||||
|
r0 = (lastRadius + this.radius) / 2;
|
||||||
|
r1 = r0;
|
||||||
|
r2 = r1;
|
||||||
|
//return;
|
||||||
|
} else {
|
||||||
|
r0 = (line[2].r + line[1].r) / 2;
|
||||||
|
r1 = line[1].r;
|
||||||
|
r2 = (line[1].r + line[0].r) / 2;
|
||||||
|
}
|
||||||
|
var n = 5;
|
||||||
|
var point = [];
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
var t = i / (n - 1);
|
||||||
|
var x = (1 - t) * (1 - t) * x0 + 2 * t * (1 - t) * x1 + t * t * x2;
|
||||||
|
var y = (1 - t) * (1 - t) * y0 + 2 * t * (1 - t) * y1 + t * t * y2;
|
||||||
|
var r = lastRadius + (this.radius - lastRadius) / n * i;
|
||||||
|
point.push({
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
r: r
|
||||||
|
});
|
||||||
|
if (point.length == 3) {
|
||||||
|
var a = this.ctaCalc(point[0].x, point[0].y, point[0].r, point[1].x, point[1].y, point[1].r, point[2].x, point[2].y, point[2].r);
|
||||||
|
a[0].color = this.color;
|
||||||
|
this.bethelDraw(a, 1);
|
||||||
|
point = [{
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
r: r
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.currentLine = line;
|
||||||
|
}
|
||||||
|
//求两点之间距离
|
||||||
|
,
|
||||||
|
distance: function(a, b) {
|
||||||
|
var x = b.x - a.x;
|
||||||
|
var y = b.y - a.y;
|
||||||
|
return Math.sqrt(x * x + y * y);
|
||||||
|
},
|
||||||
|
ctaCalc: function(x0, y0, r0, x1, y1, r1, x2, y2, r2) {
|
||||||
|
var a = [],
|
||||||
|
vx01, vy01, norm, n_x0, n_y0, vx21, vy21, n_x2, n_y2;
|
||||||
|
vx01 = x1 - x0;
|
||||||
|
vy01 = y1 - y0;
|
||||||
|
norm = Math.sqrt(vx01 * vx01 + vy01 * vy01 + 0.0001) * 2;
|
||||||
|
vx01 = vx01 / norm * r0;
|
||||||
|
vy01 = vy01 / norm * r0;
|
||||||
|
n_x0 = vy01;
|
||||||
|
n_y0 = -vx01;
|
||||||
|
vx21 = x1 - x2;
|
||||||
|
vy21 = y1 - y2;
|
||||||
|
norm = Math.sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001) * 2;
|
||||||
|
vx21 = vx21 / norm * r2;
|
||||||
|
vy21 = vy21 / norm * r2;
|
||||||
|
n_x2 = -vy21;
|
||||||
|
n_y2 = vx21;
|
||||||
|
a.push({
|
||||||
|
mx: x0 + n_x0,
|
||||||
|
my: y0 + n_y0,
|
||||||
|
color: "#1A1A1A"
|
||||||
|
});
|
||||||
|
a.push({
|
||||||
|
c1x: x1 + n_x0,
|
||||||
|
c1y: y1 + n_y0,
|
||||||
|
c2x: x1 + n_x2,
|
||||||
|
c2y: y1 + n_y2,
|
||||||
|
ex: x2 + n_x2,
|
||||||
|
ey: y2 + n_y2
|
||||||
|
});
|
||||||
|
a.push({
|
||||||
|
c1x: x2 + n_x2 - vx21,
|
||||||
|
c1y: y2 + n_y2 - vy21,
|
||||||
|
c2x: x2 - n_x2 - vx21,
|
||||||
|
c2y: y2 - n_y2 - vy21,
|
||||||
|
ex: x2 - n_x2,
|
||||||
|
ey: y2 - n_y2
|
||||||
|
});
|
||||||
|
a.push({
|
||||||
|
c1x: x1 - n_x2,
|
||||||
|
c1y: y1 - n_y2,
|
||||||
|
c2x: x1 - n_x0,
|
||||||
|
c2y: y1 - n_y0,
|
||||||
|
ex: x0 - n_x0,
|
||||||
|
ey: y0 - n_y0
|
||||||
|
});
|
||||||
|
a.push({
|
||||||
|
c1x: x0 - n_x0 - vx01,
|
||||||
|
c1y: y0 - n_y0 - vy01,
|
||||||
|
c2x: x0 + n_x0 - vx01,
|
||||||
|
c2y: y0 + n_y0 - vy01,
|
||||||
|
ex: x0 + n_x0,
|
||||||
|
ey: y0 + n_y0
|
||||||
|
});
|
||||||
|
a[0].mx = a[0].mx.toFixed(1);
|
||||||
|
a[0].mx = parseFloat(a[0].mx);
|
||||||
|
a[0].my = a[0].my.toFixed(1);
|
||||||
|
a[0].my = parseFloat(a[0].my);
|
||||||
|
for (var i = 1; i < a.length; i++) {
|
||||||
|
a[i].c1x = a[i].c1x.toFixed(1);
|
||||||
|
a[i].c1x = parseFloat(a[i].c1x);
|
||||||
|
a[i].c1y = a[i].c1y.toFixed(1);
|
||||||
|
a[i].c1y = parseFloat(a[i].c1y);
|
||||||
|
a[i].c2x = a[i].c2x.toFixed(1);
|
||||||
|
a[i].c2x = parseFloat(a[i].c2x);
|
||||||
|
a[i].c2y = a[i].c2y.toFixed(1);
|
||||||
|
a[i].c2y = parseFloat(a[i].c2y);
|
||||||
|
a[i].ex = a[i].ex.toFixed(1);
|
||||||
|
a[i].ex = parseFloat(a[i].ex);
|
||||||
|
a[i].ey = a[i].ey.toFixed(1);
|
||||||
|
a[i].ey = parseFloat(a[i].ey);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
bethelDraw: function(point, is_fill, color) {
|
||||||
|
var ctx = this.ctx;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(point[0].mx, point[0].my);
|
||||||
|
if (undefined != color) {
|
||||||
|
ctx.setFillStyle(color);
|
||||||
|
ctx.setStrokeStyle(color);
|
||||||
|
} else {
|
||||||
|
ctx.setFillStyle(point[0].color);
|
||||||
|
ctx.setStrokeStyle(point[0].color);
|
||||||
|
}
|
||||||
|
for (var i = 1; i < point.length; i++) {
|
||||||
|
ctx.bezierCurveTo(point[i].c1x, point[i].c1y, point[i].c2x, point[i].c2y, point[i].ex, point[i].ey);
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
if (undefined != is_fill) {
|
||||||
|
ctx.fill(); //填充图形 ( 后绘制的图形会覆盖前面的图形, 绘制时注意先后顺序 )
|
||||||
|
}
|
||||||
|
ctx.draw(true)
|
||||||
|
},
|
||||||
|
setCanvasBg: function(color) {
|
||||||
|
this.ctx.rect(0, 0, this.canvasWidth, this.canvasHeight - 4);
|
||||||
|
this.ctx.setFillStyle(color);
|
||||||
|
this.ctx.fill();
|
||||||
|
this.ctx.draw();
|
||||||
|
},
|
||||||
|
showsign: function() {
|
||||||
|
this.doing = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.ctx = uni.createCanvasContext('handsign', this);
|
||||||
|
var query = uni.createSelectorQuery();
|
||||||
|
var thos = this;
|
||||||
|
query.in(this).select('.handsign').boundingClientRect(function(rect) {
|
||||||
|
thos.canvasWidth = rect.width;
|
||||||
|
thos.canvasHeight = rect.height;
|
||||||
|
|
||||||
|
thos.setCanvasBg('#ffffff');
|
||||||
|
}).exec();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
btn_close: function() {
|
||||||
|
this.doing = false;
|
||||||
|
},
|
||||||
|
btn_clear: function() {
|
||||||
|
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||||||
|
this.ctx.draw();
|
||||||
|
this.setCanvasBg("#ffffff");
|
||||||
|
this.linePrack = [];
|
||||||
|
},
|
||||||
|
btn_done: function() {
|
||||||
|
var thos = this;
|
||||||
|
if (this.linePrack.length == 0)
|
||||||
|
return this.toast('请签名后再点击完成');
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: 'handsign',
|
||||||
|
fileType: 'png',
|
||||||
|
quality: 1,
|
||||||
|
success: res => {
|
||||||
|
var updata = {};
|
||||||
|
updata._uid = this.getstorage("uid"); //UserID
|
||||||
|
updata._sid = this.getstorage("sid"); //SID
|
||||||
|
updata.imgact = thos.imgact;
|
||||||
|
updata.imgrotate = '90';
|
||||||
|
|
||||||
|
uni.uploadFile({
|
||||||
|
url: this.uploadurl,
|
||||||
|
filePath: res.tempFilePath,
|
||||||
|
name: 'file',
|
||||||
|
formData: updata,
|
||||||
|
header: {
|
||||||
|
'ciyauth': this.getstorage("_auth"),
|
||||||
|
'ciyorg': this.getstorage("_org")
|
||||||
|
},
|
||||||
|
success: res => {
|
||||||
|
var jsonup = this.json_parse(res.data);
|
||||||
|
if (jsonup === null)
|
||||||
|
jsonup = {
|
||||||
|
result: false,
|
||||||
|
msg: 'JSON Parse ERROR:' + res.data.substr(0, 30)
|
||||||
|
};
|
||||||
|
if (jsonup.code != 1) {
|
||||||
|
return this.alert('上传失败:' + jsonup.errmsg);
|
||||||
|
}
|
||||||
|
thos.pic = jsonup.url;
|
||||||
|
thos.doing = false;
|
||||||
|
thos.$emit('input', thos.pic);
|
||||||
|
thos.$emit('change', {
|
||||||
|
name: thos.name,
|
||||||
|
from: 'sign',
|
||||||
|
value: thos.pic
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._vtop{
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.lbtn {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
<template>
|
||||||
|
<view class="_header_all" v-if="headershow">
|
||||||
|
<template v-if="mode=='title'">
|
||||||
|
<view class="_header_title bg2" :style="{height:header_statusbar_height+'px'}"></view>
|
||||||
|
<view class="_header_title bg2" :style="{height:header_title_height+'px',lineHeight:header_title_height+'px'}">
|
||||||
|
<view class="_header_btn">
|
||||||
|
<view v-if="hasbackbtn" @tap="goback" class="_header_title_btn">
|
||||||
|
<view class="itm _back"></view>
|
||||||
|
</view>
|
||||||
|
<view v-else @tap="gourl" :data-url="mainpage" class="_header_title_btn">
|
||||||
|
<view class="itm _home"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot>
|
||||||
|
<view class="_header_title_text" :style="{margin:'0 '+header_title_margin+'px'}">{{title}}</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<template v-if="mode=='tran'">
|
||||||
|
<view class="_header_title" :style="{height:header_statusbar_height+'px'}"></view>
|
||||||
|
<view class="_header_title" :style="{height:header_title_height+'px',lineHeight:header_title_height+'px'}">
|
||||||
|
<view class="_header_btn">
|
||||||
|
<view v-if="hasbackbtn" @tap="goback" class="_header_tran_btn">
|
||||||
|
<view class="itm _back"></view>
|
||||||
|
</view>
|
||||||
|
<view v-else @tap="gourl" :data-url="mainpage" class="_header_tran_btn">
|
||||||
|
<view class="itm _home"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<template v-if="mode=='scroll'">
|
||||||
|
<view :style="{opacity:opac}" style="background:linear-gradient(21deg, var(--e-headerbg1), var(--e-headerbg2));">
|
||||||
|
<view class="_header_title" :style="{height:header_statusbar_height+'px'}"></view>
|
||||||
|
<view class="_header_title" :style="{height:header_title_height+'px',lineHeight:header_title_height+'px'}">
|
||||||
|
<view class="_header_btn">
|
||||||
|
<view v-if="hasbackbtn" @tap="goback" class="_header_title_btn">
|
||||||
|
<view class="itm _back"></view>
|
||||||
|
</view>
|
||||||
|
<view v-else @tap="gourl" :data-url="mainpage" class="_header_title_btn">
|
||||||
|
<view class="itm _home"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot>
|
||||||
|
<view class="_header_title_text" :style="{margin:'0 '+header_title_margin+'px'}">{{title}}</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<view :style="{height:seatheight+'px'}" v-if="headershow"></view>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
._header_all {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 990;
|
||||||
|
color: var(--txt9);
|
||||||
|
}
|
||||||
|
|
||||||
|
._header_title {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
._header_btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._header_title_text {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._header_title_btn {
|
||||||
|
padding: 0.3em;
|
||||||
|
margin-left: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._header_title_btn>.itm {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
._header_tran_btn {
|
||||||
|
padding: 0.3em;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #dddddd88;
|
||||||
|
}
|
||||||
|
|
||||||
|
._header_tran_btn>.itm {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._back {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iIzc3Nzc3NyIgZD0iTTc0NC4zMzcyNTYzIDEwMTcuMTM2OTI0NDVjMTEuMTI4OTgzNyAwIDIyLjI3MDEwMzctNC4yNDc3MDM3IDMwLjc2NTUxMTExLTEyLjc0MzExMTEyIDE2Ljk5MDgxNDgyLTE2Ljk5MDgxNDgyIDE2Ljk5MDgxNDgyLTQ0LjU0MDIwNzQxIDAtNjEuNTE4ODg1OTJMMzQ1LjAyODgzNTU1IDUxMi44MDA5OTU1NSA3NzUuMTAyNzY3NDEgODIuNzM5MmMxNi45OTA4MTQ4Mi0xNi45Nzg2Nzg1MiAxNi45OTA4MTQ4Mi00NC41NDAyMDc0MSAwLTYxLjUxODg4NTkyLTE2Ljk5MDgxNDgyLTE2Ljk5MDgxNDgyLTQ0LjUyODA3MTExLTE2Ljk5MDgxNDgyLTYxLjUxODg4NTkzIDBMMjUyLjc0NDQzODUyIDQ4Mi4wNDc2MjA3NWE0My41MTQ2OTAzNyA0My41MTQ2OTAzNyAwIDAgMCAwIDYxLjUzMTAyMjIybDQ2MC44Mzk0NDI5NiA0NjAuODE1MTcwMzZjOC40ODMyNzExMSA4LjQ5NTQwNzQxIDE5LjYyNDM5MTExIDEyLjc0MzExMTExIDMwLjc1MzM3NDgyIDEyLjc0MzExMTEyeiI+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
|
||||||
|
._home {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTIzMC40IDk5MmMtNjQgMC0xMTUuMi01MS4yLTExNS4yLTExNS4yTDExNS4yIDU0NCA3Ni44IDU4Mi40QzcwLjQgNTg4LjggNTcuNiA1OTUuMiA0NC44IDU5NS4yYy0xMi44IDAtMjUuNi02LjQtMzItMTIuOEM2LjQgNTY5LjYgMCA1NTYuOCAwIDU0NCAwIDUzNy42IDYuNCA1MjQuOCAxMi44IDUxMmw0NjcuMi00NjcuMkM0ODYuNCAzOC40IDQ5OS4yIDMyIDUxMiAzMnMyNS42IDYuNCAzMiAxMi44TDEwMTEuMiA1MTJDMTAxNy42IDUyNC44IDEwMjQgNTM3LjYgMTAyNCA1NDRjMCAxMi44LTYuNCAyNS42LTEyLjggMzItNi40IDYuNC0xOS4yIDEyLjgtMzIgMTIuOHMtMjUuNi02LjQtMzItMTIuOEw1MTIgMTQ3LjIgMjExLjIgNDQ4bDAgNDIyLjRjMCAxMi44IDEyLjggMjUuNiAyNS42IDI1LjZsMTE1LjIgMCAwLTE4NS42YzAtMjUuNiAxOS4yLTQ0LjggNDQuOC00NC44bDIzMC40IDBjMjUuNiAwIDQ0LjggMTkuMiA0NC44IDQ0LjhzLTE5LjIgNDQuOC00NC44IDQ0LjhMNDQxLjYgNzU1LjJsMCAxODUuNmMwIDI1LjYtMTkuMiA0NC44LTQ0LjggNDQuOEwyMzAuNCA5ODUuNnpNNjI3LjIgOTkyYy0yNS42IDAtNDQuOC0xOS4yLTQ0LjgtNDQuOCAwLTI1LjYgMTkuMi00NC44IDQ0LjgtNDQuOGwxNjAgMGMxMi44IDAgMjUuNi0xMi44IDI1LjYtMjUuNmwwLTI1NmMwLTI1LjYgMTkuMi00NC44IDQ0LjgtNDQuOCAyNS42IDAgNDQuOCAxOS4yIDQ0LjggNDQuOGwwIDI1NmMwIDY0LTUxLjIgMTE1LjItMTE1LjIgMTE1LjJMNjI3LjIgOTkyeiIgZmlsbD0iIzc3Nzc3NyI+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'title'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
headershow: true,
|
||||||
|
hasbackbtn: false,
|
||||||
|
header_statusbar_height: 0,
|
||||||
|
header_title_height: 40,
|
||||||
|
header_title_margin: 0,
|
||||||
|
mainpage: '',
|
||||||
|
opac: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
seatheight() {
|
||||||
|
if (this.mode == 'title')
|
||||||
|
return this.header_statusbar_height + this.header_title_height;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
//#ifdef H5
|
||||||
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
|
this.headershow = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
var app = getApp();
|
||||||
|
this.header_statusbar_height = app.globalData._header_statusbar_height;
|
||||||
|
this.header_title_height = app.globalData._header_title_height;
|
||||||
|
this.header_title_margin = app.globalData._header_title_margin;
|
||||||
|
this.mainpage = app.globalData.mainpage;
|
||||||
|
if (getCurrentPages().length > 1)
|
||||||
|
this.hasbackbtn = true;
|
||||||
|
this.scrollname = this.title;
|
||||||
|
if (this.mode == 'scroll')
|
||||||
|
app.globalData.scrollcbs['header' + this.scrollname] = (e, route) => {
|
||||||
|
if (this.com_getpage().getroute() != route)
|
||||||
|
return;
|
||||||
|
if(e.scrollTop == 0 && this._last_scrolltop > 0)
|
||||||
|
return;
|
||||||
|
this._last_scrolltop = e.scrollTop;
|
||||||
|
var sc = e.scrollTop - this.header_statusbar_height - this.header_title_height;
|
||||||
|
if (sc < 0) {
|
||||||
|
this.opac = 0;
|
||||||
|
} else if (sc < this.header_title_height) {
|
||||||
|
this.opac = sc / this.header_title_height;
|
||||||
|
} else {
|
||||||
|
this.opac = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
if (this.mode == 'scroll')
|
||||||
|
delete getApp().globalData.scrollcbs['header' + this.scrollname];
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
Getheight() {
|
||||||
|
return this.seatheight;
|
||||||
|
},
|
||||||
|
goback() {
|
||||||
|
uni.navigateBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<input class="_input" :style="ciystyle" :type="type" :name="name" :value="txtvalue" :password="password" :placeholder="placeholder" :disabled="disabled" :maxlength="maxlength" :confirm-type="confirmType" @input="textinput" @focus="textfocus" @blur="textblur" @confirm="textconfirm" :cursor-spacing="120" :class="{_bb:bb,_left:left,_disabled:disabled}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
virtualHost: true
|
||||||
|
},
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'focus', 'blur', 'input'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String, //text、number、idcard、digit 微信小程序:safe-password、nickname
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bb: { //传统文本框效果
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 180
|
||||||
|
},
|
||||||
|
confirmType: {
|
||||||
|
type: String, // send发送、search搜索、next下一个、go前往、done完成
|
||||||
|
default: 'done'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
txtvalue() {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
return this.modelValue;
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
return this.value;
|
||||||
|
if (this.modelValue)
|
||||||
|
return this.modelValue;
|
||||||
|
if (this.value)
|
||||||
|
return this.value;
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.txtvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
textfocus(e) {
|
||||||
|
this.$emit('focus', e);
|
||||||
|
},
|
||||||
|
textblur(e) {
|
||||||
|
this.$emit('blur', e);
|
||||||
|
},
|
||||||
|
textinput(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('input', {
|
||||||
|
name: this.name,
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
textconfirm(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'confirm',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._input {
|
||||||
|
font-size: 1em;
|
||||||
|
height: 1em;
|
||||||
|
width: inherit;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._disabled {
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb._disabled {
|
||||||
|
background: var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb {
|
||||||
|
background: var(--bg1);
|
||||||
|
text-align: left;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
<template>
|
||||||
|
<view class="_input" :class="{_bb:bb,_left:left,_unit:!!unit,_disabled:disabled}">
|
||||||
|
<input type="hidden" :name="name" :value="tvalue" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_unit'" :value="unit" style="display:none;" />
|
||||||
|
<input type="digit" :name="hasmore?name+'_num':''" :class="{_disabled:disabled}" :value="txvalue" :placeholder="placeholder" :confirm-type="confirmType" @input="textinput" @focus="textfocus" @blur="textblur" @confirm="textconfirm" :cursor-spacing="120" :disabled="disabled" :style="ciystyle" />
|
||||||
|
<view class="_unit" v-if="unit" :class="{_disabled:disabled}">{{unit}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'focus', 'blur'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bb: { //传统文本框效果
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: {
|
||||||
|
width: '5em'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
bet: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
type: [String],
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
confirmType: {
|
||||||
|
type: String, // send发送、search搜索、next下一个、go前往、done完成
|
||||||
|
default: 'done'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tvalue: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
txvalue() {
|
||||||
|
var v = 0;
|
||||||
|
if (this.modelValue)
|
||||||
|
v = this.toint(this.modelValue);
|
||||||
|
if (this.value)
|
||||||
|
v = this.toint(this.value);
|
||||||
|
this.tvalue = v;
|
||||||
|
return this.tofix(v / this.mybet, -4);
|
||||||
|
},
|
||||||
|
mybet() {
|
||||||
|
var bet = this.toint(this.bet);
|
||||||
|
if (bet < 1)
|
||||||
|
bet = 1;
|
||||||
|
return bet;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.tvalue = this.txvalue * this.mybet;
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
textfocus(e) {
|
||||||
|
this.$emit('focus', e);
|
||||||
|
},
|
||||||
|
textblur(e) {
|
||||||
|
this.$emit('blur', e);
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
txt = this.toint(this.tofloat(txt) * this.mybet);
|
||||||
|
this.tvalue = txt;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
},
|
||||||
|
textinput(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
txt = this.toint(this.tofloat(txt) * this.mybet);
|
||||||
|
this.tvalue = txt;
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
textconfirm(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
txt = this.toint(this.tofloat(txt) * this.mybet);
|
||||||
|
this.tvalue = txt;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'confirm',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._input {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input input {
|
||||||
|
font-size: 1em;
|
||||||
|
height: 1em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb {
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb input {
|
||||||
|
background: var(--bg1);
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb._unit input {
|
||||||
|
border-radius: 0.5em 0 0 0.5em;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb ._unit {
|
||||||
|
background: var(--bg1);
|
||||||
|
padding: 0.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
border-radius: 0 0.5em 0.5em 0;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb ._disabled {
|
||||||
|
background: var(--bg3);
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input ._disabled {
|
||||||
|
color: var(--bg7);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
<template>
|
||||||
|
<view class="_cyc" :class="{_bb:bb,_left:left,_disabled:disabled}">
|
||||||
|
<input type="hidden" :name="name" :value="tvalue" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_num'" :value="num" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_unit'" :value="unit" style="display:none;" />
|
||||||
|
<ciy-input @change="chgnum" :disabled="disabled" style="width:4em;" v-model="num"></ciy-input>
|
||||||
|
<view class="_unit">
|
||||||
|
<ciy-select @change="chgunit" :disabled="disabled" v-model="unit" :rows="trowcnt" align="center" :range="trange"></ciy-select>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bb: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: String,
|
||||||
|
default: 'month,day,min'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
num: 0,
|
||||||
|
unit: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.setvalue(newD, oldD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.setvalue(newD, oldD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
if (this.unit == 'month') {
|
||||||
|
return -this.toint(this.num);
|
||||||
|
} else if (this.unit == 'day') {
|
||||||
|
return this.toint(this.num) * 86400;
|
||||||
|
} else if (this.unit == 'hour') {
|
||||||
|
return this.toint(this.num) * 3600;
|
||||||
|
} else if (this.unit == 'min') {
|
||||||
|
return this.toint(this.num) * 60;
|
||||||
|
} else {
|
||||||
|
return this.num;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trange() {
|
||||||
|
var rg = [];
|
||||||
|
var rs = this.range.split(',');
|
||||||
|
for (var i = 0; i < rs.length; i++) {
|
||||||
|
rg.push({
|
||||||
|
id: rs[i],
|
||||||
|
name: this.lang('cyc.' + rs[i])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rg;
|
||||||
|
},
|
||||||
|
trowcnt() {
|
||||||
|
var cnt = this.range.split(',').length;
|
||||||
|
if(cnt > 4)
|
||||||
|
return 3;
|
||||||
|
return cnt;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setvalue(this.value || this.modelValue);
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue,
|
||||||
|
num: this.num,
|
||||||
|
unit: this.unit
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setvalue(val, old) {
|
||||||
|
var vi = this.toint(val);
|
||||||
|
if (vi == 0)
|
||||||
|
vi = 86400;
|
||||||
|
var unit = 'day';
|
||||||
|
var num = 0;
|
||||||
|
if (vi < 0) {
|
||||||
|
unit = 'month';
|
||||||
|
num = -vi;
|
||||||
|
} else if (vi % 86400 == 0) {
|
||||||
|
unit = 'day';
|
||||||
|
num = this.toint(vi / 86400);
|
||||||
|
} else if (vi % 3600 == 0) {
|
||||||
|
unit = 'hour';
|
||||||
|
num = this.toint(vi / 3600);
|
||||||
|
} else if (vi % 60 == 0) {
|
||||||
|
unit = 'min';
|
||||||
|
num = this.toint(vi / 60);
|
||||||
|
} else {
|
||||||
|
unit = 'sec';
|
||||||
|
num = this.toint(vi);
|
||||||
|
}
|
||||||
|
if (this.unit != unit)
|
||||||
|
this.unit = unit;
|
||||||
|
if (this.num != num)
|
||||||
|
this.num = num;
|
||||||
|
},
|
||||||
|
chgnum(e) {
|
||||||
|
this.$emit('update:modelValue', this.tvalue);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'num',
|
||||||
|
value: this.tvalue,
|
||||||
|
num: this.toint(this.num),
|
||||||
|
unit: this.unit
|
||||||
|
});
|
||||||
|
},
|
||||||
|
chgunit(e) {
|
||||||
|
this.$emit('update:modelValue', this.tvalue);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'unit',
|
||||||
|
value: this.tvalue,
|
||||||
|
num: this.num,
|
||||||
|
unit: this.unit
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._cyc {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc._left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc input {
|
||||||
|
font-size: 1em;
|
||||||
|
height: 1em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc._bb {
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc._bb input {
|
||||||
|
background: var(--bg1);
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em 0 0 0.5em;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc._bb ._unit {
|
||||||
|
background: var(--bg1);
|
||||||
|
padding: 0.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
border-radius: 0 0.5em 0.5em 0;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc._bb._disabled input {
|
||||||
|
background: var(--bg3);
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._cyc._bb._disabled ._unit {
|
||||||
|
background: var(--bg3);
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
<template>
|
||||||
|
<view style="position: relative;" :style="{textAlign:left?'left':'right'}">
|
||||||
|
<input type="hidden" :name="name" :value="tvalue" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_date1'" :value="date1" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_date2'" :value="date2" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_str1'" :value="todatetime(date1,btime?'':'d')" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_str2'" :value="todatetime(date2,btime?'':'d')" style="display:none;" />
|
||||||
|
<ciy-inputdatetime :disabled="disabled" @change="chg" class="_dt" v-model="date1" :bordercolor="bordercolor" clearbtn :placeholder="placeholder" :btime="btime" :selectbg="selectbg" :selecttextcolor="selecttextcolor" :weekmonday="weekmonday" :diastema="diastema"></ciy-inputdatetime>
|
||||||
|
<view class="_spn">~</view>
|
||||||
|
<ciy-inputdatetime :disabled="disabled" @change="chg" class="_dt" v-model="date2" :bordercolor="bordercolor" clearbtn :placeholder="placeholder" :btime="btime" :selectbg="selectbg" :selecttextcolor="selecttextcolor" :weekmonday="weekmonday" :diastema="diastema"></ciy-inputdatetime>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
btime: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bordercolor: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg6)'
|
||||||
|
},
|
||||||
|
selecttextcolor: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--man5)'
|
||||||
|
},
|
||||||
|
selectbg: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg1)'
|
||||||
|
},
|
||||||
|
weekmonday: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
diastema: { //间隙
|
||||||
|
type: Number,
|
||||||
|
default: 16
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
date1: 0,
|
||||||
|
date2: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.setvalue(newD, oldD);
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.setvalue(newD, oldD);
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
if (this.date1 && this.date2) {
|
||||||
|
if (this.date1 < this.date2)
|
||||||
|
return this.todatetime(this.date1, this.btime ? '' : 'd') + '~' + this.todatetime(this.date2, this.btime ? '' : 'd');
|
||||||
|
else
|
||||||
|
return this.todatetime(this.date2, this.btime ? '' : 'd') + '~' + this.todatetime(this.date1, this.btime ? '' : 'd');
|
||||||
|
} else if (this.date1) {
|
||||||
|
return this.todatetime(this.date1, this.btime ? '' : 'd') + '~';
|
||||||
|
} else if (this.date2) {
|
||||||
|
return '~' + this.todatetime(this.date2, this.btime ? '' : 'd');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue ? this.tvalue : '',
|
||||||
|
date1: this.date1,
|
||||||
|
date2: this.date2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setvalue(val, old) {
|
||||||
|
var vals = (val || '').split('~');
|
||||||
|
if (vals.length < 2) {
|
||||||
|
if (this.date1 != 0)
|
||||||
|
this.date1 = 0;
|
||||||
|
if (this.date2 != 0)
|
||||||
|
this.date2 = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var date1 = new Date(vals[0]);
|
||||||
|
var date2 = new Date(vals[1]);
|
||||||
|
if (isNaN(date1.getTime()))
|
||||||
|
date1 = 0;
|
||||||
|
else
|
||||||
|
date1 = this.tostamp(date1);
|
||||||
|
if (isNaN(date2.getTime()))
|
||||||
|
date2 = 0;
|
||||||
|
else
|
||||||
|
date2 = this.tostamp(date2);
|
||||||
|
|
||||||
|
if (this.date1 != date1)
|
||||||
|
this.date1 = date1;
|
||||||
|
if (this.date2 != date2)
|
||||||
|
this.date2 = date2;
|
||||||
|
},
|
||||||
|
chg(e) {
|
||||||
|
if (e.from != 'done')
|
||||||
|
return;
|
||||||
|
this.$emit('update:modelValue', this.tvalue);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'value',
|
||||||
|
value: this.tvalue ? this.tvalue : '',
|
||||||
|
date1: this.date1,
|
||||||
|
date2: this.date2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._dt {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dtx {
|
||||||
|
min-width: 7em;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
text-align: center;
|
||||||
|
background: var(--bg2);
|
||||||
|
border: 1px solid var(--bg6);
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._spn {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 0 0 0.3em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,543 @@
|
||||||
|
<template>
|
||||||
|
<view style="position: relative;">
|
||||||
|
<input type="hidden" :name="name" :value="tostamp(tvalue)" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_date'" :value="todatetime(tvalue,btime?'':(selectmonth?'m':'d'))" style="display:none;" />
|
||||||
|
<view class="_show" :class="{_left:left,_disabled:disabled}" @tap="showpop" v-if="tostamp(tvalue)==0" style="color:var(--txt1)">{{placeholder===undefined?lang('placeholder.select'):placeholder}}</view>
|
||||||
|
<view class="_show" :class="{_left:left,_disabled:disabled}" @tap="showpop" v-else>{{todatetime(tvalue,btime?'':(selectmonth?'m':'d'))}}</view>
|
||||||
|
<view class="_mask" v-if="popclass" @tap="hidepop"></view>
|
||||||
|
<view class="_pop" :animation="anidatapop" v-if="popclass" :class="popclass">
|
||||||
|
<view class="_main" :class="popclass">
|
||||||
|
<view class="ciy-hr" style="flex:none;"></view>
|
||||||
|
<ciy-calendar :selectmonth="selectmonth" :value="vdate" @change="chgcalendar" v-if="cpage == 0" name="tp" :mindate="mindate" :maxdate="maxdate" :weekmonday="weekmonday" :selectbg="selectbg" :bordercolor="bordercolor" :selecttextcolor="selecttextcolor" :clearbtn="clearbtn"></ciy-calendar>
|
||||||
|
<view v-if="cpage == 1" class="_shour">
|
||||||
|
<view class="itm" v-for="(_,val) in 24" @tap="clkhour(val)" :style="val==vhour?'font-weight:bolder;color:var(--man5);':''">
|
||||||
|
{{val}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="cpage == 2" class="_smin" :class="popclass">
|
||||||
|
<view class="_smin2">
|
||||||
|
<view class="itm" v-for="(_,val) in 10" @tap="clkmin2(val)" :style="val==vminute2?'font-weight:bolder;color:var(--man5);':''">
|
||||||
|
{{val}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-hr"></view>
|
||||||
|
<view class="_smin1">
|
||||||
|
<view class="itm" v-for="(_,val) in 6" @tap="clkmin1(val)" :style="val==vminute1?'font-weight:bolder;color:var(--man5);':''">
|
||||||
|
{{val*10}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_selcard" v-if="btime">
|
||||||
|
<view class="itm" :class="{_sel:cpage==0}" @tap="clkpage(0)">
|
||||||
|
<view>{{todatetime(vdate,'y', ' ')}}</view>
|
||||||
|
<view>{{todatetime(vdate,'x', ' ')}}</view>
|
||||||
|
<view class="_txt">{{lang('inputdate.date')}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="itm" :class="{_sel:cpage==1}" @tap="clkpage(1)">
|
||||||
|
<view style="font-size:2em;">{{topad0(vhour,2)}}</view>
|
||||||
|
<view class="_txt">{{lang('inputdate.hour')}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="itm" :class="{_sel:cpage==2}" @tap="clkpage(2)">
|
||||||
|
<view style="font-size:2em;">{{topad0(vminute1*10+vminute2,2)}}</view>
|
||||||
|
<view class="_txt">{{lang('inputdate.minute')}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="itm _bbtn" :class="popclass">
|
||||||
|
<view class="btn def" @tap="today">{{lang('inputdate.now')}}</view>
|
||||||
|
<view class="btn" @tap="done">{{lang('inputdate.done')}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-hr"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
btime: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bordercolor: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg6)'
|
||||||
|
},
|
||||||
|
selecttextcolor: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--man5)'
|
||||||
|
},
|
||||||
|
selectbg: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg1)'
|
||||||
|
},
|
||||||
|
selectmonth: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
weekmonday: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
mindate: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
maxdate: {
|
||||||
|
type: [String, Number, Date],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
clearbtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
diastema: { //间隙
|
||||||
|
type: Number,
|
||||||
|
default: 16
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
vdate: 0,
|
||||||
|
vhour: 0,
|
||||||
|
vminute1: 0,
|
||||||
|
vminute2: 0,
|
||||||
|
cpage: 0,
|
||||||
|
anidatapop: {},
|
||||||
|
popclass: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = new Date(this.modelValue * 1000);
|
||||||
|
else if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = new Date(this.value * 1000);
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
} else {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(val instanceof Date)) {
|
||||||
|
if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||||||
|
val = this.str2date(val);
|
||||||
|
} else {
|
||||||
|
val = this.toint(val);
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
}
|
||||||
|
} else if (isNaN(val.getTime()))
|
||||||
|
val = new Date();
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
max() {
|
||||||
|
var val = this.maxdate;
|
||||||
|
if (val instanceof Date) {
|
||||||
|
if (isNaN(val.getTime()))
|
||||||
|
val = null;
|
||||||
|
} else if (typeof(val) == 'number') {
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
} else if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||||||
|
val = this.str2date(val);
|
||||||
|
} else if (val == 'now') {
|
||||||
|
val = new Date();
|
||||||
|
} else {
|
||||||
|
val = this.toint(val);
|
||||||
|
if (val == 0)
|
||||||
|
val = null;
|
||||||
|
else
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
min() {
|
||||||
|
var val = this.mindate;
|
||||||
|
if (val instanceof Date) {
|
||||||
|
if (isNaN(val.getTime()))
|
||||||
|
val = null;
|
||||||
|
} else if (typeof(val) == 'number') {
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
} else if (val.indexOf('-') > -1 || val.indexOf('/') > -1) {
|
||||||
|
val = this.str2date(val);
|
||||||
|
} else if (val == 'now') {
|
||||||
|
val = new Date();
|
||||||
|
} else {
|
||||||
|
val = this.toint(val);
|
||||||
|
if (val == 0)
|
||||||
|
val = null;
|
||||||
|
else
|
||||||
|
val = new Date(val * 1000);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// var vd = new Date(this.tvalue.getFullYear(), this.tvalue.getMonth(), this.tvalue.getDate());
|
||||||
|
// vd.setMinutes(-vd.getTimezoneOffset());
|
||||||
|
// this.vdate = this.tostamp(vd);
|
||||||
|
var date = this.tostamp(this.onlydate(this.tvalue));
|
||||||
|
this.vdate = date;
|
||||||
|
this.vhour = this.tvalue.getHours();
|
||||||
|
var minute = this.tvalue.getMinutes();
|
||||||
|
this.vminute1 = parseInt(minute / 10);
|
||||||
|
this.vminute2 = minute - this.vminute1 * 10;
|
||||||
|
if (this.vdate == 0 && this.vhour == 8)
|
||||||
|
this.vhour = 0;
|
||||||
|
if (this.initevent) {
|
||||||
|
this.emit('init', this.tvalue, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onlydate(val) {
|
||||||
|
var dt = new Date(val.toLocaleDateString());
|
||||||
|
dt.setMinutes(-dt.getTimezoneOffset());
|
||||||
|
return dt;
|
||||||
|
},
|
||||||
|
chgcalendar(e) {
|
||||||
|
var from = 'calendar'; //false 同步value到父
|
||||||
|
if (!this.btime || e.from == 'today' || e.from == 'nodate')
|
||||||
|
from = 'done';
|
||||||
|
if (from == 'done') {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.hidepop();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
if (e.from == 'nodate') {
|
||||||
|
this.vhour = 0;
|
||||||
|
this.vminute1 = 0;
|
||||||
|
this.vminute2 = 0;
|
||||||
|
}
|
||||||
|
this.vdate = e.value;
|
||||||
|
this.updatevalue(from);
|
||||||
|
},
|
||||||
|
updatevalue(from) {
|
||||||
|
var d = new Date(this.vdate * 1000);
|
||||||
|
if (this.vdate != 0) {
|
||||||
|
d.setHours(this.vhour);
|
||||||
|
d.setMinutes(this.vminute1 * 10 + this.vminute2);
|
||||||
|
}
|
||||||
|
if (d.getTime() == this.tvalue.getTime())
|
||||||
|
return;
|
||||||
|
this.emit(from, d);
|
||||||
|
},
|
||||||
|
emit(from, date) {
|
||||||
|
if (!this.btime) {
|
||||||
|
var date = new Date(date.getTime());
|
||||||
|
if (date.getTime() != 0) {
|
||||||
|
date.setHours(0);
|
||||||
|
date.setMinutes(0);
|
||||||
|
date.setSeconds(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (date.getFullYear() == 1970 && date.getMonth() == 0 && date.getDate() == 1)
|
||||||
|
// date.setMinutes(-date.getTimezoneOffset());
|
||||||
|
var stramp = this.tostamp(date);
|
||||||
|
if (from == 'done') {
|
||||||
|
this.$emit('update:modelValue', stramp);
|
||||||
|
this.v = date;
|
||||||
|
}
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: from,
|
||||||
|
value: stramp,
|
||||||
|
date: date
|
||||||
|
});
|
||||||
|
},
|
||||||
|
today() {
|
||||||
|
var dt = new Date();
|
||||||
|
this.vhour = dt.getHours();
|
||||||
|
var min = dt.getMinutes();
|
||||||
|
this.vminute1 = parseInt(min / 10);
|
||||||
|
this.vminute2 = min - parseInt(min / 10) * 10;
|
||||||
|
dt.setSeconds(0);
|
||||||
|
this.vdate = this.tostamp(dt);
|
||||||
|
//this.updatevalue('today', this.vdate, true);
|
||||||
|
},
|
||||||
|
done() {
|
||||||
|
var date = new Date(this.vdate * 1000);
|
||||||
|
if (this.vdate != 0) {
|
||||||
|
date.setHours(this.vhour);
|
||||||
|
date.setMinutes(this.vminute1 * 10 + this.vminute2);
|
||||||
|
date.setSeconds(0);
|
||||||
|
}
|
||||||
|
this.emit('done', date);
|
||||||
|
this.hidepop();
|
||||||
|
},
|
||||||
|
clkhour(val) {
|
||||||
|
this.vhour = val;
|
||||||
|
this.updatevalue('hour');
|
||||||
|
},
|
||||||
|
clkmin1(val) {
|
||||||
|
this.vminute1 = val;
|
||||||
|
this.updatevalue('minute');
|
||||||
|
},
|
||||||
|
clkmin2(val) {
|
||||||
|
this.vminute2 = val;
|
||||||
|
this.updatevalue('minute');
|
||||||
|
},
|
||||||
|
clkpage(page) {
|
||||||
|
this.cpage = page;
|
||||||
|
},
|
||||||
|
hidepop() {
|
||||||
|
var app = getApp();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('100vw');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.popclass = '';
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
async showpop() {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
if (this.popclass) {
|
||||||
|
return this.hidepop();
|
||||||
|
}
|
||||||
|
var app = getApp();
|
||||||
|
app.globalData.scrollcbs['com_datetime'] = e => {
|
||||||
|
delete app.globalData.scrollcbs['com_datetime'];
|
||||||
|
this.hidepop();
|
||||||
|
};
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
var fixtop = 0;
|
||||||
|
if (this.fix) {
|
||||||
|
//向上遍历页面中带fixed和absolute的父元素,累加top。
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cpage = 0;
|
||||||
|
// if (this.tvalue.getTime() == 0)
|
||||||
|
// this.vdate = this.tostamp();
|
||||||
|
var showrect = await this.getrect('._show');
|
||||||
|
if (!showrect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.popclass = 'temp';
|
||||||
|
var mainrect = await this.getrect('._main');
|
||||||
|
if (!mainrect)
|
||||||
|
return;
|
||||||
|
this.vdate = this.tostamp(this.tvalue);
|
||||||
|
if (this.vdate != 0) {
|
||||||
|
this.vhour = this.tvalue.getHours();
|
||||||
|
var minute = this.tvalue.getMinutes();
|
||||||
|
this.vminute1 = parseInt(minute / 10);
|
||||||
|
this.vminute2 = minute - this.vminute1 * 10;
|
||||||
|
} else {
|
||||||
|
this.vhour = 0;
|
||||||
|
this.vminute1 = 0;
|
||||||
|
this.vminute2 = 0;
|
||||||
|
}
|
||||||
|
var bott = app.globalData._sysinfo.windowHeight - showrect.bottom - footerheight - this.diastema;
|
||||||
|
var topcls = '_btm';
|
||||||
|
var sytop = showrect.bottom + this.diastema - fixtop;
|
||||||
|
if (bott < mainrect.height) {
|
||||||
|
sytop = showrect.top - this.diastema - mainrect.height;
|
||||||
|
if (sytop < headerheight + fixtop)
|
||||||
|
sytop = headerheight + fixtop;
|
||||||
|
topcls = '_top';
|
||||||
|
}
|
||||||
|
this.popclass = topcls;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX(0);
|
||||||
|
animation.top(sytop);
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._show {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
._show._left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._show._disabled {
|
||||||
|
color: var(--bg7);
|
||||||
|
}
|
||||||
|
|
||||||
|
._smin {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._smin1 {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
line-height: 7em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._smin1>.itm {
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 16.667%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._smin2 {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
line-height: 7em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._smin2>.itm {
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._shour {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
line-height: 5.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._shour>.itm {
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 16.6666%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._selcard {
|
||||||
|
display: flex;
|
||||||
|
width: calc(100% - 1em);
|
||||||
|
margin: 0.5em;
|
||||||
|
white-space: nowrap;
|
||||||
|
gap: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._selcard ._sel {
|
||||||
|
background: linear-gradient(33deg, var(--bg1), var(--bg4));
|
||||||
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid var(--bg6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._selcard ._txt {
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._selcard>.itm {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5em 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all 0.3s;
|
||||||
|
height: 5em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
._selcard ._bbtn {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop {
|
||||||
|
position: fixed;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
transform: translateX(100vw);
|
||||||
|
opacity: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 50001;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._main {
|
||||||
|
background: var(--bg2);
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
._btm,
|
||||||
|
._pop ._main._btm,
|
||||||
|
._selcard ._bbtn._btm {
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 50001;
|
||||||
|
flex: 1;
|
||||||
|
backgroundx: #f3abec99;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
<template>
|
||||||
|
<view class="_input" :class="{_left:left,_disabled:disabled}">
|
||||||
|
<view class="_btn" @tap="op(-1)">-</view>
|
||||||
|
<input :name="name" :value="tvalue" @input="textinput" :disabled="disabled" @confirm="textconfirm" :cursor-spacing="120" :style="{width:width}" />
|
||||||
|
<view class="_btn" @tap="op(1)">+</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'input'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: "2em"
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 9999999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tvalue: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(n, d) {
|
||||||
|
this.emit(n, 'watch'); //computed不触发
|
||||||
|
},
|
||||||
|
value(n, d) {
|
||||||
|
this.emit(n, 'watch'); //computed不触发
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
innervalue() {
|
||||||
|
var val = 0;
|
||||||
|
if (this.modelValue)
|
||||||
|
val = this.toint(this.modelValue);
|
||||||
|
if (this.value)
|
||||||
|
val = this.toint(this.value);
|
||||||
|
if (val > this.max)
|
||||||
|
val = this.max;
|
||||||
|
if (val < this.min)
|
||||||
|
val = this.min;
|
||||||
|
this.tvalue = val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.emit(this.innervalue, this.initevent ? 'init' : '');
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
emit(val, from) {
|
||||||
|
val = this.toint(val);
|
||||||
|
if (val > this.max)
|
||||||
|
val = this.max;
|
||||||
|
if (val < this.min)
|
||||||
|
val = this.min;
|
||||||
|
if (this.old === val)
|
||||||
|
return;
|
||||||
|
if (this.modelValue !== undefined && from != 'watch') {
|
||||||
|
this.$emit('update:modelValue', val);
|
||||||
|
} else {}
|
||||||
|
this.tvalue = val;
|
||||||
|
if (from) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: from,
|
||||||
|
value: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.old = val;
|
||||||
|
},
|
||||||
|
textinput(e) {
|
||||||
|
this.emit(e.detail.value || e.data, 'input');
|
||||||
|
},
|
||||||
|
textconfirm(e) {
|
||||||
|
this.emit(e.detail.value || e.data, 'confirm');
|
||||||
|
},
|
||||||
|
op(oe) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.emit(this.tvalue + oe, 'op');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._input {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input input {
|
||||||
|
font-size: 1em;
|
||||||
|
height: 2em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._btn {
|
||||||
|
background: linear-gradient(100deg, var(--bg4), var(--bg6));
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._disabled input {
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._disabled ._btn {
|
||||||
|
color: var(--txt1);
|
||||||
|
background: linear-gradient(100deg, var(--bg3), var(--bg5));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
<template>
|
||||||
|
<view class="rel _input _bb">
|
||||||
|
<input :style="ciystyle" style="margin-right:3em;" :type="type" :name="name" :value="txtvalue" :placeholder="placeholder" :disabled="disabled" :maxlength="maxlength" :confirm-type="confirmType" @input="textinput" @focus="textfocus" @blur="textblur" @confirm="textconfirm" :cursor-spacing="120" :class="{_left:left,_disabled:disabled}" />
|
||||||
|
<button class="btn sm def abs r0 t0 b0" style="z-index:10;line-height: 2em;" @tap="ocr">OCR</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'focus', 'blur'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String, //text、number、idcard、digit 微信小程序:safe-password、nickname
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
bb: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '66'
|
||||||
|
},
|
||||||
|
clktxt: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: Number,
|
||||||
|
default: 140
|
||||||
|
},
|
||||||
|
confirmType: {
|
||||||
|
type: String, // send发送、search搜索、next下一个、go前往、done完成
|
||||||
|
default: 'done'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
txtvalue() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
val = this.modelValue + '';
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
val = this.value + '';
|
||||||
|
} else {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.txtvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
textfocus(e) {
|
||||||
|
this.$emit('focus', e);
|
||||||
|
},
|
||||||
|
textblur(e) {
|
||||||
|
this.$emit('blur', e);
|
||||||
|
},
|
||||||
|
textinput(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
textconfirm(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'confirm',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ocr(e) {
|
||||||
|
var app = getApp();
|
||||||
|
app.globalData.ciy_page_ocr = {
|
||||||
|
txt: this.txtvalue,
|
||||||
|
clktxt: this.clktxt ? this.clktxt.split(',') : []
|
||||||
|
};
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/pub/ocrdata',
|
||||||
|
events: {
|
||||||
|
writedata: data => {
|
||||||
|
this.v = data;
|
||||||
|
this.$emit('update:modelValue', this.v);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'ocr',
|
||||||
|
value: this.v
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._input {
|
||||||
|
font-size: 1em;
|
||||||
|
height: 1em;
|
||||||
|
width: inherit;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._disabled {
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._input._bb {
|
||||||
|
background: var(--bg1);
|
||||||
|
text-align: left;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
height:2.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
<template>
|
||||||
|
<view class="_tp" :class="{_left:left,_disabled:disabled}">
|
||||||
|
<input type="hidden" :name="name" :value="innervalue" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_name'" :value="hour+':'+minute+(bsec?':' + sec:'')" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_hour'" :value="hour" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_min'" :value="minute" style="display:none;" />
|
||||||
|
<input v-if="hasmore && bsec" type="hidden" :name="name+'_sec'" :value="sec" style="display:none;" />
|
||||||
|
<ciy-select v-model="hour" :disabled="disabled" :diastema="diastema" noarrow :rows="6" itemalign="center" :minselectsearch="100" :range="hours" :ciystyle="{width:'2em',textAlign:'center'}" @change="chg"></ciy-select>
|
||||||
|
:
|
||||||
|
<ciy-select v-model="minute" :disabled="disabled" :diastema="diastema" noarrow :rows="5" itemalign="center" :minselectsearch="100" :range="minutes" :ciystyle="{width:'2em',textAlign:'center'}" @change="chg"></ciy-select>
|
||||||
|
<template v-if="bsec">
|
||||||
|
:
|
||||||
|
<ciy-select v-model="sec" :disabled="disabled" :diastema="diastema" noarrow :rows="5" itemalign="center" :minselectsearch="100" :range="minutes" :ciystyle="{width:'2em',textAlign:'center'}" @change="chg"></ciy-select>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bsec: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
diastema: { //上下间隙
|
||||||
|
type: Number,
|
||||||
|
default: 16
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innervalue: this.modelValue !== undefined ? this.modelValue : this.value,
|
||||||
|
hours: [],
|
||||||
|
minutes: [],
|
||||||
|
hour: 0,
|
||||||
|
minute: 0,
|
||||||
|
sec: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(newD) {
|
||||||
|
if (newD !== undefined) {
|
||||||
|
this.innervalue = newD;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value(newD) {
|
||||||
|
if (this.modelValue === undefined) {
|
||||||
|
this.innervalue = newD;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
innervalue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
var time = this.toint(newD);
|
||||||
|
if (time <= 0 || time > 86400)
|
||||||
|
return;
|
||||||
|
time--;
|
||||||
|
this.hour = this.toint(time / 3600);
|
||||||
|
this.minute = this.toint((time - this.hour * 3600) / 60);
|
||||||
|
this.sec = time - this.hour * 3600 - this.minute * 60;
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
mounted() {
|
||||||
|
for (var i = 0; i < 24; i++)
|
||||||
|
this.hours.push({
|
||||||
|
id: i,
|
||||||
|
name: this.topad0(i, 2)
|
||||||
|
});
|
||||||
|
for (var i = 0; i < 60; i++)
|
||||||
|
this.minutes.push({
|
||||||
|
id: i,
|
||||||
|
name: this.topad0(i, 2)
|
||||||
|
});
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.innervalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updatevalue() {
|
||||||
|
this.innervalue = this.hour * 3600 + this.minute * 60 + 1;
|
||||||
|
if (this.bsec)
|
||||||
|
this.innervalue += this.sec;
|
||||||
|
},
|
||||||
|
chg(e) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.updatevalue();
|
||||||
|
this.$emit('update:modelValue', this.innervalue);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'click',
|
||||||
|
value: this.innervalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._tp {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tp._left {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tp._disabled {
|
||||||
|
color: var(--bg7);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
<template>
|
||||||
|
<view class="_unitedit" :class="{_left:left}">
|
||||||
|
<input type="hidden" :name="name" :value="tvalue" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_unit1'" :value="unit1" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_num12'" :value="num12" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_unit2'" :value="unit2" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_num23'" :value="num23" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_unit3'" :value="unit3" style="display:none;" />
|
||||||
|
|
||||||
|
<ciy-input @change="chg" :disabled="disabled" v-model="unit1" class="_unit" type="text" />
|
||||||
|
<ciy-input @change="chg" :disabled="disabled" v-model="num12" class="_num" type="number" />
|
||||||
|
<ciy-input @change="chg" :disabled="disabled" v-model="unit2" class="_unit" type="text" />
|
||||||
|
<ciy-input @change="chg" :disabled="disabled" v-model="num23" class="_num" type="number" />
|
||||||
|
<ciy-input @change="chg" :disabled="disabled" v-model="unit3" class="_unit" type="text" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._unitedit {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
._unitedit._left {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._unitedit ._unit {
|
||||||
|
width: 3em;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5em 0px;
|
||||||
|
border: 1px solid var(--bg6);
|
||||||
|
background: var(--bg1);
|
||||||
|
border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._unitedit ._num {
|
||||||
|
width: 3em;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 0.3em;
|
||||||
|
padding: 0.3em 0;
|
||||||
|
font-size: 0.7em;
|
||||||
|
border-top: 1px solid var(--bg6);
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid var(--bg6);
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
._unitedit ._num._disabled {
|
||||||
|
background: var(--bg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._unitedit ._unit._disabled {
|
||||||
|
background: var(--bg4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
unit1: '',
|
||||||
|
unit2: '',
|
||||||
|
unit3: '',
|
||||||
|
num12: '',
|
||||||
|
num23: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.setvalue(newD, oldD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.setvalue(newD, oldD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
if (this.unit1) {
|
||||||
|
var num12 = this.toint(this.num12);
|
||||||
|
var num23 = this.toint(this.num23);
|
||||||
|
if (this.unit2 && num12 > 0 && this.unit2 != this.unit1) {
|
||||||
|
if (this.unit3 && num23 > 0 && this.unit3 != this.unit1 && this.unit3 != this.unit2)
|
||||||
|
return this.unit1 + '|' + num12 + '|' + this.unit2 + '|' + num23 + '|' + this.unit3;
|
||||||
|
else
|
||||||
|
return this.unit1 + '|' + num12 + '|' + this.unit2;
|
||||||
|
} else
|
||||||
|
return this.unit1;
|
||||||
|
} else
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setvalue(this.value || this.modelValue);
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue,
|
||||||
|
unit1: this.unit1,
|
||||||
|
unit2: this.unit2,
|
||||||
|
unit3: this.unit3,
|
||||||
|
num12: this.num12,
|
||||||
|
num23: this.num23,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setvalue(val, old) {
|
||||||
|
var us = val.split('|'); // 瓶 瓶|24|盒 瓶|24|盒|20|箱
|
||||||
|
this.unit1 = '';
|
||||||
|
this.unit2 = '';
|
||||||
|
this.unit3 = '';
|
||||||
|
this.num12 = '';
|
||||||
|
this.num23 = '';
|
||||||
|
if (this.unit1 != us[0])
|
||||||
|
this.unit1 = us[0];
|
||||||
|
if (us.length < 3)
|
||||||
|
return;
|
||||||
|
var num = this.toint(us[1]);
|
||||||
|
if (num <= 0 || !us[2])
|
||||||
|
return;
|
||||||
|
if (this.num12 != num)
|
||||||
|
this.num12 = num;
|
||||||
|
if (this.unit2 != us[2])
|
||||||
|
this.unit2 = us[2];
|
||||||
|
if (us.length < 5)
|
||||||
|
return;
|
||||||
|
num = this.toint(us[3]);
|
||||||
|
if (num <= 0 || !us[4])
|
||||||
|
return;
|
||||||
|
if (this.num23 != num)
|
||||||
|
this.num23 = num;
|
||||||
|
if (this.unit3 != us[4])
|
||||||
|
this.unit3 = us[4];
|
||||||
|
},
|
||||||
|
chg(e) {
|
||||||
|
this.$emit('update:modelValue', this.tvalue);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
value: this.tvalue,
|
||||||
|
unit1: this.unit1,
|
||||||
|
unit2: this.unit2,
|
||||||
|
unit3: this.unit3,
|
||||||
|
num12: this.num12,
|
||||||
|
num23: this.num23,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view v-if="listlen==0">
|
||||||
|
<view class="_vlistnodata">
|
||||||
|
<image v-if="nodataimg" :src="nodataimg" mode="widthFix" />
|
||||||
|
<view>{{nodatamsg?nodatamsg:lang('list.nodatamsg')}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_vlistend" v-if="listlen > 0 && page < 0">———— ● ————</view>
|
||||||
|
<view class="_obs_listend"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['show'],
|
||||||
|
props: {
|
||||||
|
listlen: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
nodatamsg: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
nodataimg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.observer = uni.createIntersectionObserver(this, {
|
||||||
|
nativeMode: true
|
||||||
|
});
|
||||||
|
this.observer.relativeToViewport();
|
||||||
|
this.observer.observe('._obs_listend', res => {
|
||||||
|
if (res.intersectionRatio == 1) {
|
||||||
|
this.$emit('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
this.observer.disconnect();
|
||||||
|
},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._vlistnodata {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vlistend {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--txt1);
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._obs_listend {
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<view style="border-radius:5px;transition: all .5s;" :style="{width:pix+'px',height:pix+'px',border:'1px solid ' + color}">
|
||||||
|
<view :style="{opacity: (count >= maxclk?0:1),background:color,marginTop:top+'px',marginLeft:left+'px'}" @tap="chkxw" style="transition: all .5s; width:20px;height:20px;border-radius: 10px;"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//hidden: 加密正确答案,用户答案,验证码,手机号
|
||||||
|
//选择验证方式
|
||||||
|
//是否短信验证
|
||||||
|
//答题验证,请求img图片及加密答案
|
||||||
|
//图片验证,请求img图片及加密答案
|
||||||
|
//滑动验证,请求img图片及加密目标位置
|
||||||
|
//文字验证,请求img图片及加密文字位置
|
||||||
|
//
|
||||||
|
//短信验证码(上面验证后,才能申请发送)
|
||||||
|
var app = getApp();
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group']
|
||||||
|
, props: {
|
||||||
|
pix: {
|
||||||
|
type: Number
|
||||||
|
, default: 100
|
||||||
|
}
|
||||||
|
, maxclk: {
|
||||||
|
type: Number
|
||||||
|
, default: 3
|
||||||
|
}
|
||||||
|
, }
|
||||||
|
, data() {
|
||||||
|
return {
|
||||||
|
count: -1
|
||||||
|
, color: ''
|
||||||
|
, top: 0
|
||||||
|
, left: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
, mounted() {
|
||||||
|
this.chkxw();
|
||||||
|
}
|
||||||
|
, methods: {
|
||||||
|
chkxw(e) {
|
||||||
|
this.count++;
|
||||||
|
if (this.count >= this.maxclk) {
|
||||||
|
this.color = '#21c33c';
|
||||||
|
}else{
|
||||||
|
this.color = '#cc0000';
|
||||||
|
this.top = parseInt(Math.random() * (this.pix - 20));
|
||||||
|
this.left = parseInt(Math.random() * (this.pix - 20));
|
||||||
|
}
|
||||||
|
if (!e)
|
||||||
|
return;
|
||||||
|
this.$emit('change', {
|
||||||
|
ok: this.maxclk <= this.count
|
||||||
|
, top: this.top
|
||||||
|
, left: this.left
|
||||||
|
, detail: e.detail
|
||||||
|
});
|
||||||
|
}
|
||||||
|
, init(){
|
||||||
|
this.count = -1;
|
||||||
|
this.chkxw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,295 @@
|
||||||
|
<template>
|
||||||
|
<template v-for="(item,index) in htmls" :key="index">
|
||||||
|
<view v-if="item.type == 'image'" style="text-align:center;">
|
||||||
|
<image :src="file_stor(item.content)" mode="heightFix" style="max-width:100%;"></image>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'video'" style="text-align:center;">
|
||||||
|
<video :src="file_stor(item.content)" style="width:100%;"></video>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'audio'" style="padding:1em;">
|
||||||
|
<ciy-audio :src="file_stor(item.content)"></ciy-audio>
|
||||||
|
</view>
|
||||||
|
<view v-else v-html="item.content" style="width:100%;position: relative;" :style="{padding:padding}"></view>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
md: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
type: String,
|
||||||
|
default: '0 0.5em'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
htmls: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
md: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.htmls = this.convert(newD);
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
fillmdlines() {
|
||||||
|
|
||||||
|
},
|
||||||
|
convert(markdown) {
|
||||||
|
// #,!,`,@lcr,|表格
|
||||||
|
markdown = markdown || '';
|
||||||
|
if (markdown.substring(0, 4) == '[MD]')
|
||||||
|
markdown = markdown.substring(4).trim();
|
||||||
|
var mds = markdown.split('\n');
|
||||||
|
var htmls = [];
|
||||||
|
var html = '';
|
||||||
|
var ispvs = 0; //0文本,1html,2表格
|
||||||
|
var isol = false;
|
||||||
|
var titnum = [0, 0, 0, 0, 0];
|
||||||
|
var tabalign = {};
|
||||||
|
for (var m in mds) {
|
||||||
|
var mdline = mds[m].trim();
|
||||||
|
if (mdline.length == 0) {
|
||||||
|
if (ispvs == 0)
|
||||||
|
html += '<br/>';
|
||||||
|
if (ispvs == 2) {
|
||||||
|
html += '</table></div>';
|
||||||
|
ispvs = 0;
|
||||||
|
}
|
||||||
|
if (isol) {
|
||||||
|
isol = false;
|
||||||
|
html += '</ol>';
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mdline[0] == '#') { //标题1/2/3
|
||||||
|
if (ispvs == 2)
|
||||||
|
html += '</table></div>';
|
||||||
|
ispvs = 0;
|
||||||
|
if (isol) {
|
||||||
|
isol = false;
|
||||||
|
html += '</ol>';
|
||||||
|
}
|
||||||
|
var cr = mdline.substring(1, 2).toLowerCase();
|
||||||
|
if (mdline.substring(0, 5) == '#####') {
|
||||||
|
oladd(4, titnum);
|
||||||
|
if (mdline.substring(5, 6) == '.')
|
||||||
|
html += '<h5 class="md-h5">' + olnum(4, titnum, '、') + convertcode(mdline.substring(6)) + '</h5>';
|
||||||
|
else if (mdline.substring(5, 6) == ':')
|
||||||
|
html += '<div class="md-content">' + olnum(4, titnum, ' ') + convertcode(mdline.substring(6)) + '</div>';
|
||||||
|
else
|
||||||
|
html += '<h5 class="md-h5">' + convertcode(mdline.substring(5)) + '</h5>';
|
||||||
|
} else if (mdline.substring(0, 4) == '####') {
|
||||||
|
oladd(3, titnum);
|
||||||
|
if (mdline.substring(4, 5) == '.')
|
||||||
|
html += '<h4 class="md-h4">' + olnum(3, titnum, '、') + convertcode(mdline.substring(5)) + '</h4>';
|
||||||
|
else if (mdline.substring(4, 5) == ':')
|
||||||
|
html += '<div class="md-content">' + olnum(3, titnum, ' ') + convertcode(mdline.substring(5)) + '</div>';
|
||||||
|
else
|
||||||
|
html += '<h4 class="md-h4">' + convertcode(mdline.substring(4)) + '</h4>';
|
||||||
|
} else if (mdline.substring(0, 3) == '###') {
|
||||||
|
oladd(2, titnum);
|
||||||
|
if (mdline.substring(3, 4) == '.')
|
||||||
|
html += '<h3 class="md-h3">' + olnum(2, titnum, '、') + convertcode(mdline.substring(4)) + '</h3>';
|
||||||
|
else if (mdline.substring(3, 4) == ':')
|
||||||
|
html += '<div class="md-content">' + olnum(2, titnum, ' ') + convertcode(mdline.substring(4)) + '</div>';
|
||||||
|
else
|
||||||
|
html += '<h3 class="md-h3">' + convertcode(mdline.substring(3)) + '</h3>';
|
||||||
|
} else if (mdline.substring(0, 2) == '##') {
|
||||||
|
oladd(1, titnum);
|
||||||
|
if (mdline.substring(2, 3) == '.')
|
||||||
|
html += '<h2 class="md-h2">' + olnum(1, titnum, '、') + convertcode(mdline.substring(3)) + '</h2>';
|
||||||
|
else if (mdline.substring(2, 3) == ':')
|
||||||
|
html += '<div class="md-content">' + olnum(1, titnum, ' ') + convertcode(mdline.substring(3)) + '</div>';
|
||||||
|
else
|
||||||
|
html += '<h2 class="md-h2">' + convertcode(mdline.substring(2)) + '</h2>';
|
||||||
|
} else {
|
||||||
|
oladd(0, titnum);
|
||||||
|
if (cr == 'c')
|
||||||
|
html += '<h1 class="md-h1" style="text-align:center;">' + convertcode(mdline.substring(2)) + '</h1>';
|
||||||
|
else if (cr == 'r')
|
||||||
|
html += '<h1 class="md-h1" style="text-align:right;">' + convertcode(mdline.substring(2)) + '</h1>';
|
||||||
|
else if (cr == '.')
|
||||||
|
html += '<h1 class="md-h1">' + olnum(0, titnum, '、') + convertcode(mdline.substring(2)) + '</h1>';
|
||||||
|
else if (cr == ':')
|
||||||
|
html += '<div class="md-content">' + olnum(0, titnum, ' ') + convertcode(mdline.substring(2)) + '</div>';
|
||||||
|
else
|
||||||
|
html += '<h1 class="md-h1">' + convertcode(mdline.substring(1)) + '</h1>';
|
||||||
|
}
|
||||||
|
} else if (mdline[0] == '^') { //c居中,r靠右
|
||||||
|
if (ispvs == 2)
|
||||||
|
html += '</table></div>';
|
||||||
|
ispvs = 0;
|
||||||
|
var cr = mdline.substring(1, 2).toLowerCase();
|
||||||
|
if (cr == 'c')
|
||||||
|
html += '<div class="md-content" style="text-align:center;text-indent: 0;">' + convertcode(mdline.substring(2)) + '</div>';
|
||||||
|
else if (cr == 'r')
|
||||||
|
html += '<div class="md-content" style="text-align:right;margin-right:1em;">' + convertcode(mdline.substring(2)) + '</div>';
|
||||||
|
else if (mdline[1] == '.') {
|
||||||
|
if (!isol) {
|
||||||
|
isol = true;
|
||||||
|
html += '<ol>';
|
||||||
|
}
|
||||||
|
html += '<li style="line-height: 1.5em;padding: 0.5em 0;">' + convertcode(mdline.substring(2)) + '</li>';
|
||||||
|
} else
|
||||||
|
html += '<div class="md-content">' + mdline.substring(1) + '</div>';
|
||||||
|
|
||||||
|
} else if (mdline[0] == '!') { //图片、视频、音频
|
||||||
|
if (ispvs == 2)
|
||||||
|
html += '</table></div>';
|
||||||
|
ispvs = 0;
|
||||||
|
var mis = mdline.split('|');
|
||||||
|
var url = mis[0];
|
||||||
|
url = this.file_stor(url.substring(1));
|
||||||
|
var ind = url.indexOf('?');
|
||||||
|
var match;
|
||||||
|
if (ind > -1) {
|
||||||
|
match = url.substring(0, ind).match(/\.([^./]+)$/);
|
||||||
|
} else
|
||||||
|
match = url.match(/\.([^./]+)$/);
|
||||||
|
var exurl = match ? match[1] : '';
|
||||||
|
htmls.push({
|
||||||
|
type: 'text',
|
||||||
|
content: html
|
||||||
|
});
|
||||||
|
html = '';
|
||||||
|
if (exurl == 'mp4' || exurl == 'm3u8') {
|
||||||
|
var alt = '';
|
||||||
|
if (mis[1])
|
||||||
|
alt = ' alt="' + mis[1].replace('"', "") + '"';
|
||||||
|
htmls.push({
|
||||||
|
type: 'video',
|
||||||
|
content: url
|
||||||
|
});
|
||||||
|
} else if (exurl == 'mp3') {
|
||||||
|
var alt = '';
|
||||||
|
if (mis[1])
|
||||||
|
alt = ' alt="' + mis[1].replace('"', "") + '"';
|
||||||
|
htmls.push({
|
||||||
|
type: 'audio',
|
||||||
|
content: url
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var alt = '';
|
||||||
|
if (mis[1])
|
||||||
|
alt = ' alt="' + mis[1].replace('"', "") + '"';
|
||||||
|
htmls.push({
|
||||||
|
type: 'image',
|
||||||
|
content: url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (mdline[0] == '|' && mdline.substring(mdline.length - 1) == '|') { //表格
|
||||||
|
var trs = mdline.substring(1, mdline.length - 1).split('|');
|
||||||
|
if (ispvs == 0) {
|
||||||
|
html += '<div class="md-table-div"><table class="md-table"><tr style="font-weight:bold;">';
|
||||||
|
for (var i in trs) {
|
||||||
|
var align = 'left';
|
||||||
|
if (trs[i].substring(trs[i].length - 1) == ':') {
|
||||||
|
align = 'right';
|
||||||
|
trs[i] = trs[i].substring(0, trs[i].length - 1);
|
||||||
|
}
|
||||||
|
if (trs[i].substring(0, 1) == ':') {
|
||||||
|
align = 'center';
|
||||||
|
trs[i] = trs[i].substring(1);
|
||||||
|
}
|
||||||
|
tabalign[i] = align;
|
||||||
|
html += '<td style="text-align:' + align + ';">' + convertcode(trs[i].trim()) + '</td>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html += '<tr>';
|
||||||
|
for (var i in trs) {
|
||||||
|
html += '<td style="text-align:' + tabalign[i] + ';">' + convertcode(trs[i].trim()) + '</td>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += '</tr>';
|
||||||
|
ispvs = 2;
|
||||||
|
} else if (mdline[0] == '<') { //原始HTML
|
||||||
|
if (ispvs == 2)
|
||||||
|
html += '</table></div>';
|
||||||
|
ispvs = 1;
|
||||||
|
html += mdline;
|
||||||
|
} else {
|
||||||
|
if (ispvs == 2)
|
||||||
|
html += '</table></div>';
|
||||||
|
ispvs = 0;
|
||||||
|
html += '<div class="md-content">' + convertcode(mdline) + '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (html) {
|
||||||
|
if (ispvs == 2)
|
||||||
|
html += '</table></div>';
|
||||||
|
if (isol) {
|
||||||
|
isol = false;
|
||||||
|
html += '</ol>';
|
||||||
|
}
|
||||||
|
htmls.push({
|
||||||
|
type: 'text',
|
||||||
|
content: html
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return htmls;
|
||||||
|
|
||||||
|
function oladd(idx, olnum) {
|
||||||
|
olnum[idx]++;
|
||||||
|
for (var i = idx + 1; i < olnum.length; i++)
|
||||||
|
olnum[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function olnum(idx, olnum, end) {
|
||||||
|
for (var i = 0; i <= idx; i++) {
|
||||||
|
if (olnum[i] == 0)
|
||||||
|
continue;
|
||||||
|
var ols = [];
|
||||||
|
for (var j = i; j <= idx; j++) {
|
||||||
|
ols.push(olnum[j]);
|
||||||
|
}
|
||||||
|
return ols.join('.') + end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertcode(md) {
|
||||||
|
var bcode = false;
|
||||||
|
md = md.replace(/ /g, ' ');
|
||||||
|
while (true) {
|
||||||
|
var ind = md.indexOf('`');
|
||||||
|
if (ind == -1)
|
||||||
|
break;
|
||||||
|
var el = '<span class="md-code">';
|
||||||
|
if (bcode) {
|
||||||
|
bcode = false;
|
||||||
|
el = '</span>';
|
||||||
|
} else
|
||||||
|
bcode = true;
|
||||||
|
md = md.substring(0, ind) + el + md.substring(ind + 1);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
var ind = md.indexOf('**');
|
||||||
|
if (ind == -1)
|
||||||
|
break;
|
||||||
|
var el = '<span style="font-weight:bold;">';
|
||||||
|
if (bcode) {
|
||||||
|
bcode = false;
|
||||||
|
el = '</span>';
|
||||||
|
} else
|
||||||
|
bcode = true;
|
||||||
|
md = md.substring(0, ind) + el + md.substring(ind + 2);
|
||||||
|
}
|
||||||
|
if (bcode)
|
||||||
|
md += '</span>';
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,359 @@
|
||||||
|
<template>
|
||||||
|
<view style="width:100%;position: relative;">
|
||||||
|
<view style="min-height:10em;border:1px solid #dddddd;margin:0;background:#fafafa;">
|
||||||
|
<view v-for="(item,index) in mdlines" :key="index" @tap="rightmenu(index)" :class="item.vms">
|
||||||
|
<view v-if="item.cls == 'md-pic'">
|
||||||
|
<image :src="item.content" style="width:100%;display:block;" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
<view v-else :class="item.cls">{{item.content}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_edittip" style="top:-0.5em;">编辑区</view>
|
||||||
|
<input type="hidden" :name="name" :value="valuetxt" style="display:none;" />
|
||||||
|
<view style="position:relative;margin:0;border:1px solid #dddddd;">
|
||||||
|
<textarea :name="name + '_unup'" class="_textarea" v-model="etext" :fixed="true" auto-height maxlength="-1" />
|
||||||
|
<view style="display:flex;align-items: center;background:#ffffff;border-top:1px solid #dddddd;">
|
||||||
|
<view class="_icon _photo" @tap="upimg"></view>
|
||||||
|
<view style="position: absolute;bottom:0;left:4em;font-size:0.6em;color:#cccccc;">{{imgtip}}</view>
|
||||||
|
<view style="flex:1;text-align:right;padding:0 1em;">首行样式</view>
|
||||||
|
<ciy-picker name="linecls" v-model="elinecls" :range="styles" style="width:8em;"></ciy-picker>
|
||||||
|
<view class="_icon _uptxt" @tap="uptxt"></view>
|
||||||
|
</view>
|
||||||
|
<view class="_edittip" style="top:-1.5em;">录入区</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//下拉选择
|
||||||
|
//多行文本,每一行按照选择生成。
|
||||||
|
//按钮 上箭头,上传
|
||||||
|
//每段长按,删除、编辑、插入(在上)。
|
||||||
|
|
||||||
|
|
||||||
|
// 所见即所得的结果
|
||||||
|
// 添加文字段落
|
||||||
|
// 添加一张或多张图片
|
||||||
|
var app = getApp();
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group']
|
||||||
|
, props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
, value: {
|
||||||
|
type: String
|
||||||
|
, default: ''
|
||||||
|
}
|
||||||
|
, imgact: {
|
||||||
|
type: String
|
||||||
|
, default: 'cp|1280|60'
|
||||||
|
}
|
||||||
|
, uploadurl: {
|
||||||
|
type: String
|
||||||
|
, default: ''
|
||||||
|
}
|
||||||
|
, }
|
||||||
|
, data() {
|
||||||
|
return {
|
||||||
|
Gvalue: false
|
||||||
|
, valuetxt: '' //最终结果
|
||||||
|
, valuelines: [] //带格式的原始行
|
||||||
|
, mdlines: [] //显示的行
|
||||||
|
, eimgs: ''
|
||||||
|
, etext: ''
|
||||||
|
, imgtip: ''
|
||||||
|
, elinecls: 'md-content'
|
||||||
|
, styles: [{
|
||||||
|
id: 'md-content'
|
||||||
|
, pre: ''
|
||||||
|
, name: '正文'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-h1'
|
||||||
|
, pre: '#'
|
||||||
|
, name: '大标题'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-h1 _center'
|
||||||
|
, pre: '#c'
|
||||||
|
, name: '大标题居中'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-h1 _right'
|
||||||
|
, pre: '#r'
|
||||||
|
, name: '大标题靠右'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-h2'
|
||||||
|
, pre: '##'
|
||||||
|
, name: '二号标题 [n]'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-h3'
|
||||||
|
, pre: '###'
|
||||||
|
, name: '三号标题 [n.m]'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-h4'
|
||||||
|
, pre: '####'
|
||||||
|
, name: '四号标题 [n.m.k]'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-content _center'
|
||||||
|
, pre: '^c'
|
||||||
|
, name: '正文居中'
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
id: 'md-content _right'
|
||||||
|
, pre: '^r'
|
||||||
|
, name: '正文靠右'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
, watch: {
|
||||||
|
value(newD, oldD) {
|
||||||
|
if (this.Gvalue)
|
||||||
|
this.Gvalue = false;
|
||||||
|
else {
|
||||||
|
this.valuetxt = newD;
|
||||||
|
this.fillmdlines();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, mounted() {
|
||||||
|
this.valuetxt = this.value || '';
|
||||||
|
this.fillmdlines();
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name
|
||||||
|
, from: 'create'
|
||||||
|
, value: this.valuetxt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
, methods: {
|
||||||
|
fillmdlines() {
|
||||||
|
var markdown = this.valuetxt;
|
||||||
|
if (markdown.substr(0, 4) == '[MD]')
|
||||||
|
markdown = markdown.substr(4).trim();
|
||||||
|
var mds = markdown.split('\n');
|
||||||
|
var mdls = [];
|
||||||
|
for (var m in mds) {
|
||||||
|
if (mds[m].trim().length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var mdl = {};
|
||||||
|
if (mds[m][0] == '#') { //标题1/2/3
|
||||||
|
if (mds[m].substr(0, 4) == '####') {
|
||||||
|
mdl.cls = 'md-h4';
|
||||||
|
mdl.content = 'n.m.k、' + mds[m].substr(4);
|
||||||
|
} else if (mds[m].substr(0, 3) == '###') {
|
||||||
|
mdl.cls = 'md-h3';
|
||||||
|
mdl.content = 'n.m、' + mds[m].substr(3);
|
||||||
|
} else if (mds[m].substr(0, 2) == '##') {
|
||||||
|
mdl.cls = 'md-h2';
|
||||||
|
mdl.content = 'n、' + mds[m].substr(2);
|
||||||
|
} else if (mds[m].substr(1, 1) == 'c') {
|
||||||
|
mdl.cls = 'md-h1 _center';
|
||||||
|
mdl.content = mds[m].substr(2);
|
||||||
|
} else if (mds[m].substr(1, 1) == 'r') {
|
||||||
|
mdl.cls = 'md-h1 _right';
|
||||||
|
mdl.content = mds[m].substr(2);
|
||||||
|
} else {
|
||||||
|
mdl.cls = 'md-h1';
|
||||||
|
mdl.content = mds[m].substr(1);
|
||||||
|
}
|
||||||
|
} else if (mds[m][0] == '@') { //c居中,r靠右
|
||||||
|
if (mds[m][1] == 'c') {
|
||||||
|
mdl.cls = 'md-content _center';
|
||||||
|
mdl.content = mds[m].substr(2);
|
||||||
|
} else if (mds[m][1] == 'r') {
|
||||||
|
mdl.cls = 'md-content _right';
|
||||||
|
mdl.content = mds[m].substr(2);
|
||||||
|
} else {
|
||||||
|
mdl.cls = 'md-content';
|
||||||
|
mdl.content = mds[m].substr(1);
|
||||||
|
}
|
||||||
|
} else if (mds[m][0] == '!') { //图片
|
||||||
|
var mis = mds[m].split('|');
|
||||||
|
var url = mis[0];
|
||||||
|
url = url.substring(1);
|
||||||
|
var alt = '';
|
||||||
|
if (mis[1])
|
||||||
|
alt = ' alt="' + mis[1].replace('"', "") + '"';
|
||||||
|
if (url.substr(0, 4).toLowerCase() != 'http')
|
||||||
|
url = this.file_stor(url);//xx
|
||||||
|
mdl.cls = 'md-pic';
|
||||||
|
mdl.content = url;
|
||||||
|
} else if (mds[m][0] == '_') {} else {
|
||||||
|
mdl.cls = 'md-content';
|
||||||
|
mdl.content = mds[m];
|
||||||
|
}
|
||||||
|
if (mdl.cls) {
|
||||||
|
mdl.idx = m;
|
||||||
|
mdl.vms = '';
|
||||||
|
mdls.push(mdl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.mdlines = mdls;
|
||||||
|
this.valuetxt = '[MD]' + markdown;
|
||||||
|
}
|
||||||
|
, rightmenu(idx) {
|
||||||
|
for (var i in this.mdlines)
|
||||||
|
this.mdlines[i].vms = '';
|
||||||
|
this.mdlines[idx].vms = '_sel';
|
||||||
|
var menus = [];
|
||||||
|
menus.push({
|
||||||
|
name: '插入'
|
||||||
|
, url: 'ins'
|
||||||
|
});
|
||||||
|
if (this.mdlines[idx].cls != 'md-pic') {
|
||||||
|
menus.push({
|
||||||
|
name: '编辑'
|
||||||
|
, url: 'edit'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
menus.push({
|
||||||
|
name: '删除'
|
||||||
|
, url: 'del'
|
||||||
|
});
|
||||||
|
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: menus.map(item => item.name)
|
||||||
|
, success: res => {
|
||||||
|
var menu = menus[res.tapIndex];
|
||||||
|
if (menu.url == 'del') {
|
||||||
|
app.askmsg('确认删除?', () => {
|
||||||
|
var ls = this.valuetxt.split('\n');
|
||||||
|
ls.splice(this.mdlines[idx].idx, 1);
|
||||||
|
this.valuetxt = ls.join('\n');
|
||||||
|
this.fillmdlines();
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name
|
||||||
|
, from: 'delete'
|
||||||
|
, value: this.valuetxt
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (menu.url == 'edit') {
|
||||||
|
this.etext = this.mdlines[idx].content;
|
||||||
|
this.elinecls = this.mdlines[idx].cls;
|
||||||
|
this.mdlines[idx].vms = '_edit';
|
||||||
|
} else if (menu.url == 'ins') {
|
||||||
|
this.mdlines[idx].vms = '_ins';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, complete: res => {
|
||||||
|
if (this.mdlines[idx].vms == '_sel')
|
||||||
|
this.mdlines[idx].vms = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
, doedit(pre, txt) {
|
||||||
|
var lineidx = -1;
|
||||||
|
var op = '_append';
|
||||||
|
for (var i in this.mdlines) {
|
||||||
|
if (this.mdlines[i].vms) {
|
||||||
|
lineidx = this.mdlines[i].idx;
|
||||||
|
op = this.mdlines[i].vms;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ls = this.valuetxt.split('\n');
|
||||||
|
if (op == '_append')
|
||||||
|
ls.push(pre + txt);
|
||||||
|
else if (op == '_edit') {
|
||||||
|
ls.splice(lineidx, 1, pre + txt);
|
||||||
|
} else {
|
||||||
|
ls.splice(lineidx, 0, pre + txt);
|
||||||
|
}
|
||||||
|
this.valuetxt = ls.join('\n');
|
||||||
|
this.fillmdlines();
|
||||||
|
}
|
||||||
|
, uptxt() {
|
||||||
|
var txt = this.etext;
|
||||||
|
if (txt == '')
|
||||||
|
return app.toast('请填写内容');
|
||||||
|
|
||||||
|
var pre = '';
|
||||||
|
for (var i = 0; i < this.styles.length; i++) {
|
||||||
|
if (this.styles[i].id == this.elinecls)
|
||||||
|
pre = this.styles[i].pre;
|
||||||
|
}
|
||||||
|
this.etext = '';
|
||||||
|
this.doedit(pre, txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name
|
||||||
|
, from: 'uptxt'
|
||||||
|
, pre: pre
|
||||||
|
, content: txt
|
||||||
|
, value: this.valuetxt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
, upimg: function(b) {
|
||||||
|
if (this.Grunning)
|
||||||
|
return app.toast('上传中...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._edittip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0.5em;
|
||||||
|
background: #fffad7;
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
font-size: 0.6em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
line-height: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ins {
|
||||||
|
border-top: 3px solid #cc0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
._sel {
|
||||||
|
border: 1px solid #cc0000;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._edit {
|
||||||
|
border: 2px solid #009000;
|
||||||
|
}
|
||||||
|
|
||||||
|
._textarea {
|
||||||
|
display: block;
|
||||||
|
padding: 0.5em;
|
||||||
|
min-height: 5em;
|
||||||
|
background: #ffffff;
|
||||||
|
line-height:1.2em;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
._photo {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQyOC41NzYgMzc4LjM2OGE1MC4xNzYgNTAuMTc2IDAgMSAwLTEwMC4zNTIgMCA1MC4xNzYgNTAuMTc2IDAgMCAwIDEwMC4zNTIgMG0wIDB6IG0xNjYuOTQ0IDI1Ni40NDhoNDEuNTA0di00MS41MDRjMC0zMC41NiAxOC4zMzYtNTYuOCA0NC41MTItNjguNzM2bC02Ljk0NC0yMy44MDh2LTEuNjY0aDAuMDY0bC00NS40MDgtMTM3LjE4NC0xNTguNDk2IDIwNC41MTItNDIuNDk2LTcxLjk2OC0xNjguNTc2IDE3MC4xMTJoMjc2LjA5NmE3NS4zNiA3NS4zNiAwIDAgMSA1OS43NDQtMjkuNzZtMjY3LjcxMi0zNjEuNjY0YTExMi43MDQgMTEyLjcwNCAwIDAgMC0xMTIuMzg0LTExMi4zODRIMjczLjE1MmExMTIuNzA0IDExMi43MDQgMCAwIDAtMTEyLjM4NCAxMTIuMzg0djQ3Ny42NjRhMTEyLjcwNCAxMTIuNzA0IDAgMCAwIDExMi4zODQgMTEyLjM4NGgzMzcuMTg0di0wLjAzMmwwLjEyOCAwLjAzMmEyMS4wODggMjEuMDg4IDAgMSAwIDAtNDIuMTc2bC0wLjEyOCAwLjAzMnYtMC4wMzJIMjczLjE1MmE3MC4zMDQgNzAuMzA0IDAgMCAxLTcwLjI0LTcwLjI0VjI3My4xNTJjMC0zOC43NTIgMzEuNDg4LTcwLjI0IDcwLjI0LTcwLjI0aDQ3Ny42NjRjMzguNzUyIDAgNzAuMjQgMzEuNDg4IDcwLjI0IDcwLjI0djMzNS4xMzZjMCAwLjI1Ni0wLjEyOCAwLjQ0OC0wLjEyOCAwLjY3MmEyMS4wODggMjEuMDg4IDAgMSAwIDQyLjE3NiAwbC0wLjA2NC0wLjI1NmgwLjE5MlYyNzMuMTUybS0yMS44ODggNDE2LjIyNGgtMTA3LjQyNHYtMTA3LjQyNGEyMS4wODggMjEuMDg4IDAgMSAwLTQyLjE3NiAwdjEwNy40MjRINTg0LjMyYTIxLjA4OCAyMS4wODggMCAxIDAgMCA0Mi4xNzZoMTA3LjQyNHYxMDcuNDI0YTIxLjA4OCAyMS4wODggMCAxIDAgNDIuMTc2IDBWNzMxLjUyaDEwNy40MjRhMjEuMDg4IDIxLjA4OCAwIDEgMCAwLTQyLjE0NCIgZmlsbD0iIzQ4OENDQiI+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
|
||||||
|
._uptxt {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTUxMiAxMDIuNGM1NC42MTMzMzMgMCAxMDYuOTM5NzMzIDExLjM2NjQgMTU3LjAxMzMzMyAzMS44NDY0IDQ3Ljc4NjY2NyAyMC40OCA5My4yODY0IDUwLjA3MzYgMTMxLjk5MzYgODguNzQ2NjY3IDM4LjY3MzA2NyAzNi40MjAyNjcgNjguMjY2NjY3IDgxLjkyIDg4Ljc0NjY2NyAxMzEuOTkzNiAyMC40OCA1MC4wNzM2IDMxLjg0NjQgMTAyLjQgMzEuODQ2NCAxNTcuMDEzMzMzIDAgNTQuNjEzMzMzLTExLjM2NjQgMTA2LjkzOTczMy0zMS44NDY0IDE1Ny4wMTMzMzMtMjAuNDggNDcuNzg2NjY3LTUwLjA3MzYgOTMuMjg2NC04OC43NDY2NjcgMTMxLjk5MzYtMzYuNDIwMjY3IDM4LjY3MzA2Ny04MS45MiA2OC4yNjY2NjctMTMxLjk5MzYgODguNzQ2NjY3LTUwLjA3MzYgMjAuNDgtMTAyLjQgMzEuODQ2NC0xNTcuMDEzMzMzIDMxLjg0NjQtNTQuNjEzMzMzIDAtMTA2LjkzOTczMy0xMS4zNjY0LTE1Ny4wMTMzMzMtMzEuODQ2NC00Ny43ODY2NjctMjAuNDgtOTMuMjg2NC01MC4wNzM2LTEzMS45OTM2LTg4Ljc0NjY2Ny0zOC42NzMwNjctMzYuNDIwMjY3LTY4LjI2NjY2Ny04MS45Mi04OC43NDY2NjctMTMxLjk5MzYtMjAuNDgtNTAuMDczNi0zMS44NDY0LTEwMi40LTMxLjg0NjQtMTU3LjAxMzMzMyAwLTU0LjYxMzMzMyAxMS4zNjY0LTEwNi45Mzk3MzMgMzEuODQ2NC0xNTcuMDEzMzMzIDIwLjQ4LTQ3Ljc4NjY2NyA1MC4wNzM2LTkzLjI4NjQgODguNzQ2NjY3LTEzMS45OTM2IDM4LjcwNzItMzguNjczMDY3IDgxLjkyLTY4LjI2NjY2NyAxMzEuOTkzNi04OC43NDY2NjcgNTAuMDczNi0yMC40OCAxMDIuNC0zMS44NDY0IDE1Ny4wMTMzMzMtMzEuODQ2NHpNMjk1LjA4MjY2NyA1OTYuNjE2NTMzbC0yMS43MDg4IDk0LjkyNDggMzUuMjI1NiAzNS4yMjU2IDk0LjkyNDgtMjEuNzA4OC0xMDguNDQxNi0xMDguNDQxNnogbTIwOS4zNzM4NjYtMjg3LjA2MTMzM2wtMTc4Ljg1ODY2NiAxNzguODkyOGMtNC43NDQ1MzMgMzAuMTczODY3IDEuODQzMiA1MC4zMTI1MzMgMzIuOTcyOCA0Ny43ODY2NjdsMTIzLjkwNC0xMjAuMDgxMDY3IDEwLjk5MDkzMyAxMC45OTA5MzMtMTIwLjcyOTYgMTE2Ljk0MDhjNy41MDkzMzMgNDkuMDQ5NiAzOS41OTQ2NjcgNjguMjY2NjY3IDgyLjY3MDkzMyA3NC4yMDU4NjctNS42NjYxMzMgMzQuMjY5ODY3IDMuNDQ3NDY3IDU1LjAyMjkzMyA0NS45MDkzMzQgNDUuOTA5MzMzbDE3OC44NTg2NjYtMTc4Ljg5MjgtMTc1LjcxODQtMTc1Ljc1MjUzM3ogbTU1LjYzNzMzNC01NS4yOTZMNTIzLjk0NjY2NyAyOTAuMzcyMjY3bDE3NS43NTI1MzMgMTc1LjcxODQgMzYuMTQ3Mi0zNi4xNDcyYzE5Ljc5NzMzMy0xOS43OTczMzMgMTkuNzk3MzMzLTUyLjQ5NzA2NyAwLTcyLjI5NDRsLTEwMy40MjQtMTAzLjQyNGE1MS40Mzg5MzMgNTEuNDM4OTMzIDAgMCAwLTcyLjMyODUzMyAweiIgZmlsbD0iIzg1QzJGRiI+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon {
|
||||||
|
width: 3em;
|
||||||
|
height: 3em;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,262 @@
|
||||||
|
<template>
|
||||||
|
<view @touchmove.prevent class="_movcontain" :style="'width:'+width+';height:'+height+'; overflow: hidden;'">
|
||||||
|
<view :style="{width:cwidth+'px',height:cheight+'px',transition:trans, transformOrigin:'0 0', transform: 'translate('+mapx+'px,'+mapy+'px) scale('+scale+')'}" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
|
||||||
|
<image :src="src" style="width:100%;height:100%;" />
|
||||||
|
<view v-for="(item,index) in boxs" :key="index" class="abs t0 l0" :style="{zIndex:item.z,transform: 'translate('+item.x+'px,'+item.y+'px)'}" @tap="boxtap(index)" @touchstart="boxhandleTouchStart($event, index)" @touchmove="boxhandleTouchMove($event, index)" @touchend="boxhandleTouchEnd($event, index)">
|
||||||
|
<slot :box="item"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change', 'boxclick'],
|
||||||
|
props: {
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '100%'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '100vw'
|
||||||
|
},
|
||||||
|
boxmove: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
src: '',
|
||||||
|
containwidth: 0,
|
||||||
|
containheight: 0,
|
||||||
|
cwidth: 0,
|
||||||
|
cheight: 0,
|
||||||
|
trans: '',
|
||||||
|
|
||||||
|
scale: 1,
|
||||||
|
minScale: 0.5,
|
||||||
|
maxScale: 5,
|
||||||
|
mapx: 0,
|
||||||
|
mapy: 0,
|
||||||
|
last: {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
},
|
||||||
|
isDragging: false, // 是否正在拖拽
|
||||||
|
initialDistance: 0, // 初始双指距离
|
||||||
|
initialScale: 1, // 初始缩放比例
|
||||||
|
|
||||||
|
boxisDragging: false, // 是否正在拖拽
|
||||||
|
boxindex: 0,
|
||||||
|
boxs: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
Setbox(boxs) {
|
||||||
|
this.zindex = 0;
|
||||||
|
this.boxs = boxs;
|
||||||
|
for (var i = 0; i < this.boxs.length; i++) {
|
||||||
|
if (this.boxs[i].z === undefined)
|
||||||
|
continue;
|
||||||
|
if (this.boxs[i].z > this.zindex)
|
||||||
|
this.zindex = this.boxs[i].z;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Getbox() {
|
||||||
|
return this.objclone(this.boxs);
|
||||||
|
},
|
||||||
|
Setmap(opn) {
|
||||||
|
this.src = this.file_stor(opn.src);
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.src = this.src.replace('http://', 'https://');
|
||||||
|
// #endif
|
||||||
|
this.getrect('._movcontain').then(res => {
|
||||||
|
this.containwidth = res.width;
|
||||||
|
this.containheight = res.height;
|
||||||
|
});
|
||||||
|
uni.getImageInfo({
|
||||||
|
src: this.src,
|
||||||
|
success: res => {
|
||||||
|
this.cwidth = res.width;
|
||||||
|
this.cheight = res.height;
|
||||||
|
this.mapx = -this.toint(opn.x);
|
||||||
|
this.mapy = -this.toint(opn.y);
|
||||||
|
this.scale = opn.scale;
|
||||||
|
},
|
||||||
|
fail: res => {
|
||||||
|
console.log('getImageInfo err', res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleTouchStart(e) {
|
||||||
|
this.trans = '';
|
||||||
|
this.pagenoscroll(true);
|
||||||
|
if (e.touches.length === 1) {
|
||||||
|
// 单指触摸
|
||||||
|
this.isDragging = true
|
||||||
|
this.last.x = e.touches[0].clientX
|
||||||
|
this.last.y = e.touches[0].clientY
|
||||||
|
} else if (e.touches.length === 2) {
|
||||||
|
// 双指触摸
|
||||||
|
this.isDragging = false
|
||||||
|
const x1 = e.touches[0].clientX
|
||||||
|
const y1 = e.touches[0].clientY
|
||||||
|
const x2 = e.touches[1].clientX
|
||||||
|
const y2 = e.touches[1].clientY
|
||||||
|
this.initialDistance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
|
||||||
|
this.initialScale = this.scale
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleTouchMove(e) {
|
||||||
|
if (e.touches.length === 1 && this.isDragging) {
|
||||||
|
// 单指移动 - 平移
|
||||||
|
const deltaX = e.touches[0].clientX - this.last.x
|
||||||
|
const deltaY = e.touches[0].clientY - this.last.y
|
||||||
|
|
||||||
|
this.last.x = e.touches[0].clientX
|
||||||
|
this.last.y = e.touches[0].clientY
|
||||||
|
// 计算新的位置
|
||||||
|
let newTranslateX = this.mapx + deltaX
|
||||||
|
let newTranslateY = this.mapy + deltaY
|
||||||
|
|
||||||
|
this.mapx = newTranslateX
|
||||||
|
this.mapy = newTranslateY
|
||||||
|
this.last.x = e.touches[0].clientX
|
||||||
|
this.last.y = e.touches[0].clientY
|
||||||
|
} else if (e.touches.length === 2) {
|
||||||
|
// 双指移动 - 缩放
|
||||||
|
const x1 = e.touches[0].clientX
|
||||||
|
const y1 = e.touches[0].clientY
|
||||||
|
const x2 = e.touches[1].clientX
|
||||||
|
const y2 = e.touches[1].clientY
|
||||||
|
const currentDistance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
|
||||||
|
|
||||||
|
if (this.initialDistance > 0) {
|
||||||
|
let newScale = this.initialScale * (currentDistance / this.initialDistance)
|
||||||
|
newScale = Math.min(Math.max(newScale, this.minScale), this.maxScale)
|
||||||
|
|
||||||
|
// 计算缩放中心点
|
||||||
|
const centerX = (x1 + x2) / 2
|
||||||
|
const centerY = (y1 + y2) / 2
|
||||||
|
|
||||||
|
// 调整位置使缩放中心保持稳定
|
||||||
|
const ratio = (newScale - this.scale) / this.scale
|
||||||
|
this.mapx -= (centerX - this.mapx) * ratio
|
||||||
|
this.mapy -= (centerY - this.mapy) * ratio
|
||||||
|
|
||||||
|
this.scale = newScale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleTouchEnd() {
|
||||||
|
this.trans = 'transform 0.5s';
|
||||||
|
this.pagenoscroll(false);
|
||||||
|
this.isDragging = false
|
||||||
|
this.initialDistance = 0
|
||||||
|
// 缩放结束后检查边界
|
||||||
|
const containerWidth = this.containwidth
|
||||||
|
const containerHeight = this.containheight
|
||||||
|
const imageWidth = this.cwidth * this.scale
|
||||||
|
const imageHeight = this.cheight * this.scale
|
||||||
|
|
||||||
|
// X轴边界检查
|
||||||
|
const maxX = containerWidth - imageWidth
|
||||||
|
const minX = 0
|
||||||
|
if (this.mapx < maxX / 2) {
|
||||||
|
if (this.mapx < maxX)
|
||||||
|
this.mapx = maxX
|
||||||
|
} else {
|
||||||
|
if (this.mapx > minX)
|
||||||
|
this.mapx = minX
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y轴边界检查
|
||||||
|
const maxY = containerHeight - imageHeight
|
||||||
|
const minY = 0
|
||||||
|
if (this.mapy < maxY / 2) {
|
||||||
|
if (this.mapy < maxY)
|
||||||
|
this.mapy = maxY
|
||||||
|
} else {
|
||||||
|
if (this.mapy > minY)
|
||||||
|
this.mapy = minY
|
||||||
|
}
|
||||||
|
this.$emit('change', {
|
||||||
|
x: this.mapx,
|
||||||
|
y: this.mapy,
|
||||||
|
sacle: this.sacle,
|
||||||
|
index: -1,
|
||||||
|
boxs: this.boxs
|
||||||
|
});
|
||||||
|
},
|
||||||
|
boxtap(index) {
|
||||||
|
this.$emit('boxclick', {
|
||||||
|
index: index,
|
||||||
|
boxs: this.boxs
|
||||||
|
});
|
||||||
|
},
|
||||||
|
boxhandleTouchStart(e, index) {
|
||||||
|
if (!this.boxmove)
|
||||||
|
return;
|
||||||
|
e.stopPropagation()
|
||||||
|
this.pagenoscroll(true);
|
||||||
|
this.boxisDragging = true
|
||||||
|
this.boxindex = index;
|
||||||
|
this.last.x = e.touches[0].clientX
|
||||||
|
this.last.y = e.touches[0].clientY
|
||||||
|
if (typeof(this.boxs[this.boxindex].z) == 'number')
|
||||||
|
this.boxs[this.boxindex].z = ++this.zindex;
|
||||||
|
},
|
||||||
|
boxhandleTouchMove(e, index) {
|
||||||
|
e.stopPropagation()
|
||||||
|
if (!this.boxisDragging)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 单指移动 - 平移
|
||||||
|
const deltaX = (e.touches[0].clientX - this.last.x) / this.scale
|
||||||
|
const deltaY = (e.touches[0].clientY - this.last.y) / this.scale
|
||||||
|
|
||||||
|
this.last.x = e.touches[0].clientX
|
||||||
|
this.last.y = e.touches[0].clientY
|
||||||
|
// 计算新的位置
|
||||||
|
let newTranslateX = this.boxs[this.boxindex].x + deltaX
|
||||||
|
let newTranslateY = this.boxs[this.boxindex].y + deltaY
|
||||||
|
|
||||||
|
this.boxs[this.boxindex].x = newTranslateX
|
||||||
|
this.boxs[this.boxindex].y = newTranslateY
|
||||||
|
this.last.x = e.touches[0].clientX
|
||||||
|
this.last.y = e.touches[0].clientY
|
||||||
|
},
|
||||||
|
boxhandleTouchEnd(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
this.pagenoscroll(false);
|
||||||
|
this.boxisDragging = false
|
||||||
|
if (this.boxs[this.boxindex].x < 0)
|
||||||
|
this.boxs[this.boxindex].x = 0;
|
||||||
|
if (this.boxs[this.boxindex].y < 0)
|
||||||
|
this.boxs[this.boxindex].y = 0;
|
||||||
|
const maxx = this.cwidth - this.toint(this.boxs[this.boxindex].w);
|
||||||
|
const maxy = this.cheight - this.toint(this.boxs[this.boxindex].h);
|
||||||
|
if (this.boxs[this.boxindex].x > maxx)
|
||||||
|
this.boxs[this.boxindex].x = maxx;
|
||||||
|
if (this.boxs[this.boxindex].y > maxy)
|
||||||
|
this.boxs[this.boxindex].y = maxy;
|
||||||
|
|
||||||
|
this.$emit('change', {
|
||||||
|
x: this.mapx,
|
||||||
|
y: this.mapy,
|
||||||
|
sacle: this.sacle,
|
||||||
|
index: this.boxindex,
|
||||||
|
boxs: this.boxs
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
<template>
|
||||||
|
<ciy-anipop v-model="popsh" maskbg="#00000055" @change="popclose">
|
||||||
|
<view class="_menu">
|
||||||
|
<view class="_title" v-if="title">{{title}}</view>
|
||||||
|
<slot name="list" :data="{items:items, rowcount:rowcount}">
|
||||||
|
<view class="_list" :class="rowcount<=1?'_flex':'_grid'" :style="'grid-template-columns: repeat('+rowcount+', 1fr);'">
|
||||||
|
<template v-for="(item,index) in items" :key="index">
|
||||||
|
<view v-if="item.br" style="grid-column: 1 / -1;"></view>
|
||||||
|
<view v-else-if="item.line" style="grid-column: 1 / -1;height: 3px;width: 100%;background: linear-gradient(90deg, transparent, var(--bg5), transparent);"></view>
|
||||||
|
<view v-else class="_item" @tap="selitem(index)">
|
||||||
|
<view class="_icon" v-if="item.icon"><ciy-svgimg :src="item.icon"></ciy-svgimg></view>
|
||||||
|
<view class="_name" :style="item.style" v-if="item.name">{{lang(item.name)}}</view>
|
||||||
|
<view class="_sub" v-if="item.sub">{{item.sub}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<view style="height:2em;"></view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</ciy-anipop>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._menu {
|
||||||
|
background: var(--bg2);
|
||||||
|
border-top: 1px solid var(--bg6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
font-weight: bold;
|
||||||
|
background: var(--bg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list._flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list._flex ._item {
|
||||||
|
padding: 1em;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._list._grid {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list._grid ._item {
|
||||||
|
padding: 1em 1em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list ._icon {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list ._name {
|
||||||
|
color: var(--txt7);
|
||||||
|
}
|
||||||
|
|
||||||
|
._list ._sub {
|
||||||
|
font-size:0.7em;
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
items: [],
|
||||||
|
rowcount: 0,
|
||||||
|
title: '',
|
||||||
|
popsh: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
Open(opn) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
opn = opn || {};
|
||||||
|
if(!opn.items || opn.items.length == 0)
|
||||||
|
return;
|
||||||
|
if(opn.one && opn.items.length == 1){
|
||||||
|
resolve({...opn.items[0]});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.resolvecb = resolve;
|
||||||
|
this.items = opn.items;
|
||||||
|
this.rowcount = opn.rowcount;
|
||||||
|
this.title = opn.title;
|
||||||
|
this.popsh = true;
|
||||||
|
}).catch(e => {
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selitem(idx) {
|
||||||
|
this.popsh = false;
|
||||||
|
this.resolvecb({...this.items[idx]});
|
||||||
|
},
|
||||||
|
popclose(e) {
|
||||||
|
if(!e.value)
|
||||||
|
this.resolvecb({close:true});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,343 @@
|
||||||
|
<template>
|
||||||
|
<view class="_lnte" @tap="toggle">
|
||||||
|
<view class="_search">
|
||||||
|
<view v-if="!qshow" class="_itm">
|
||||||
|
<view class="itm" v-for="(item,index) in items" :key="index" :class="item.cls">{{item.txt}}</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="qshow" class="_txt">{{lang('query.pselect')}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="_sbtn" :class="{queryed}">
|
||||||
|
<view class="itm"></view>{{lang('query.btn_query')}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view :animation="anidatapop" v-if="qshow" class="_qshow">
|
||||||
|
<view :style="{height:qmtop+'px'}" @tap="close"></view>
|
||||||
|
<view class="_main">
|
||||||
|
<view class="_form" :style="{maxHeight: fheight + 'px'}">
|
||||||
|
<view class="ciy-form" v-for="(item,index) in qry" :key="index">
|
||||||
|
<label v-if="item.label != 'no'">{{item.name}}</label>
|
||||||
|
<view v-if="item.type == 'input'">
|
||||||
|
<ciy-input bb :name="item.form" v-model="data[item.form]" type="text"></ciy-input>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'select'">
|
||||||
|
<ciy-select :name="item.form" v-model="data[item.form]"
|
||||||
|
:range="loadrange(gdict, item)"></ciy-select>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'num'"
|
||||||
|
style="display:flex;align-items: center;justify-content: flex-end;">
|
||||||
|
<ciy-input bb :name="item.form + '_1'" v-model="data[item.form+'_1']" type="digit" style="width:4em;text-align:center;"></ciy-input>
|
||||||
|
<view style="margin-left:0.5em;">~</view>
|
||||||
|
<ciy-input bb :name="item.form + '_2'" v-model="data[item.form+'_2']" type="digit" style="width:4em;text-align:center;"></ciy-input>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'bool'">
|
||||||
|
<ciy-selbool left :name="item.form" v-model="data[item.form]"></ciy-selbool>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'radio'">
|
||||||
|
<ciy-radio left :name="item.form" v-model="data[item.form]" :range="loadrange(gdict, item)"></ciy-radio>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'checkbox'">
|
||||||
|
<ciy-checkbox left :name="item.form" v-model="data[item.form]" :range="loadrange(gdict, item)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'daterange'">
|
||||||
|
<ciy-inputdaterange :name="item.form" v-model="data[item.form]"></ciy-inputdaterange>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'day'">
|
||||||
|
<ciy-inputdatetime :name="item.form" v-model="data[item.form]"></ciy-inputdatetime>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="item.type == 'month'">
|
||||||
|
<ciy-inputdatetime selectmonth :name="item.form" v-model="data[item.form]"></ciy-inputdatetime>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<slot :itm="{item:item,data:data}"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_bottombtn">
|
||||||
|
<button class="btn def" @tap="close">{{lang('query.btn_close')}}</button>
|
||||||
|
<button class="btn lg" @tap="submit">{{lang('query.btn_run')}}</button>
|
||||||
|
<button class="btn def" @tap="reset">{{lang('query.btn_reset')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_mask" @tap="close"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['confirm'],
|
||||||
|
props: {
|
||||||
|
qry: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
gdict: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
qshow: false,
|
||||||
|
qmtop:0,
|
||||||
|
fheight:0,
|
||||||
|
anidatapop: {},
|
||||||
|
data: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
computed: {
|
||||||
|
items() {
|
||||||
|
var itms = [];
|
||||||
|
for (var i in this.qry) {
|
||||||
|
if (this.hasdata(i))
|
||||||
|
itms.push({
|
||||||
|
txt: this.qry[i].name,
|
||||||
|
cls: '_valed'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (var i in this.qry) {
|
||||||
|
if (!this.hasdata(i))
|
||||||
|
itms.push({
|
||||||
|
txt: this.qry[i].name,
|
||||||
|
cls: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return itms;
|
||||||
|
},
|
||||||
|
queryed() {
|
||||||
|
for (var i in this.qry) {
|
||||||
|
if (this.hasdata(i))
|
||||||
|
return '_queryed';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
if (this.qshow)
|
||||||
|
this.close();
|
||||||
|
else
|
||||||
|
this.open();
|
||||||
|
},
|
||||||
|
loadrange(gdict, item) {
|
||||||
|
var sels = [];
|
||||||
|
if (item.all)
|
||||||
|
sels.push({
|
||||||
|
id: '',
|
||||||
|
name: item.all
|
||||||
|
});
|
||||||
|
var gg = [];
|
||||||
|
if (item.select instanceof Array)
|
||||||
|
gg = item.select;
|
||||||
|
else {
|
||||||
|
if (item.select.substring(0, 5) == 'cata_') {
|
||||||
|
gg = gdict[item.select.substring(5)];
|
||||||
|
} else {
|
||||||
|
gg = gdict[item.select];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i in gg) {
|
||||||
|
sels.push({
|
||||||
|
...gg[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return sels;
|
||||||
|
},
|
||||||
|
async open() {
|
||||||
|
this.pagenoscroll(true);
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
var lnterect = await this.getrect('._lnte');
|
||||||
|
if (!lnterect)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var app = getApp();
|
||||||
|
this.qmtop = lnterect.bottom;
|
||||||
|
this.fheight = app.globalData._sysinfo.windowHeight - lnterect.bottom - footerheight - 110;
|
||||||
|
this.qshow = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
var animation = uni.createAnimation({
|
||||||
|
transformOrigin: "100% " + (lnterect.bottom - 60) + "px"
|
||||||
|
});
|
||||||
|
animation.scale(1);
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.pagenoscroll(false);
|
||||||
|
var animation = uni.createAnimation({
|
||||||
|
transformOrigin: "100% " + (this.qmtop - 60) + "px"
|
||||||
|
});
|
||||||
|
|
||||||
|
animation.scale(0);
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.qshow = false;
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
hasdata(idx) {
|
||||||
|
var form = this.qry[idx].form;
|
||||||
|
if (this.qry[idx].type == 'num') {
|
||||||
|
return this.data[form + '_1'] || this.data[form + '_2'];
|
||||||
|
} else if (this.qry[idx].type == 'bool') {
|
||||||
|
return this.data[form] == 1;
|
||||||
|
} else {
|
||||||
|
return !!this.data[form];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
for (var i in this.data) {
|
||||||
|
delete this.data[i];
|
||||||
|
}
|
||||||
|
this.$emit("confirm", {});
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
// #ifndef APP-PLUS
|
||||||
|
uni.hideKeyboard();
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
plus.key.hideSoftKeybord();
|
||||||
|
// #endif
|
||||||
|
this.$emit("confirm", {...this.data});
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
setdata(where){
|
||||||
|
if(!where)
|
||||||
|
return;
|
||||||
|
for(var i in this.data){
|
||||||
|
if(where[i])
|
||||||
|
this.data[i] = where[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._qshow {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
opacity: 0;
|
||||||
|
top: 0;
|
||||||
|
transform-origin: 100% 0;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
._qshow>._main {
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
|
background: linear-gradient(0deg, var(--man3), var(--bg1));
|
||||||
|
padding: 0 1em;
|
||||||
|
border-bottom: 2px solid var(--man7);
|
||||||
|
}
|
||||||
|
|
||||||
|
._qshow>._mask {
|
||||||
|
height: 100vh;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
._qshow ._form {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
._qshow ._bottombtn {
|
||||||
|
margin: 1em 0px;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte {
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em;
|
||||||
|
background: var(--bg2);
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid var(--bg5);
|
||||||
|
height: 3.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._search {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._search ._itm {
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._search ._itm>.itm {
|
||||||
|
margin: 0.2em;
|
||||||
|
border-radius: 1em;
|
||||||
|
border: 1px solid var(--bg6);
|
||||||
|
color: var(--txt1);
|
||||||
|
padding: 0 0.5em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._search ._itm>.itm._valed {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background-clip: padding-box, border-box;
|
||||||
|
background-origin: padding-box, border-box;
|
||||||
|
background-image: linear-gradient(to right, var(--bg1), var(--bg1)), linear-gradient(331deg, var(--man5), var(--man7));
|
||||||
|
color: var(--man6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._search::after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 4em;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--bg2));
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._search ._txt {
|
||||||
|
background: linear-gradient(331deg, var(--man5), var(--man7));
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: bolder;
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._sbtn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin: 0 0.5em;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._sbtn._queryed {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
._lnte ._sbtn>.itm {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
display: inline-block;
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTc0Ny45IDk4LjVIMjc2LjFjLTQ4LjUgMC03NC45IDU2LjctNDMuNiA5My44TDM2MiAzNDUuOHY0MDkuNmgwLjJjLTEuNSAxNS4yIDUuNyAzMC42IDE5LjggMzguN2wyMTguNSAxMjYuMWMxOS4xIDExIDQzLjYgNC41IDU0LjYtMTQuNnM0LjUtNDMuNi0xNC42LTU0LjZMNDQyIDczNi4zVjM0NS44YzAtMTguOS02LjctMzcuMS0xOC44LTUxLjZsLTk3LjYtMTE1LjdoMzcyLjlsLTk3LjYgMTE1LjdjLTEyLjIgMTQuNC0xOC44IDMyLjctMTguOCA1MS42djU5LjRjMCAyMi4xIDE3LjkgNDAgNDAgNDBzNDAtMTcuOSA0MC00MHYtNTkuNGwxMjkuNS0xNTMuNWMzMS4xLTM3LjEgNC44LTkzLjgtNDMuNy05My44eiIgZmlsbD0iIzRhNWZlMiI+PC9wYXRoPjxwYXRoIGQ9Ik02ODIgNDY0LjNINTYyYy0yMi4xIDAtNDAgMTcuOS00MCA0MHMxNy45IDQwIDQwIDQwaDEyMGMyMi4xIDAgNDAtMTcuOSA0MC00MCAwLTIyLTE3LjktNDAtNDAtNDB6TTY4MiA1ODIuM0g1NjJjLTIyLjEgMC00MCAxNy45LTQwIDQwczE3LjkgNDAgNDAgNDBoMTIwYzIyLjEgMCA0MC0xNy45IDQwLTQwIDAtMjItMTcuOS00MC00MC00MHpNNjgyIDcwMC4zSDU2MmMtMjIuMSAwLTQwIDE3LjktNDAgNDBzMTcuOSA0MCA0MCA0MGgxMjBjMjIuMSAwIDQwLTE3LjkgNDAtNDAgMC0yMi0xNy45LTQwLTQwLTQweiIgZmlsbD0iIzdjNDRlMiI+PC9wYXRoPjwvc3ZnPg==");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,230 @@
|
||||||
|
<template>
|
||||||
|
<view style="width:100%;">
|
||||||
|
<input type="hidden" :name="name" :value="tkv.id" style="display:none;" />
|
||||||
|
<template v-if="hasmore">
|
||||||
|
<input type="hidden" :name="name+'_name'" :value="tkv.name" style="display:none;" />
|
||||||
|
</template>
|
||||||
|
<view v-if="innerrang.length==0" :style="{color:'var(--bg6)',textAlign:left?'left':''}">无选项</view>
|
||||||
|
<radio-group class="_gp" :class="{'_line':line,'_left':left,'_itemright':itemright}">
|
||||||
|
<view @tap="chkitem(item)" class="_item" v-for="(item,index) in innerrang" :key="index">
|
||||||
|
<ciy-checkitem style="pointer-events: none;" :disabled="disabled" :tag="item.id+''" :value="tkv.id == item.id"></ciy-checkitem>
|
||||||
|
<view :style="{color:disabled?'var(--txt1)':''}">{{item.name}}</view>
|
||||||
|
</view>
|
||||||
|
</radio-group>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
chkuse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
itemright: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
byname: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
valuearr: {
|
||||||
|
id: 0,
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
tkv: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (this.from && newD.id == oldD.id)
|
||||||
|
return;
|
||||||
|
if (!this.from)
|
||||||
|
this.from = 'init';
|
||||||
|
else if (this.from == 'init') {
|
||||||
|
this.from = 'check';
|
||||||
|
}
|
||||||
|
if (this.from != 'init') {
|
||||||
|
if (this.byname)
|
||||||
|
this.$emit('update:modelValue', newD.name);
|
||||||
|
else
|
||||||
|
this.$emit('update:modelValue', newD.id);
|
||||||
|
}
|
||||||
|
if (this.from != 'init' || this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: this.from,
|
||||||
|
value: {
|
||||||
|
id: newD.id,
|
||||||
|
name: newD.name
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
innerrang() {
|
||||||
|
if (typeof(this.range) == 'string') {
|
||||||
|
const lis = this.range.split(',');
|
||||||
|
var lst = [];
|
||||||
|
for (let i = 0; i < lis.length; i++) {
|
||||||
|
const ls = lis[i].split(':');
|
||||||
|
if (ls.length < 2)
|
||||||
|
continue;
|
||||||
|
lst.push({
|
||||||
|
id: ls[0],
|
||||||
|
name: ls[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
let range = [];
|
||||||
|
for (let i = 0; i < this.range.length; i++) {
|
||||||
|
if (this.chkuse && this.range[i].isuse == 2)
|
||||||
|
continue;
|
||||||
|
range.push(this.range[i]);
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
},
|
||||||
|
tkv() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = this.modelValue;
|
||||||
|
else if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = this.value;
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
} else {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
if (this.byname) {
|
||||||
|
for (var i in this.innerrang) {
|
||||||
|
if (this.innerrang[i].name == val)
|
||||||
|
return {
|
||||||
|
...this.innerrang[i]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i in this.innerrang) {
|
||||||
|
if (this.innerrang[i].id == val)
|
||||||
|
return {
|
||||||
|
...this.innerrang[i]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: 0,
|
||||||
|
name: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
chkitem(itm) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.v = itm.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._gp {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._left {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._left ._item {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp ._item {
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
min-width: 7em;
|
||||||
|
padding: 0.5em;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._itemright ._item {
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._gp._line ._item {
|
||||||
|
width: 100%;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
<template>
|
||||||
|
<view class="_star" :class="{_left:left,_disabled:disabled}">
|
||||||
|
<input type="hidden" :name="name" :value="innervalue" style="display:none;" />
|
||||||
|
<view @tap="selstar(item.id)" :class="item.cls" v-for="(item, index) in stars" :key="index" :style="{width:size,height:size}"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'update:value'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxstar: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 5
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: '2em'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innervalue: this.modelValue !== undefined ? this.modelValue : this.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(newD) {
|
||||||
|
if (newD !== undefined) {
|
||||||
|
this.innervalue = newD;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value(newD) {
|
||||||
|
if (this.modelValue === undefined) {
|
||||||
|
this.innervalue = newD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
stars() {
|
||||||
|
var stars = [];
|
||||||
|
for (var i = 1; i <= this.maxstar; i++) {
|
||||||
|
if (i <= this.innervalue)
|
||||||
|
stars.push({
|
||||||
|
id: i,
|
||||||
|
cls: '_sel'
|
||||||
|
});
|
||||||
|
else
|
||||||
|
stars.push({
|
||||||
|
id: i,
|
||||||
|
cls: '_unsel'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return stars;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.innervalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updatevalue(val) {
|
||||||
|
if (val > this.maxstar)
|
||||||
|
val = this.maxstar;
|
||||||
|
this.innervalue = val;
|
||||||
|
},
|
||||||
|
selstar(id) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
var val = this.toint(id);
|
||||||
|
this.updatevalue(val);
|
||||||
|
this.$emit('update:modelValue', val);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'click',
|
||||||
|
value: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._star {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
._star._left {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._star._disabled ._sel,
|
||||||
|
._star._disabled ._unsel {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
._star ._sel {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTUxMS4wNDI1NiAxMTUuMzA3NTJsMTIxLjQ5NzYgMjc0LjMyNDQ4IDI5OC4zMjE5MiAzMS45NTkwNC0yMjMuMzYgMjAwLjMyNTEyIDYxLjc4ODE2IDI5My41ODU5Mi0yNTkuNTI3NjgtMTUwLjUyOC0yNjAuMTMxODQgMTQ5LjUwNCA2Mi45NTU1Mi0yOTMuMzYwNjQtMjIyLjU1NjE2LTIwMS4xOTU1MiAyOTguNDI5NDQtMzAuNzc2MzIgMTIyLjU4MzA0LTI3My44MzgwOHoiIGZpbGw9IiNGRjk2MkYiPjwvcGF0aD48L3N2Zz4=");
|
||||||
|
}
|
||||||
|
|
||||||
|
._star ._unsel {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTg5Ny41NzE4NCA0MjAuNDQ0MTZsLTI2NS42NjY1Ni00MC41NDUyOEw1MTIgMTI1LjQ0IDM5Mi4wOTk4NCAzNzkuODk4ODhsLTI2NS42NjY1NiA0MC41NDUyOCAxOTIuMzUzMjggMTk2LjY2NDMyLTQ1LjcwNjI0IDI3OS40NjQ5Nkw1MTIgNzY0LjYxNTY4bDIzOC45MTk2OCAxMzEuOTU3NzYtNDUuNzExMzYtMjc5LjQ2NDk2IDE5Mi4zNjM1Mi0xOTYuNjY0MzJ6TTUxMiA3MDguNTI2MDhsLTE3OS40MDk5MiAxMDAuOTEwMDggMzQuNDk4NTYtMjAyLjcwNTkyLTE1NC4zOTg3Mi0xNTYuOTk5NjggMjA4Ljc0NzUyLTI3LjYwMTkyTDUxMiAyMjguOTE1Mmw4OS43MDc1MiAxOTMuMjEzNDQgMjA3Ljg2Njg4IDI5LjM0MjcyLTE1Mi42NTc5MiAxNTYuMTEzOTIgMzEuOTAyNzIgMjAyLjcxMTA0TDUxMiA3MDguNTI2MDh6IiBmaWxsPSIjRkY5NjJGIj48L3BhdGg+PC9zdmc+");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="_searchbar" @tap="clksearch">
|
||||||
|
<view class="_icon _search"></view>
|
||||||
|
<input v-if="show" ref="refinp" :focus="showfocus" :placeholder="placeholder" style="flex: 1;font-size: 0.9em;color: #333333;" confirm-type="search" type="text" v-model="searchval" @confirm="confirm(true)" @blur="confirm(false)" />
|
||||||
|
<text v-else style="font-size: 0.9em;color: #808080;">{{ placeholder === undefined?lang('searchbar.placeholder'):placeholder }}</text>
|
||||||
|
<text @tap="confirm(true)" class="_btn" v-if="show">{{btntxt===undefined?lang('searchbar.btn'):btntxt}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['confirm'],
|
||||||
|
props: {
|
||||||
|
placeholder: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
btntxt: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
showfocus: false,
|
||||||
|
searchval: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this._time = 0;
|
||||||
|
this.searchval = this.value || '';
|
||||||
|
this.lastsearch = this.searchval;
|
||||||
|
if (this.searchval != '')
|
||||||
|
this.show = true;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clksearch() {
|
||||||
|
this.show = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.showfocus = true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
confirm() {
|
||||||
|
this.hidekeyboard();
|
||||||
|
var x = new Date().getTime() - this._time;
|
||||||
|
if (x > 500) {
|
||||||
|
this._time = new Date().getTime();
|
||||||
|
this.$emit("confirm", {
|
||||||
|
value: this.searchval
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!this.searchval)
|
||||||
|
this.show = false;
|
||||||
|
},
|
||||||
|
hidekeyboard() {
|
||||||
|
// #ifndef APP-PLUS
|
||||||
|
uni.hideKeyboard();
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
plus.key.hideSoftKeybord();
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._icon._search {
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zycgd2lkdGg9JzIwMCcgaGVpZ2h0PScyMDAnPjxwYXRoIGQ9J000NTQuNjU2IDg0OS45MkMyMzEuNDI0IDg0OS45MiA1MS4yIDY2OC42NzIgNTEuMiA0NDUuNDQgNTEuMiAyMjMuMjMyIDIzMS40MjQgNDEuOTg0IDQ1NC42NTYgNDEuOTg0YzIyMi4yMDggMCA0MDMuNDU2IDE4MS4yNDggNDAzLjQ1NiA0MDMuNDU2Qzg1OC4xMTIgNjY4LjY3MiA2NzYuODY0IDg0OS45MiA0NTQuNjU2IDg0OS45MnogbTAtNzQ2LjQ5NkMyNjYuMjQgMTAzLjQyNCAxMTIuNjQgMjU3LjAyNCAxMTIuNjQgNDQ1LjQ0czE1My42IDM0Mi4wMTYgMzQyLjAxNiAzNDIuMDE2IDM0Mi4wMTYtMTUzLjYgMzQyLjAxNi0zNDIuMDE2LTE1My42LTM0Mi4wMTYtMzQyLjAxNi0zNDIuMDE2eicgZmlsbD0nIzEyOTZkYic+PC9wYXRoPjxwYXRoIGQ9J005NDIuMDggMTAwOC42NGMtMTIuMjg4IDAtMjMuNTUyLTQuMDk2LTMyLjc2OC0xMy4zMTJMNzM3LjI4IDgyMi4yNzJjLTE4LjQzMi0xOC40MzItMTguNDMyLTQ3LjEwNCAwLTY1LjUzNnM0Ny4xMDQtMTguNDMyIDY1LjUzNiAwbDE3Mi4wMzIgMTcyLjAzMmMxOC40MzIgMTguNDMyIDE4LjQzMiA0Ny4xMDQgMCA2NS41MzYtOS4yMTYgOS4yMTYtMjAuNDggMTQuMzM2LTMyLjc2OCAxNC4zMzZ6JyBmaWxsPScjMTMyMjdhJyBjbGFzcz0nJz48L3BhdGg+PC9zdmc+");
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
margin: 0 0.4em;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
._searchbar {
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 2.5em;
|
||||||
|
border: 1px solid var(--bg5);
|
||||||
|
border-radius: 0.3em;
|
||||||
|
background: var(--bg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._btn {
|
||||||
|
padding: 0 0.5em;
|
||||||
|
line-height: 2.5em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--txt6);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,175 @@
|
||||||
|
<template>
|
||||||
|
<view class="_vli" v-if="lis.length > 0">
|
||||||
|
<view class="_ul">
|
||||||
|
<template v-for="(item,index) in lilist" :key="index">
|
||||||
|
<view class="itm" :class="{_active:liid==item.id}" @tap="changeli(index)">
|
||||||
|
{{lang(item.name)}}
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
all: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
lis: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
liid() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
val = this.modelValue + '';
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
val = this.value + '';
|
||||||
|
} else {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
lilist() {
|
||||||
|
var lst = [];
|
||||||
|
var idx = 0;
|
||||||
|
if (this.all) {
|
||||||
|
lst.push({
|
||||||
|
id: '',
|
||||||
|
name: this.all
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (typeof(this.lis) == 'string') {
|
||||||
|
const lis = this.lis.split(',');
|
||||||
|
for (let i = 0; i < lis.length; i++) {
|
||||||
|
const ls = lis[i].split(':');
|
||||||
|
if (ls.length < 2)
|
||||||
|
continue;
|
||||||
|
lst.push({
|
||||||
|
id: ls[0],
|
||||||
|
name: ls[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isarray(this.lis)) {
|
||||||
|
for (var i = 0; i < this.lis.length; i++)
|
||||||
|
lst.push({
|
||||||
|
...this.lis[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this._index = 0;
|
||||||
|
if (this.initevent) {
|
||||||
|
this.changeli(this._index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeli(idx) {
|
||||||
|
if (!this.lilist)
|
||||||
|
return;
|
||||||
|
if (!this.lilist[idx])
|
||||||
|
return;
|
||||||
|
var val = {
|
||||||
|
_index: idx,
|
||||||
|
...this.lilist[idx]
|
||||||
|
};
|
||||||
|
this._index = idx;
|
||||||
|
this.v = val.id + '';
|
||||||
|
this.$emit('update:modelValue', val.id);
|
||||||
|
this.$emit('change', {
|
||||||
|
value: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._vli {
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: hidden;
|
||||||
|
background: var(--bg1);
|
||||||
|
border-bottom: 1px solid var(--bg6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._vli>._ul {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vli>._ul>.itm {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
color: var(--txt7);
|
||||||
|
}
|
||||||
|
|
||||||
|
._vli>._ul>.itm._active {
|
||||||
|
background: linear-gradient(331deg, var(--man5), var(--man7));
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vli>._ul>.itm::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
height: 0.3em;
|
||||||
|
bottom: -0.5em;
|
||||||
|
width: 0em;
|
||||||
|
left: 50%;
|
||||||
|
background: linear-gradient(331deg, var(--man5), var(--man7));
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vli>._ul>.itm._active::after {
|
||||||
|
width: 2em;
|
||||||
|
opacity: 1;
|
||||||
|
left: calc(50% - 1em);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
<template>
|
||||||
|
<view class="_switch" :class="{_disabled:disabled}" @tap="clickswitch(!this.tvalue)" :animation="anidatabg">
|
||||||
|
<input :name="name" :value="tvalue?1:2" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_name'" :value="tvalue?this.y:this.n" style="display:none;" />
|
||||||
|
<view class="_y" :animation="anidatay">{{y}}</view>
|
||||||
|
<view class="_n" :animation="anidatan">{{n}}</view>
|
||||||
|
<ciy-gesture :pxlen="10" @toleft="gestureto(false)" @toright="gestureto(true)">
|
||||||
|
<view class="_bn" :animation="anidatabn"></view>
|
||||||
|
</ciy-gesture>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._switch {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 2em;
|
||||||
|
height: 2em;
|
||||||
|
font-size: 1em;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid var(--e-switch-br);
|
||||||
|
background: var(--e-switch-bg);
|
||||||
|
color: var(--e-switch-txt);
|
||||||
|
border-radius: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch._disabled {
|
||||||
|
background: var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch ._n {
|
||||||
|
position: relative;
|
||||||
|
margin-top: -2em;
|
||||||
|
margin-left: 2em;
|
||||||
|
margin-right: 0.8em;
|
||||||
|
color: var(--e-switch-txt);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch ._y {
|
||||||
|
margin-right: 2em;
|
||||||
|
margin-left: 0.8em;
|
||||||
|
color: var(--e-switch-chktxt);
|
||||||
|
opacity: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch ._bn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 1.6em;
|
||||||
|
height: 1.6em;
|
||||||
|
margin: 0.1em;
|
||||||
|
border-radius: 0.8em;
|
||||||
|
background: var(--e-switch-bg);
|
||||||
|
box-shadow: var(--e-switch-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch._disabled ._bn {
|
||||||
|
background: var(--bg5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: -998
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: -998
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
y: { //选中文字
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
n: { //未选中文字
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
ms: { //动画毫秒数
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
anidatabg: {},
|
||||||
|
anidatay: {},
|
||||||
|
anidatan: {},
|
||||||
|
anidatabn: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
tvalue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (this.v == 'modelValue' || this.v == 'value')
|
||||||
|
this.ani();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD === -998)
|
||||||
|
return;
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD === -998)
|
||||||
|
return;
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'boolean')
|
||||||
|
return this.modelValue;
|
||||||
|
else if (typeof(this.modelValue) == 'number')
|
||||||
|
return (this.modelValue == 1);
|
||||||
|
else if (this.modelValue.toLowerCase() == 'true')
|
||||||
|
return true;
|
||||||
|
else if (this.modelValue == '1')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'boolean')
|
||||||
|
return this.value;
|
||||||
|
else if (typeof(this.value) == 'number')
|
||||||
|
return (this.value == 1);
|
||||||
|
else if (this.value.toLowerCase() == 'true')
|
||||||
|
return true;
|
||||||
|
else if (this.value == '1')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.v;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue ? 1 : 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.tvalue)
|
||||||
|
this.ani();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
chg(e) {
|
||||||
|
this.clickswitch(!this.tvalue);
|
||||||
|
},
|
||||||
|
ani() {
|
||||||
|
uni.createSelectorQuery().in(this).select('._switch').boundingClientRect(data => {
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
var ln = data.width - data.height;
|
||||||
|
var time = this.ms;
|
||||||
|
var len = this.y.length > this.n.length ? this.y.length : this.n.length;
|
||||||
|
len = 0;
|
||||||
|
if (this.tvalue) {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
if (len > 0) {
|
||||||
|
animation.translateX((ln / 2) + 'px');
|
||||||
|
animation.translateY('4px');
|
||||||
|
animation.scale(0.9);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
animation.translateX(ln + 'px');
|
||||||
|
//animation.translateY(0);
|
||||||
|
animation.scale(1);
|
||||||
|
animation.step({
|
||||||
|
duration: (len > 0 ? time / 2 : time)
|
||||||
|
});
|
||||||
|
this.anidatabn = animation.export();
|
||||||
|
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.backgroundColor(this.disabled ? 'var(--e-switch-chkbgdis)' : 'var(--e-switch-chkbg)');
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatabg = animation.export();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('20px');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatan = animation.export();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatay = animation.export();
|
||||||
|
} else {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
if (len > 0) {
|
||||||
|
animation.translateX((ln / 2) + 'px');
|
||||||
|
animation.translateY('-4px');
|
||||||
|
animation.scale(0.9);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
animation.translateX(0);
|
||||||
|
//animation.translateY(0);
|
||||||
|
animation.scale(1);
|
||||||
|
animation.step({
|
||||||
|
duration: (len > 0 ? time / 2 : time)
|
||||||
|
});
|
||||||
|
this.anidatabn = animation.export();
|
||||||
|
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.backgroundColor(this.disabled ? 'var(--e-switch-br)' : 'var(--e-switch-bg)');
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatabg = animation.export();
|
||||||
|
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatan = animation.export();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('-20px');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatay = animation.export();
|
||||||
|
}
|
||||||
|
}).exec();
|
||||||
|
},
|
||||||
|
gestureto(chk) {
|
||||||
|
if (chk == this.v)
|
||||||
|
return;
|
||||||
|
this.clickswitch(chk);
|
||||||
|
},
|
||||||
|
clickswitch(chk) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.v = chk;
|
||||||
|
this.ani();
|
||||||
|
this.$emit('update:modelValue', this.tvalue ? 1 : 2);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
value: this.tvalue ? 1 : 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,410 @@
|
||||||
|
<template>
|
||||||
|
<view style="width:100%;">
|
||||||
|
<input type="hidden" :name="name" :value="tvalue.value" style="display:none;" />
|
||||||
|
<template v-if="hasmore">
|
||||||
|
<checkbox-group :name="name+'_name'" style="display:none;">
|
||||||
|
<checkbox v-for="(item,index) in tvalue.names" :key="index" :value="item" checked />
|
||||||
|
</checkbox-group>
|
||||||
|
<checkbox-group :name="name+'_id'" style="display:none;">
|
||||||
|
<checkbox v-for="(item,index) in tvalue.ids" :key="index" :value="item" checked />
|
||||||
|
</checkbox-group>
|
||||||
|
</template>
|
||||||
|
<view class="_show" @tap="showhide(true)" :class="{_disabled:disabled}">
|
||||||
|
<slot name="list" :data="{value:tvalue, range:range}">
|
||||||
|
<view class="_defshow" :class="{_left:left}">
|
||||||
|
<template v-for="(item,index) in tvalue.sels" :key="index">
|
||||||
|
<view style="padding-left:0.3em;" v-if="index>0">~</view>
|
||||||
|
<view class="itm" v-if="item.id > 0">{{item.name}}</view>
|
||||||
|
</template>
|
||||||
|
<view class="itm" v-if="tvalue.sels.length == 0">{{placeholder?placeholder:lang('placeholder.select')}}</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<ciy-anipop v-model="popsh">
|
||||||
|
<view class="_pop">
|
||||||
|
<view class="_op">
|
||||||
|
<view class="_cata">
|
||||||
|
<template v-for="(item,index) in openvalue.sels" :key="index">
|
||||||
|
<view v-if="item.high" class="itm _level">{{item.name}}</view>
|
||||||
|
<view v-else @tap="sellevel(index)" class="itm">{{item.name}}</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<button class="btn sm def" @tap="selclear" v-if="clearbtn">{{lang('selcas.clear')}}</button>
|
||||||
|
<button class="btn sm" @tap="seldone">{{lang('selcas.done')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_list">
|
||||||
|
<template v-for="(item,index) in range" :key="index">
|
||||||
|
<view class="itm" @tap="selandnext(index)" v-if="(!chkuse || item.isuse != 2) && item.upid == openvalue.upval" :class="{select:item.id == openvalue.value}">
|
||||||
|
{{item.name}}
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</ciy-anipop>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._defshow {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
._defshow._left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._defshow>.itm {
|
||||||
|
padding-left: 0.3em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
._show._disabled {
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop {
|
||||||
|
display: flex;
|
||||||
|
z-index: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--bg2);
|
||||||
|
border-top: 1px solid var(--bg6);
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 1em 1em 0 0;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._op {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._op ._cata {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._op ._cata>.itm {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._op ._cata>.itm:first-child::before {
|
||||||
|
content: "";
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._op ._cata>.itm::before {
|
||||||
|
content: "";
|
||||||
|
vertical-align: middle;
|
||||||
|
display: inline-block;
|
||||||
|
width: 0.7em;
|
||||||
|
height: 0.7em;
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZGF0YS1zcG0tYW5jaG9yLWlkPSJhMzEzeC5zZWFyY2hfaW5kZXguMC5pMy40MTE0M2E4MThFZlpjRiI+PHBhdGggZD0iTTM1OC42NzggODJMMjk2IDE0NC42NDZsMzUxLjg3IDM1MS42OTNjNy45ODggNy45ODQgOC42MDMgMjAuNTQ3IDEuODQzIDI5LjIzNmwtMS44NDMgMi4wODdMMjk2IDg3OS4zNTQgMzU4LjY3OCA5NDJsMzUxLjg3LTM1MS42OTJjNDEuOTU4LTQxLjkzOCA0My4yMy0xMDkuMTQyIDMuODE0LTE1Mi42MTFsLTMuODE0LTQuMDA1TDM1OC42NzggODJ6IiBkYXRhLXNwbS1hbmNob3ItaWQ9ImEzMTN4LnNlYXJjaF9pbmRleC4wLmkxLjQxMTQzYTgxOEVmWmNGIiBmaWxsPSIjNzc3Nzc3Ij48L3BhdGg+PC9zdmc+");
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._op ._cata ._level {
|
||||||
|
color: var(--man5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
._pop ._list {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 1em 0.5em 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._list>.itm {
|
||||||
|
min-height: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._pop ._list>.itm.select {
|
||||||
|
color: var(--man5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'loaddata'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
chkuse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
clearbtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
rootupid: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
asyncdata: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
allowpart: { //允许选择部分
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
editval: {
|
||||||
|
value: 0,
|
||||||
|
enext: false
|
||||||
|
}, //当前值,用于openvalue计算
|
||||||
|
popsh: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
if (newD) {
|
||||||
|
this.$emit('update:modelValue', newD);
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: newD,
|
||||||
|
selvalue: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
if (newD) {
|
||||||
|
this.$emit('update:modelValue', newD);
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: newD,
|
||||||
|
selvalue: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() { //当前选项链
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
val = this.value;
|
||||||
|
} else {
|
||||||
|
val = this.v;
|
||||||
|
}
|
||||||
|
var vals = [];
|
||||||
|
var tval = {};
|
||||||
|
var fillvid = id => {
|
||||||
|
for (var i in this.range) {
|
||||||
|
if (this.range[i].id == id) {
|
||||||
|
fillvid(this.range[i].upid);
|
||||||
|
vals.push({
|
||||||
|
...this.range[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fillvid(val);
|
||||||
|
tval.sels = vals;
|
||||||
|
tval.value = val;
|
||||||
|
if (vals.length == 0) {
|
||||||
|
tval.upval = this.rootupid;
|
||||||
|
} else {
|
||||||
|
tval.upval = vals[vals.length - 1].upid;
|
||||||
|
}
|
||||||
|
var idarr = [];
|
||||||
|
var namearr = [];
|
||||||
|
for (var i in tval.sels) {
|
||||||
|
idarr.push(tval.sels[i].id + '');
|
||||||
|
namearr.push(tval.sels[i].name + '');
|
||||||
|
}
|
||||||
|
tval.names = namearr;
|
||||||
|
tval.ids = idarr;
|
||||||
|
return tval;
|
||||||
|
},
|
||||||
|
openvalue() { //中间数据
|
||||||
|
var val = this.editval.value;
|
||||||
|
var oval = {};
|
||||||
|
var vals = [];
|
||||||
|
var fillvid = id => {
|
||||||
|
for (var i in this.range) {
|
||||||
|
if (this.range[i].id == id) {
|
||||||
|
fillvid(this.range[i].upid);
|
||||||
|
vals.push({
|
||||||
|
...this.range[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fillvid(val);
|
||||||
|
if (this.editval.enext) {
|
||||||
|
var hasnext = this.arrayfind(this.range, this.editval.value, 'upid');
|
||||||
|
if (hasnext > -1)
|
||||||
|
vals.push({
|
||||||
|
id: this.editval.value,
|
||||||
|
upid: this.editval.value,
|
||||||
|
high: true,
|
||||||
|
name: this.placeholder
|
||||||
|
});
|
||||||
|
else
|
||||||
|
vals[vals.length - 1].high = true;
|
||||||
|
} else {
|
||||||
|
if (vals.length > 0)
|
||||||
|
vals[vals.length - 1].high = true;
|
||||||
|
else
|
||||||
|
vals.push({
|
||||||
|
id: this.editval.value,
|
||||||
|
upid: this.rootupid,
|
||||||
|
high: true,
|
||||||
|
name: this.placeholder
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (vals.length == 0) {
|
||||||
|
oval.upval = this.rootupid;
|
||||||
|
val = this.rootupid;
|
||||||
|
} else {
|
||||||
|
oval.upval = vals[vals.length - 1].upid;
|
||||||
|
}
|
||||||
|
oval.sels = vals;
|
||||||
|
oval.value = val;
|
||||||
|
return oval;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
showhide(bsh) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.popsh = !this.popsh;
|
||||||
|
if (this.popsh) {
|
||||||
|
this._runajax = false;
|
||||||
|
this.editval = {
|
||||||
|
value: this.tvalue.value,
|
||||||
|
enext: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sellevel(idx) {
|
||||||
|
this._runajax = false;
|
||||||
|
this.editval = {
|
||||||
|
value: this.openvalue.sels[idx].id,
|
||||||
|
enext: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
selandnext(idx) {
|
||||||
|
this._runajax = false;
|
||||||
|
if (this.asyncdata) {
|
||||||
|
if (!this.range[idx]._ajax) {
|
||||||
|
this.range[idx]._ajax = true;
|
||||||
|
var hasnext = this.arrayfind(this.range, this.range[idx].id, 'upid');
|
||||||
|
if (hasnext == -1) {
|
||||||
|
(index => {
|
||||||
|
this._runajax = true;
|
||||||
|
this.$emit('loaddata', {
|
||||||
|
range: this.range[index],
|
||||||
|
success: () => {
|
||||||
|
if (this._runajax)
|
||||||
|
this.selandnext(index);
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
this.range[index]._ajax = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.editval = {
|
||||||
|
value: this.range[idx].id,
|
||||||
|
enext: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
selclear() {
|
||||||
|
this.$emit('update:modelValue', 0);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'clear',
|
||||||
|
value: 0,
|
||||||
|
selvalue: {}
|
||||||
|
});
|
||||||
|
this.v = 0;
|
||||||
|
this.popsh = false;
|
||||||
|
},
|
||||||
|
seldone() {
|
||||||
|
for (var i = this.openvalue.sels.length - 1; i >= 0; i--) {
|
||||||
|
if (this.openvalue.sels[i].id == 0)
|
||||||
|
continue;
|
||||||
|
var hasnext = this.arrayfind(this.range, this.openvalue.sels[i].id, 'upid');
|
||||||
|
if (hasnext > -1 && !this.allowpart)
|
||||||
|
return this.selandnext(hasnext);
|
||||||
|
var thisv = this.openvalue.sels[i];
|
||||||
|
this.$emit('update:modelValue', thisv.id);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'done',
|
||||||
|
value: thisv.id,
|
||||||
|
selvalue: {
|
||||||
|
...thisv
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.v = thisv.id;
|
||||||
|
this.popsh = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,483 @@
|
||||||
|
<template>
|
||||||
|
<view class="_select">
|
||||||
|
<view class="_mask" @touchmove.stop.prevent="() => { }" v-if="popclass" @tap="hidepop"></view>
|
||||||
|
<view class="_pop" :animation="anidatapop" v-if="popclass" :class="popclass">
|
||||||
|
<view class="ciy-hr"></view>
|
||||||
|
<view class="_search" v-if="range.length > minselectsearch">
|
||||||
|
<view class="itm">
|
||||||
|
<input v-model="searchval" :placeholder="lang('placeholder.key')" @confirm="searchconfirm" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="_list" :class="rows==1?'_flex':'_grid'" :style="'grid-template-columns: repeat('+rows+', 1fr);text-align:' + itemalign">
|
||||||
|
<slot name="list" :data="{range:mrange,searchkey:searchval,popclass:popclass,onselect:Selitem}">
|
||||||
|
<view class="_item" :class="{_select:tvalue.id==item.id}" v-for="(item,index) in mrange" :key="index" @tap="Selitem(index)">
|
||||||
|
{{item.name}}
|
||||||
|
</view>
|
||||||
|
<template v-if="mrange.length == 0">
|
||||||
|
<view v-if="searchval" class="_nodata">
|
||||||
|
{{lang('select.nosearch')}}
|
||||||
|
<text class="_code">{{searchval}}</text>
|
||||||
|
</view>
|
||||||
|
<view v-else class="_nodata">{{lang('select.nodata')}}</view>
|
||||||
|
</template>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-hr"></view>
|
||||||
|
<view style="flex:1;pointer-events: none;width:100%;" @touchmove.stop.prevent="() => { }" @tap="hidepop"></view>
|
||||||
|
</view>
|
||||||
|
<view class="_show" :class="{_left:left}" @tap="showpop">
|
||||||
|
<view class="_txt" :style="ciystyle">
|
||||||
|
<view v-if="tvalue.name" :style="{color:disabled?'var(--bg6)':'var(--txt9)'}">{{tvalue.name}}</view>
|
||||||
|
<view v-else-if="placeholder !== ''" style="color:var(--txt1);">{{placeholder?placeholder:lang('placeholder.select')}}</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="!noarrow" class="_arrow ciy-icon-arrow" :class="{_sel:popclass}"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<input type="hidden" :name="name" :value="tvalue.id" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_name'" :value="tvalue.name" style="display:none;" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'search'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
chkuse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
diastema: { //上下间隙
|
||||||
|
type: Number,
|
||||||
|
default: 16
|
||||||
|
},
|
||||||
|
itemalign: { //item对齐
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
all: { //0值选项
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
noarrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
rows: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
minselectsearch: { //选项少于n,则不显示搜索
|
||||||
|
type: Number,
|
||||||
|
default: 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
searchval: '', //搜索键入内容
|
||||||
|
popclass: '', //值包含[btm/top],制定弹出在上方还是下方
|
||||||
|
anidatapop: {}, //弹出的选项动画
|
||||||
|
addrange: [] //动态新增的选项,不能污染属性,保持单向性
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
searchval: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.$emit('search', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
com: this,
|
||||||
|
value: newD
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
mrange() {
|
||||||
|
var mr = [];
|
||||||
|
if (this.all)
|
||||||
|
mr.push({
|
||||||
|
id: 0,
|
||||||
|
name: this.all
|
||||||
|
});
|
||||||
|
var tmprange = this.range;
|
||||||
|
if (!this.isarray(this.range)) {
|
||||||
|
tmprange = [];
|
||||||
|
let oprang = (this.range + '').split('.');
|
||||||
|
for (let r in oprang) {
|
||||||
|
let idx = oprang[r].indexOf(':');
|
||||||
|
if (idx <= 0)
|
||||||
|
continue;
|
||||||
|
tmprange.push({
|
||||||
|
id: oprang[r].substring(0, idx),
|
||||||
|
name: oprang[r].substring(idx + 1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i in tmprange) {
|
||||||
|
if (this.chkuse && tmprange[i].isuse == 2)
|
||||||
|
continue;
|
||||||
|
if (tmprange[i].name.indexOf(this.searchval) > -1)
|
||||||
|
mr.push(tmprange[i]);
|
||||||
|
}
|
||||||
|
for (var i in this.addrange) {
|
||||||
|
if (this.chkuse && tmprange[i].isuse == 2)
|
||||||
|
continue;
|
||||||
|
if (this.addrange[i].name.indexOf(this.searchval) > -1)
|
||||||
|
mr.push(this.addrange[i]);
|
||||||
|
}
|
||||||
|
return mr;
|
||||||
|
},
|
||||||
|
tvalue() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = this.modelValue;
|
||||||
|
else if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = this.value;
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
} else if (this.v instanceof Object) {
|
||||||
|
return this.v;
|
||||||
|
}
|
||||||
|
for (var i in this.mrange) {
|
||||||
|
if (this.mrange[i].id == val)
|
||||||
|
return {
|
||||||
|
_index: i,
|
||||||
|
...this.mrange[i]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (this.mrange.length > 0 && this.placeholder === '')
|
||||||
|
return {
|
||||||
|
_index: 0,
|
||||||
|
...this.mrange[0]
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
id: 0,
|
||||||
|
_index: -1,
|
||||||
|
name: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: {
|
||||||
|
...this.tvalue
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.lastvalue = {
|
||||||
|
...this.tvalue
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
searchconfirm(e) {
|
||||||
|
this.$emit('search', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'confirm',
|
||||||
|
com: this,
|
||||||
|
value: e.detail.value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Addrange(newrange) {
|
||||||
|
if (!(newrange instanceof Array))
|
||||||
|
return 'ERR: Not Array.';
|
||||||
|
var addarr = [];
|
||||||
|
for (var i in newrange) {
|
||||||
|
var bfind = false;
|
||||||
|
for (var r in this.mrange) {
|
||||||
|
if (newrange[i].id == this.mrange[r].id) {
|
||||||
|
bfind = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bfind)
|
||||||
|
continue;
|
||||||
|
for (var r in addarr) {
|
||||||
|
if (newrange[i].id == addarr[r].id) {
|
||||||
|
bfind = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bfind)
|
||||||
|
continue;
|
||||||
|
addarr.push(newrange[i]);
|
||||||
|
}
|
||||||
|
this.addrange.push(...addarr);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Selitem(index) {
|
||||||
|
this.v = this.mrange[index];
|
||||||
|
this.$emit('update:modelValue', this.v.id);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'select',
|
||||||
|
value: {
|
||||||
|
_index: index,
|
||||||
|
...this.v
|
||||||
|
},
|
||||||
|
lastvalue: this.lastvalue
|
||||||
|
});
|
||||||
|
this.lastvalue = {
|
||||||
|
_index: index,
|
||||||
|
...this.v
|
||||||
|
};
|
||||||
|
this.hidepop();
|
||||||
|
},
|
||||||
|
hidepop() {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('100vw');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
animation.height('auto');
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.popclass = '';
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
async showpop() {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
var app = getApp();
|
||||||
|
app.globalData.scrollcbs['com_select'] = e => {
|
||||||
|
delete app.globalData.scrollcbs['com_select'];
|
||||||
|
this.hidepop();
|
||||||
|
};
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
var fixtop = 0;
|
||||||
|
|
||||||
|
this.searchval = '';
|
||||||
|
this.popclass = 'temp';
|
||||||
|
var mainrect = await this.getrect('._pop');
|
||||||
|
if (!mainrect)
|
||||||
|
return;
|
||||||
|
var showrect = await this.getrect('._show');
|
||||||
|
if (!showrect)
|
||||||
|
return;
|
||||||
|
var toph = showrect.top - headerheight - this.diastema;
|
||||||
|
var btmh = app.globalData._sysinfo.windowHeight - footerheight - showrect.bottom - this.diastema;
|
||||||
|
var topcls = '_btm';
|
||||||
|
var syheight, sytop;
|
||||||
|
if (toph > btmh) {
|
||||||
|
topcls = '_top';
|
||||||
|
syheight = mainrect.height;
|
||||||
|
if (syheight > toph)
|
||||||
|
syheight = toph;
|
||||||
|
sytop = headerheight + fixtop + toph - syheight;
|
||||||
|
} else {
|
||||||
|
syheight = mainrect.height;
|
||||||
|
if (syheight > btmh)
|
||||||
|
syheight = btmh;
|
||||||
|
sytop = showrect.bottom + this.diastema - fixtop;
|
||||||
|
}
|
||||||
|
this.popclass = topcls;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX(0);
|
||||||
|
animation.top(sytop);
|
||||||
|
animation.height(syheight);
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._select ._pop {
|
||||||
|
position: fixed;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
opacity: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transform: translateX(100vw);
|
||||||
|
transform: translateY(38px);
|
||||||
|
z-index: 992;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._search {
|
||||||
|
background: var(--bg2);
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._search>.itm {
|
||||||
|
background: var(--bg1);
|
||||||
|
border: 1px solid var(--bg4);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop._top {
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop._top ._list._flex {
|
||||||
|
/* flex-direction: column-reverse; */
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list._flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: left;
|
||||||
|
overscroll-behavior-y: contain !important;
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._item._select {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--man6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list._flex ._item {
|
||||||
|
padding: 1em 1em;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list._grid {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: left;
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list._grid ._item {
|
||||||
|
padding: 1em 1em;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop._top ._list._grid {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop._top ._list._grid ._item {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list ._nodata {
|
||||||
|
background: var(--bg2);
|
||||||
|
text-align: center;
|
||||||
|
padding: 2em 0 1em 0;
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show {
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show._left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show._left ._txt {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show ._arrow {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show ._arrow._sel {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
backgroundx: #f3abec99;
|
||||||
|
z-index: 992;
|
||||||
|
backdrop-filterx: blur(10px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,459 @@
|
||||||
|
<template>
|
||||||
|
<view class="_select">
|
||||||
|
<view class="_mask" @touchmove.stop.prevent="() => { }" v-if="popclass" @tap="hidepop"></view>
|
||||||
|
<view class="_pop" :animation="anidatapop" v-if="popclass" :class="popclass">
|
||||||
|
<view class="ciy-hr"></view>
|
||||||
|
<view class="_search" v-if="mrange.length > minselectsearch">
|
||||||
|
<view class="itm">
|
||||||
|
<input v-model="searchval" :placeholder="lang('placeholder.key')" @confirm="searchconfirm" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view id="select_list" class="_list" :scroll-top="itemtop" scroll-y>
|
||||||
|
<slot name="list" :data="{range:mrange,searchkey:searchval,popclass:popclass,onselect:Selitem}">
|
||||||
|
<view :class="rows==1?'_flex':'_grid'" :style="'grid-template-columns: repeat('+rows+', 1fr);text-align:' + itemalign">
|
||||||
|
<view :id="'selectitem-' + index" class="_item" :class="{_select:tvalue.id==item.id}" v-for="(item,index) in mrange" :key="index" @tap="Selitem(index)">
|
||||||
|
{{item.name}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<template v-if="mrange.length == 0">
|
||||||
|
<view v-if="searchval" class="_nodata">
|
||||||
|
{{lang('select.nosearch')}}
|
||||||
|
<text class="_code">{{searchval}}</text>
|
||||||
|
</view>
|
||||||
|
<view v-else class="_nodata">{{lang('select.nodata')}}</view>
|
||||||
|
</template>
|
||||||
|
</slot>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="ciy-hr"></view>
|
||||||
|
<view style="flex:1;pointer-events: none;width:100%;" @touchmove.stop.prevent="() => { }" @tap="hidepop"></view>
|
||||||
|
</view>
|
||||||
|
<view class="_show" :class="{_left:left}" @tap="showpop">
|
||||||
|
<view class="_txt" :style="ciystyle">
|
||||||
|
<view v-if="tvalue.name" :style="{color:disabled?'var(--bg6)':'var(--txt9)'}">{{tvalue.name}}</view>
|
||||||
|
<view v-else-if="placeholder !== ''" style="color:var(--txt1);">{{placeholder?placeholder:lang('placeholder.select')}}</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="!noarrow" class="_arrow ciy-icon-arrow" :class="{_sel:popclass}"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<input type="hidden" :name="name" :value="tvalue.id" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_name'" :value="tvalue.name" style="display:none;" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'search'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
chkuse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
diastema: { //上下间隙
|
||||||
|
type: Number,
|
||||||
|
default: 16
|
||||||
|
},
|
||||||
|
itemalign: { //item对齐
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
all: { //0值选项
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
noarrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
rows: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
minselectsearch: { //选项少于n,则不显示搜索
|
||||||
|
type: Number,
|
||||||
|
default: 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: '',
|
||||||
|
searchval: '', //搜索键入内容
|
||||||
|
popclass: '', //值包含[btm/top],制定弹出在上方还是下方
|
||||||
|
anidatapop: {}, //弹出的选项动画
|
||||||
|
itemtop: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
searchval: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.$emit('search', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
com: this,
|
||||||
|
value: newD
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
mrange() {
|
||||||
|
var mr = [];
|
||||||
|
if (this.all)
|
||||||
|
mr.push({
|
||||||
|
id: 0,
|
||||||
|
name: this.all
|
||||||
|
});
|
||||||
|
var tmprange = this.range;
|
||||||
|
if (!this.isarray(this.range)) {
|
||||||
|
tmprange = [];
|
||||||
|
let oprang = (this.range + '').split('.');
|
||||||
|
for (let r in oprang) {
|
||||||
|
let idx = oprang[r].indexOf(':');
|
||||||
|
if (idx <= 0)
|
||||||
|
continue;
|
||||||
|
tmprange.push({
|
||||||
|
id: oprang[r].substring(0, idx),
|
||||||
|
name: oprang[r].substring(idx + 1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i in tmprange) {
|
||||||
|
if (this.chkuse && tmprange[i].isuse == 2)
|
||||||
|
continue;
|
||||||
|
if (tmprange[i].name.indexOf(this.searchval) > -1)
|
||||||
|
mr.push(tmprange[i]);
|
||||||
|
}
|
||||||
|
return mr;
|
||||||
|
},
|
||||||
|
tvalue() {
|
||||||
|
var val = '';
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = this.modelValue;
|
||||||
|
else if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = this.value;
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
} else if (this.v instanceof Object) {
|
||||||
|
return this.v;
|
||||||
|
}
|
||||||
|
for (var i in this.mrange) {
|
||||||
|
if (this.mrange[i].id == val)
|
||||||
|
return {
|
||||||
|
index: i,
|
||||||
|
...this.mrange[i]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (this.mrange.length > 0 && this.placeholder === '')
|
||||||
|
return {
|
||||||
|
index: 0,
|
||||||
|
...this.mrange[0]
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
id: 0,
|
||||||
|
index: -1,
|
||||||
|
name: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: {
|
||||||
|
...this.tvalue
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.lastvalue = {
|
||||||
|
...this.tvalue
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
searchconfirm(e) {
|
||||||
|
this.$emit('search', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'confirm',
|
||||||
|
com: this,
|
||||||
|
value: e.detail.value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Selitem(index) {
|
||||||
|
this.v = {
|
||||||
|
index: index,
|
||||||
|
...this.mrange[index]
|
||||||
|
};
|
||||||
|
this.$emit('update:modelValue', this.v.id);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'select',
|
||||||
|
value: {
|
||||||
|
index: index,
|
||||||
|
...this.v
|
||||||
|
},
|
||||||
|
lastvalue: this.lastvalue
|
||||||
|
});
|
||||||
|
this.lastvalue = {
|
||||||
|
index: index,
|
||||||
|
...this.v
|
||||||
|
};
|
||||||
|
this.hidepop();
|
||||||
|
},
|
||||||
|
hidepop() {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('100vw');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
animation.height('auto');
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.popclass = '';
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
async showpop() {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
var app = getApp();
|
||||||
|
app.globalData.scrollcbs['com_select'] = e => {
|
||||||
|
delete app.globalData.scrollcbs['com_select'];
|
||||||
|
this.hidepop();
|
||||||
|
};
|
||||||
|
const {
|
||||||
|
headerheight,
|
||||||
|
footerheight
|
||||||
|
} = await this.com_gethdft();
|
||||||
|
var fixtop = 0;
|
||||||
|
|
||||||
|
this.searchval = '';
|
||||||
|
this.popclass = 'temp';
|
||||||
|
var mainrect = await this.getrect('._pop');
|
||||||
|
if (!mainrect)
|
||||||
|
return;
|
||||||
|
var showrect = await this.getrect('._show');
|
||||||
|
if (!showrect)
|
||||||
|
return;
|
||||||
|
var toph = showrect.top - headerheight - this.diastema;
|
||||||
|
var btmh = app.globalData._sysinfo.windowHeight - footerheight - showrect.bottom - this.diastema;
|
||||||
|
var topcls = '_btm';
|
||||||
|
var syheight, sytop;
|
||||||
|
if (toph > btmh) {
|
||||||
|
topcls = '_top';
|
||||||
|
syheight = mainrect.height;
|
||||||
|
if (syheight > toph)
|
||||||
|
syheight = toph;
|
||||||
|
sytop = headerheight + fixtop + toph - syheight;
|
||||||
|
} else {
|
||||||
|
syheight = mainrect.height;
|
||||||
|
if (syheight > btmh)
|
||||||
|
syheight = btmh;
|
||||||
|
sytop = showrect.bottom + this.diastema - fixtop;
|
||||||
|
}
|
||||||
|
this.popclass = topcls;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX(0);
|
||||||
|
animation.top(sytop);
|
||||||
|
animation.height(syheight);
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
this.anidatapop = animation.export();
|
||||||
|
if (!this.tvalue.index)
|
||||||
|
return;
|
||||||
|
this.itemtop = 0;
|
||||||
|
setTimeout(async () => {
|
||||||
|
var listrect = await this.getrect('#select_list');
|
||||||
|
var rect = await this.getrect('#selectitem-' + this.tvalue.index);
|
||||||
|
if (!rect || !listrect)
|
||||||
|
return;
|
||||||
|
this.itemtop = rect.top - listrect.height / 2 - listrect.top;
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._select ._pop {
|
||||||
|
position: fixed;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
opacity: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transform: translateX(100vw);
|
||||||
|
transform: translateY(38px);
|
||||||
|
z-index: 992;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._search {
|
||||||
|
background: var(--bg2);
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._search>.itm {
|
||||||
|
background: var(--bg1);
|
||||||
|
border: 1px solid var(--bg4);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop._top {
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: left;
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list ._flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
overscroll-behavior-y: contain !important;
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._item._select {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--man6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list ._flex ._item {
|
||||||
|
padding: 1em 1em;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list ._grid {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: left;
|
||||||
|
background: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list ._grid ._item {
|
||||||
|
padding: 1em 1em;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._pop ._list ._nodata {
|
||||||
|
background: var(--bg2);
|
||||||
|
text-align: center;
|
||||||
|
padding: 2em 0 1em 0;
|
||||||
|
color: var(--txt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show {
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show._left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show._left ._txt {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show ._arrow {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._show ._arrow._sel {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
._select ._mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
backgroundx: #f3abec99;
|
||||||
|
z-index: 992;
|
||||||
|
backdrop-filterx: blur(10px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<input type="hidden" v-if="name=='loc'" name="lng" :value="tvalue.lng" style="display:none;" />
|
||||||
|
<input type="hidden" v-else :name="name+'_lng'" :value="tvalue.lng" style="display:none;" />
|
||||||
|
<input type="hidden" v-if="name=='loc'" name="lat" :value="tvalue.lat" style="display:none;" />
|
||||||
|
<input type="hidden" v-else :name="name+'_lat'" :value="tvalue.lat" style="display:none;" />
|
||||||
|
<template v-if="hasmore">
|
||||||
|
<input type="hidden" :name="name+'_name'" :value="loc.name" style="display:none;" />
|
||||||
|
<input type="hidden" :name="name+'_addr'" :value="loc.addr" style="display:none;" />
|
||||||
|
<input type="hidden" :name="name+'_latlng'" :value="tvalue.lat+','+tvalue.lng" style="display:none;" />
|
||||||
|
</template>
|
||||||
|
<view style="display:flex;align-items: center;">
|
||||||
|
<template v-if="left">
|
||||||
|
<view class="_btn" :class="{_disabled:disabled}" @tap="map_select">
|
||||||
|
<view class="_icon _mapicon"></view>
|
||||||
|
</view>
|
||||||
|
<slot name="show" :data="{value:tvalue, loc:loc, bet:innerbet}">
|
||||||
|
<view style="line-height:1.5em;font-size:0.9em;flex: 1; margin-left:0.5em;text-align:left;">
|
||||||
|
<view v-if="loc.name || loc.addr">{{loc.name}}<br />{{loc.addr}}</view>
|
||||||
|
<view v-else-if="tvalue.lat == 0" style="padding-top:0.3em;display:inline-block;">{{lang('selmap.select')}}</view>
|
||||||
|
<view v-else style="padding-top:0.3em;display:inline-block;">{{lang('selmap.loced')}}</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<slot name="show" :data="{value:tvalue, loc:loc, bet:innerbet}">
|
||||||
|
<view style="line-height:1.5em;font-size:0.9em;flex: 1; margin-right:0.5em;">
|
||||||
|
<view v-if="loc.name || loc.addr">{{loc.name}}<br />{{loc.addr}}</view>
|
||||||
|
<view v-else-if="tvalue.lat == 0" style="padding-top:0.3em;display:inline-block;">{{lang('selmap.select')}}</view>
|
||||||
|
<view v-else style="padding-top:0.3em;display:inline-block;">{{lang('selmap.loced')}}</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
<view class="_btn" :class="{_disabled:disabled}" @tap="map_select">
|
||||||
|
<view class="_icon _mapicon"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import gcoord from '@/util/gcoord.js'
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['update:lng', 'update:lat', 'change'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: 'loc'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bet: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 10000000
|
||||||
|
},
|
||||||
|
lat: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
lng: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loc: {},
|
||||||
|
vlat: null,
|
||||||
|
vlng: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
lat: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.vlat = null;
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
lng: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.vlng = null;
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
var ret = {};
|
||||||
|
if (this.vlat !== null) {
|
||||||
|
ret.lat = this.vlat;
|
||||||
|
} else {
|
||||||
|
ret.lat = this.tofloat(this.lat);
|
||||||
|
}
|
||||||
|
if (this.vlng !== null) {
|
||||||
|
ret.lng = this.vlng;
|
||||||
|
} else {
|
||||||
|
ret.lng = this.tofloat(this.lng);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
innerbet() {
|
||||||
|
var bet = this.bet;
|
||||||
|
if (bet <= 1)
|
||||||
|
return 1;
|
||||||
|
return this.toint(bet);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
async map_select(e) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
var result;
|
||||||
|
if (this.toint(this.lat) == 0) {
|
||||||
|
result = this.getstorage('_map');
|
||||||
|
if (!result || result.length != 2) {
|
||||||
|
result = [1164000000, 398000000];
|
||||||
|
} else {
|
||||||
|
result[0] += 50000 * Math.random();
|
||||||
|
result[1] += 50000 * Math.random();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = gcoord.transform([this.lng / this.innerbet, this.lat / this.innerbet], gcoord.WGS84, gcoord.GCJ02);
|
||||||
|
result[0] = this.caldectoint(result[0]);
|
||||||
|
result[1] = this.caldectoint(result[1]);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var retchoose = await uni.chooseLocation({
|
||||||
|
longitude: result[0] / this.innerbet,
|
||||||
|
latitude: result[1] / this.innerbet
|
||||||
|
});
|
||||||
|
} catch (res) {
|
||||||
|
if (res.errMsg.indexOf('cancel') > -1)
|
||||||
|
return;
|
||||||
|
this.alert(res.errMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!retchoose.longitude)
|
||||||
|
return this.alert(this.lang('selmap.noselect'));
|
||||||
|
var result = gcoord.transform([retchoose.longitude, retchoose.latitude], gcoord.GCJ02, gcoord.WGS84);
|
||||||
|
result[0] = this.caldectoint(result[0]);
|
||||||
|
result[1] = this.caldectoint(result[1]);
|
||||||
|
this.setstorage('_map', result);
|
||||||
|
this.loc.name = retchoose.name;
|
||||||
|
this.loc.addr = retchoose.address;
|
||||||
|
this.loc.distance = retchoose.distance;
|
||||||
|
this.$emit('update:lng', result[0]);
|
||||||
|
this.$emit('update:lat', result[1]);
|
||||||
|
this.vlat = result[1];
|
||||||
|
this.vlng = result[0];
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'choose',
|
||||||
|
value: {
|
||||||
|
...this.loc
|
||||||
|
},
|
||||||
|
lng: result[0],
|
||||||
|
lat: result[1]
|
||||||
|
});
|
||||||
|
|
||||||
|
//gcj02
|
||||||
|
// gcoord.WGS84 [lng,lat] WGS-84坐标系,GPS设备获取的经纬度坐标
|
||||||
|
// gcoord.GCJ02 [lng,lat] GCJ-02坐标系,google中国地图、soso地图、aliyun地图、mapabc地图和高德地图所用的经纬度坐标
|
||||||
|
// gcoord.BD09 [lng,lat] BD-09坐标系,百度地图采用的经纬度坐标
|
||||||
|
// gcoord.BD09LL [lng,lat] 同BD09
|
||||||
|
// gcoord.BD09MC [x,y] BD-09米制坐标,百度地图采用的米制坐标,单位:米
|
||||||
|
// gcoord.BD09Meter [x,y] 同BD09MC
|
||||||
|
// gcoord.Baidu [lng,lat] 百度坐标系,BD-09坐标系别名,同BD-09
|
||||||
|
// gcoord.BMap [lng,lat] 百度地图,BD-09坐标系别名,同BD-09
|
||||||
|
// gcoord.AMap [lng,lat] 高德地图,同GCJ-02
|
||||||
|
// gcoord.WebMercator [x,y] Web Mercator投影,墨卡托投影,同EPSG3857,单位:米
|
||||||
|
// gcoord.WGS1984 [lng,lat] WGS-84坐标系别名,同WGS-84
|
||||||
|
// gcoord.EPSG4326 [lng,lat] WGS-84坐标系别名,同WGS-84
|
||||||
|
// gcoord.EPSG3857 [x,y] Web Mercator投影,同WebMercator,单位:米
|
||||||
|
// gcoord.EPSG900913 [x,y] Web Mercator投影,同WebMercator,单位:米
|
||||||
|
},
|
||||||
|
caldectoint(dec) {
|
||||||
|
if (this.innerbet <= 1)
|
||||||
|
return dec;
|
||||||
|
return this.toint(dec * this.innerbet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._btn {
|
||||||
|
padding: 0.2em;
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
._btn._disabled {
|
||||||
|
background: #ebebeb;
|
||||||
|
filter: grayscale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
._icon._mapicon {
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PHBhdGggZD0nTTUxMiA1MTJtLTUxMiAwYTUxMiA1MTIgMCAxIDAgMTAyNCAwIDUxMiA1MTIgMCAxIDAtMTAyNCAwWicgZmlsbD0nIzFFOUZGRic+PC9wYXRoPjxwYXRoIGQ9J002NjguNTQxIDM0NS43MTRjMC05MS41NzktODAuOTIxLTE2My45OS0xNzAuMzc3LTE2My45OS04OS40NSAwLTE2OC4yNDMgNzIuNDA5LTE2OC4yNDMgMTYzLjk4OSAwIDgzLjA1MyAxNjguMjQzIDI4My4yNTggMTY4LjI0MyAyODMuMjU4czE3MC4zNzctMTk1Ljk0MyAxNzAuMzc3LTI4My4yNTd6IG0tMjMyLjEzNSA4LjUyMmMwLTM2LjIxIDI5LjgxLTY2LjAyMiA2My44ODUtNjMuODk3IDM0LjA4OSAwIDYzLjg5OSAyNy42ODcgNjMuODk5IDYzLjg5NyAwLjAwMSAzNC4wNzUtMjcuNjkyIDYzLjg4NS02My44OTkgNjMuODg1LTM0LjA3NSAwLjAwMS02My44ODUtMjcuNjc5LTYzLjg4NS02My44ODV6JyBmaWxsPScjRkZGRkZGJz48L3BhdGg+PHBhdGggZD0nTTUzNi40NjUgNzU4Ljc2bC0yLjA4Ni02LjI2N2MyLjYwMi0wLjk3NyA1LjIwNC0xLjk1NSA3LjgyOC0yLjk1MyAzMi4zMDUtNDcuMjM5IDEwMC4xNDYtNzkuNzc2IDE3OC42MjMtNzkuNzc2IDIuOTM4IDAgNS44NTkgMC4wNTYgOC43NjcgMC4xNDZsLTEuNDIxLTQuNzMyYzIxLjMwMS02LjM5NiA0NC43My04LjUxNiA2Ni4wMjktMTAuNjU1aC0wLjAwMXYyMS4zMTFjLTMuNTA3IDAuMzg4LTcuMDE1IDAuNzc3LTEwLjUzNiAxLjE5MSAxMS44NTUgMi44MjMgMjMuMjEgNi40MjggMzMuOTU0IDEwLjcyMlY1MDEuMTg4YzAtMjMuNDI5LTE5LjE2NS00Mi41OTktNDQuNzE1LTQyLjU5OUg2NjQuMjk0Yy02MS43NjYgMTA4LjYxNi0xNjguMjUyIDIzMi4xNDctMTY4LjI1MiAyMzIuMTQ3UzM5My44MDkgNTY3LjIwNCAzMzQuMTc0IDQ1OC41OWgtODcuMzE4Yy0yMy40MyAwLTQ0LjcxNiAxOS4xNjctNDQuNzE2IDQyLjU5OXYyOTguMTY2YzAgMjMuNDE4IDIxLjI4NiA0Mi41ODYgNDQuNzE2IDQyLjU4NmgyNzkuNjljLTIuOTEtOS42ODEtNC40NTYtMTkuNzIzLTQuNDU2LTMwLjAyMyAwLTE4Ljc5NyA1LjExMS0zNi43MzYgMTQuMzc1LTUzLjE1OHogbS0yNDkuMTQyLTMzLjk0N2MtMTkuMTY3LTguNTI1LTM2LjIwNy0yMS4zMDEtNTUuMzcyLTM0LjA3NWwxMi43NzQtMTcuMDVjMTcuMDM3IDEyLjc4NiAzNi4yMDUgMjMuNDI5IDUzLjI0IDM0LjA3NmwtMTAuNjQyIDE3LjA0OXogbTk3Ljk3MiA0NC43MThjLTE5LjE2Ny04LjUxNi0zOC4zMzQtMTQuOTA3LTU5LjYzNS0yMy40MzRsOC41MTQtMTkuMTY5YzE5LjE2NiA4LjUyNiAzOC4zMzcgMTcuMDU0IDU3LjUwMyAyMS4zMTNsLTYuMzgyIDIxLjI5eiBtNzIuNDExIDEyLjc4NGMtOC41MjQgMC0xNy4wMzctMi4xMzQtMjcuNjkzLTQuMjYzbDQuMjY0LTIxLjI5OGM4LjUyMSAyLjEzIDE5LjE2NyAyLjEzIDI3LjY4MSA0LjI2MSAxMC42NTYgMi4xMzMgMjEuMjk4IDAgMzEuOTU3IDBsMi4xMjkgMjEuM2ExMTYuMzQ1IDExNi4zNDUgMCAwIDEtMzguMzM4IDB6JyBmaWxsPScjRkZGRkZGJz48L3BhdGg+PHBhdGggZD0nTTc3Mi45MDcgODQxLjkzOWMyMy40MTggMCA0NC43MTUtMTkuMTY2IDQ0LjcxNS00Mi41ODdWNjg3Ljc0NGMtMTAuNzQ0LTQuMjk0LTIyLjA5OS03Ljg5Ny0zMy45NTQtMTAuNzIyLTE1LjcxOSAxLjg1My0zMS42OTkgNC4yMjktNDkuMDk5IDkuNDVsLTQuOTc0LTE2LjU2M2EyNzkuOTgxIDI3OS45ODEgMCAwIDAtOC43NjctMC4xNDZjLTc4LjQ3NyAwLTE0Ni4zMTggMzIuNTM3LTE3OC42MjMgNzkuNzc2IDE0LjU2MS01LjU0MSAyOS44MTgtMTEuNzczIDQ5LjY2MS0yMi42MDlsOC41MjUgMTkuMTY5Yy0yMy40MyAxMC42NTctNDIuNTk4IDE5LjE2OS01OS42MzUgMjUuNTZsLTQuMjk1LTEyLjg5OGMtOS4yNjQgMTYuNDIyLTE0LjM3NSAzNC4zNjEtMTQuMzc1IDUzLjE1NiAwIDEwLjMwMiAxLjU0NiAyMC4zNDQgNC40NTYgMzAuMDIzaDI0Ni4zNjV6IG0tODMuMDY0LTE2My45ODZsOC41MjUgMTkuMTY0Yy0xOS4xNjkgOC41MjUtMzYuMjA3IDE3LjA1MS01OS42MzcgMjcuNjk0bC04LjUyMS0xOS4xNjhjMjMuNDMtMTAuNjQyIDQwLjQ2NS0xOS4xNjUgNTkuNjMzLTI3LjY5eicgZmlsbD0nI0ZGRkZGRicgb3BhY2l0eT0nLjQnPjwvcGF0aD48L3N2Zz4=");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
<template>
|
||||||
|
<view class="_selpage">
|
||||||
|
<view class="_show" :class="{_left:left}">
|
||||||
|
<view class="btn sm" :class="{dis:disabled}" @tap="selpage">{{btn}}</view>
|
||||||
|
<view class="_txt" :style="style2obj(ciystyle, {color:disabled?'var(--bg6)':'var(--txt9)'})" v-if="tvalue.id>0">
|
||||||
|
<slot :data="tvalue">
|
||||||
|
<view v-html="tvalue.name"></view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<view class="_txt" :style="style2obj(ciystyle, {color:'var(--txt1)'})" v-else>{{placeholder?placeholder:lang('placeholder.select')}}</view>
|
||||||
|
</view>
|
||||||
|
<input type="hidden" :name="name" :value="tvalue.id" style="display:none;" />
|
||||||
|
<input v-if="hasmore" type="hidden" :name="name+'_more'" :value="tvalue._more" style="display:none;" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasmore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
morevalue: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
btn: {
|
||||||
|
type: String,
|
||||||
|
default: '选取'
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innermore: {},
|
||||||
|
v: {
|
||||||
|
id: 0,
|
||||||
|
_more: ''
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
morevalue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
this.v = this.modelValue || this.value;
|
||||||
|
this.innermore = {
|
||||||
|
...newD
|
||||||
|
};
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
var val = '';
|
||||||
|
var valmore = {
|
||||||
|
...this.innermore
|
||||||
|
};
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
val = this.modelValue;
|
||||||
|
else
|
||||||
|
val = this.modelValue;
|
||||||
|
valmore.id = val;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
val = this.value;
|
||||||
|
else
|
||||||
|
val = this.value;
|
||||||
|
valmore.id = val;
|
||||||
|
} else if (this.v instanceof Object) {
|
||||||
|
valmore = {
|
||||||
|
...this.v
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
valmore.id = this.v;
|
||||||
|
}
|
||||||
|
valmore._more = this.setstrparam(valmore);
|
||||||
|
return valmore;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: {
|
||||||
|
...this.tvalue
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selpage(e) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
uni.navigateTo({
|
||||||
|
url: this.page + '?sel=true&id=' + this.tvalue.id,
|
||||||
|
events: {
|
||||||
|
writedata: data => {
|
||||||
|
this.v = {
|
||||||
|
...data
|
||||||
|
};
|
||||||
|
this.innermore = {
|
||||||
|
...data
|
||||||
|
};
|
||||||
|
this.$emit('update:modelValue', data.id);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'selpage',
|
||||||
|
value: {
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
._selpage {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._selpage ._show {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._selpage ._show._left {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
._selpage ._show._left ._txt {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
<template>
|
||||||
|
<view style="display:flex;">
|
||||||
|
<view v-if="picarr.length > 0 && label" style="width: 1em;margin-right: 0.5em;line-height: 1.2em;color: #999999;">{{label}}</view>
|
||||||
|
<view v-if="type == 'thumb'" style="flex:1;">
|
||||||
|
<video :id="'video' + index" v-for="(item,index) in videoarr" :key="index" :src="file_stor(item)" controls @tap="fullvideo('video' + index)" :show-fullscreen-btn="false" :style="{width:width,height:height,margin:'0 0.5em 0 0'}"></video>
|
||||||
|
<image lazy-load :lazy-load-margin="0" @tap.stop="preview(index)" :src="item" v-for="(item,index) in picarr" :key="index" :mode="mode" :style="{width:width,height:height,margin:'0 0.5em 0 0'}" style="border-radius:0.3em;" />
|
||||||
|
<view @tap.stop="openfile(index)" v-for="(item,index) in pdfarr" :key="index" :style="{width:width,height:height,lineHeight: height}" style="margin:0 0.5em 0 0;border-radius:0.3em;display:inline-block;vertical-align: top;border: 1px solid #cccccc;text-align: center;color:#000000;background: #ffffff;">{{lang('showimgs.att')}}{{index+1}}</view>
|
||||||
|
</view>
|
||||||
|
<view v-else style="flex:1;">
|
||||||
|
<video :id="'video' + index" v-for="(item,index) in videoarr" :key="index" :src="file_stor(item)" controls @tap="fullvideo('video' + index)" :show-fullscreen-btn="false" :style="{width:width,margin:'0 0 -2px 0;'}"></video>
|
||||||
|
<image lazy-load :lazy-load-margin="0" @tap.stop="preview(index)" :src="item" v-for="(item,index) in picarr" :key="index" :mode="mode" :style="{width:width}" style="margin:0 0 -2px 0;" />
|
||||||
|
<view @tap.stop="openfile(index)" v-for="(item,index) in pdfarr" :key="index" :style="{width:width,height:height,lineHeight: height,margin:index==0?'0':'0 0.5em 0 0'}" style="border-radius:0.3em;display:inline-block;vertical-align: top;border: 1px solid #cccccc;text-align: center;color:#000000;background: #ffffff;">{{lang('showimgs.att')}}{{index+1}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '5em'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '5em'
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'thumb'
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'aspectFill'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
picarr: [],
|
||||||
|
picoriarr: [],
|
||||||
|
pdfarr: [],
|
||||||
|
videoarr: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
src(newD, oldD) {
|
||||||
|
this.fill();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fill();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fill() {
|
||||||
|
this.picarr = [];
|
||||||
|
this.picoriarr = [];
|
||||||
|
var ps = this.src.split('~');
|
||||||
|
var images = [];
|
||||||
|
for (var i = 0; i < ps.length; i++) {
|
||||||
|
if (ps[i].length == 0)
|
||||||
|
continue;
|
||||||
|
var ind = ps[i].lastIndexOf('.');
|
||||||
|
var ext = ps[i].substring(ind + 1).toUpperCase();
|
||||||
|
if (ext == 'JPG' || ext == 'JPEG' || ext == 'GIF' || ext == 'PNG' || ext == 'WEBP')
|
||||||
|
images.push(ps[i]);
|
||||||
|
else if (ext == 'MP4')
|
||||||
|
this.videoarr.push(ps[i]);
|
||||||
|
else
|
||||||
|
this.pdfarr.push(ps[i]);
|
||||||
|
}
|
||||||
|
for (var i in images) {
|
||||||
|
this.picarr.push(this.file_stor(images[i], 'thumb'));
|
||||||
|
this.picoriarr.push(this.file_stor(images[i]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preview(idx) {
|
||||||
|
uni.previewImage({
|
||||||
|
current: idx,
|
||||||
|
indicator: 'default',
|
||||||
|
urls: this.picoriarr
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openfile(idx) {
|
||||||
|
var app = getApp();
|
||||||
|
app.toast('Downloading...');
|
||||||
|
var url = this.file_stor(this.pdfarr[idx]);
|
||||||
|
uni.downloadFile({
|
||||||
|
url: url,
|
||||||
|
success: res => {
|
||||||
|
uni.openDocument({
|
||||||
|
filePath: res.tempFilePath,
|
||||||
|
showMenu: true,
|
||||||
|
fail: res => {
|
||||||
|
app.toast('Open Document Fail:' + res.errMsg + '\n' + url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: res => {
|
||||||
|
app.toast('Down Document Fail:' + res.errMsg + '\n' + url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fullvideo(id) {
|
||||||
|
const videoContext = uni.createVideoContext(id, this);
|
||||||
|
videoContext.requestFullScreen({
|
||||||
|
direction: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<template>
|
||||||
|
<view style="display:inline-block;" :style="ciystyle">
|
||||||
|
<text :style="intstyle">{{p1}}</text>
|
||||||
|
<text :style="decstyle">{{p2}}</text>
|
||||||
|
<text :style="decstyle">{{unit}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
dec0: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
intstyle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
decstyle: {
|
||||||
|
type: String,
|
||||||
|
default: 'font-size:0.7em;'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
p1() {
|
||||||
|
if (this.unit == '万元')
|
||||||
|
return this.toint(this.value / 1000000);
|
||||||
|
else
|
||||||
|
return this.toint(this.value / 100);
|
||||||
|
},
|
||||||
|
p2() {
|
||||||
|
if (this.unit == '万元')
|
||||||
|
return this.tonumdec(this.value / 1000000, this.dec0, 3);
|
||||||
|
else if (this.unit == '元')
|
||||||
|
return this.tonumdec(this.value / 100, this.dec0, 2);
|
||||||
|
else
|
||||||
|
return this.tonumdec(this.value / 100, this.dec0, 2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
<template>
|
||||||
|
<view style="display:inline-block;">
|
||||||
|
{{p1}}<text style="font-size:0.6em;">{{p2}}</text><text style="font-size:0.6em;padding-left:0.3em;">{{punit}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}, //元,100,2|万元,1000000,3|亿元,10000000000,3 单位,除数,保留位数
|
||||||
|
speed: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
p1: 0,
|
||||||
|
p2: '',
|
||||||
|
punit: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newD, oldD) {
|
||||||
|
if (this.inter) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fillnum(newD);
|
||||||
|
}, 500);
|
||||||
|
} else
|
||||||
|
this.ani(newD, oldD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
speeddata() {
|
||||||
|
var speed = this.toint(this.speed);
|
||||||
|
if(speed < 3)
|
||||||
|
speed = 10;
|
||||||
|
return speed;
|
||||||
|
},
|
||||||
|
units() {
|
||||||
|
var unitss = this.unit.replace(/\*/g, '').split('|');
|
||||||
|
var units = [];
|
||||||
|
for (var i in unitss) {
|
||||||
|
var u = {};
|
||||||
|
var ss = unitss[i].split(',');
|
||||||
|
u.unit = ss[0];
|
||||||
|
u.bet = parseInt(ss[1]);
|
||||||
|
u.fix = parseInt(ss[2]);
|
||||||
|
if (isNaN(u.bet))
|
||||||
|
u.bet = 1;
|
||||||
|
if (u.bet < 1)
|
||||||
|
u.bet = 1;
|
||||||
|
if (isNaN(u.fix))
|
||||||
|
u.fix = 0;
|
||||||
|
units.unshift(u);
|
||||||
|
}
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.ani(this.value, -1);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
ani(newD, oldD) {
|
||||||
|
if (newD == oldD)
|
||||||
|
return;
|
||||||
|
var step = (newD - oldD) / this.speeddata;
|
||||||
|
var val = parseFloat(oldD);
|
||||||
|
var stepi = 0;
|
||||||
|
this.inter = setInterval(() => {
|
||||||
|
val += step;
|
||||||
|
stepi++;
|
||||||
|
if (stepi > this.speeddata) {
|
||||||
|
clearInterval(this.inter);
|
||||||
|
this.inter = null;
|
||||||
|
this.fillnum(newD);
|
||||||
|
} else
|
||||||
|
this.fillnum(val);
|
||||||
|
}, 16);
|
||||||
|
},
|
||||||
|
fillnum(value) {
|
||||||
|
value = parseInt(value);
|
||||||
|
if (isNaN(value))
|
||||||
|
value = 0;
|
||||||
|
for (var u in this.units) {
|
||||||
|
var val = value / this.units[u].bet;
|
||||||
|
if (val < 1 && u < this.units.length - 1)
|
||||||
|
continue;
|
||||||
|
val = this.tofix(val, this.units[u].fix) + '';
|
||||||
|
var ind = val.indexOf('.');
|
||||||
|
if (ind === -1) {
|
||||||
|
this.p1 = val;
|
||||||
|
this.p2 = '';
|
||||||
|
} else {
|
||||||
|
this.p1 = val.substr(0, ind);
|
||||||
|
this.p2 = val.substr(ind);
|
||||||
|
}
|
||||||
|
this.punit = this.units[u].unit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<view style="width:100%;position: relative;display:flex;">
|
||||||
|
<slider :name="name" :value="txtvalue" :style="ciystyle" :disabled="disabled" :min="min" :max="max" :step="step" :show-value="false" @changing="textchanging" @change="textchange" style="width: 100%;margin: 0 1em;" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 100
|
||||||
|
},
|
||||||
|
step: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
txtvalue() {
|
||||||
|
if (typeof(this.modelValue) == 'number')
|
||||||
|
return this.modelValue;
|
||||||
|
if (typeof(this.value) == 'number')
|
||||||
|
return this.value;
|
||||||
|
if (this.modelValue)
|
||||||
|
return this.modelValue;
|
||||||
|
if (this.value)
|
||||||
|
return this.value;
|
||||||
|
return this.min;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.txtvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
textchanging(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'changing',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
textchange(e) {
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'changed',
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
<template>
|
||||||
|
<template v-if="!src"></template>
|
||||||
|
<image v-else-if="type == 'img'" class="_wh100" :src="srcdata" :mode="mode" :style="cstyle" />
|
||||||
|
<view v-else-if="type == 'svg'" class="_wh100" :style="cstyle"></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._wh100 {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
virtualHost: false
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'widthFix'
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
type: '',
|
||||||
|
srcdata: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
src: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (typeof(newD) != 'string')
|
||||||
|
return;
|
||||||
|
if (newD.substring(0, 5).toLowerCase() == '<svg ') {
|
||||||
|
this.type = 'svg';
|
||||||
|
this.srcdata = this.svg2bg(newD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var ext = this.file_ext(newD);
|
||||||
|
if (ext == 'SVG') {
|
||||||
|
this.calltxt({
|
||||||
|
url: this.file_stor(newD),
|
||||||
|
}).then(res => {
|
||||||
|
this.type = 'svg';
|
||||||
|
this.srcdata = this.svg2bg(res);
|
||||||
|
}).catch(err => {
|
||||||
|
err._url = url;
|
||||||
|
this.uperr("h5.loadsvg.fail", err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.type = 'img';
|
||||||
|
this.srcdata = this.file_stor(newD);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
cstyle() {
|
||||||
|
var csty = this.style2obj(this.ciystyle);
|
||||||
|
if (this.type == 'svg' && this.srcdata) {
|
||||||
|
if (!csty['display'])
|
||||||
|
csty['display'] = 'inline-block';
|
||||||
|
csty['backgroundImage'] = this.srcdata;
|
||||||
|
}
|
||||||
|
return csty;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
<template>
|
||||||
|
<view class="_list" :style="{borderBottom:noborder?'none':''}">
|
||||||
|
<view class="_icon" v-if="icon">
|
||||||
|
<ciy-svgimg :src="icon"></ciy-svgimg>
|
||||||
|
</view>
|
||||||
|
<view class="_title">{{lang(title)}}</view>
|
||||||
|
<slot></slot>
|
||||||
|
<view class="_right txt-wl" v-if="right" v-html="lang(right)"></view>
|
||||||
|
<view class="_reddot" v-if="reddot">{{reddot>99?'99+':reddot}}</view>
|
||||||
|
<view class="_more" v-if="more"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._list {
|
||||||
|
position: relative;
|
||||||
|
background: var(--bg2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid var(--bg6);
|
||||||
|
height: 3.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list>._icon {
|
||||||
|
pointer-events: none;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 1.6em;
|
||||||
|
height: 1.6em;
|
||||||
|
margin-left: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list>._title {
|
||||||
|
pointer-events: none;
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 1em;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--txt9);
|
||||||
|
/* overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
min-width: 7em; */
|
||||||
|
line-height: 1.1em;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
._list>._right {
|
||||||
|
pointer-events: none;
|
||||||
|
text-align: right;
|
||||||
|
margin: 0 1em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
overflow: hidden;
|
||||||
|
max-height: 100%;
|
||||||
|
color: var(--txt6);
|
||||||
|
}
|
||||||
|
|
||||||
|
._list>._more {
|
||||||
|
pointer-events: none;
|
||||||
|
margin-right: 1em;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PHBhdGggZD0nTTM5Mi4zMDgzNjQgNzEuODE5NjM2YTU4LjE4MTgxOCA1OC4xODE4MTggMCAwIDAtNzcuOTE3MDkxIDg2LjMxODU0NmwzLjA3MiAyLjc5MjcyNyAzNzkuOTA0IDMxOS4wOTIzNjRhMzQuOTA5MDkxIDM0LjkwOTA5MSAwIDAgMSA0LjI1ODkwOSA0OS4xOTg1NDVsLTEuODM4NTQ2IDIuMDI0NzI3LTIuMDAxNDU0IDEuODYxODE5TDMxNi43NDE4MTggODYzLjcyMDcyN0E1OC4xODE4MTggNTguMTgxODE4IDAgMCAwIDM4OS44MTgxODIgOTU0LjE4MTgxOGwzLjIzNDkwOS0yLjYyOTgxOCAzODAuOTk3ODE4LTMzMC41NDI1NDVhMTUxLjI3MjcyNyAxNTEuMjcyNzI3IDAgMCAwIDIuNTYtMjI2LjI4MDcyOGwtNC4zNzUyNzMtMy44MTY3MjdMMzkyLjMwODM2NCA3MS44MTk2MzZ6JyBmaWxsPScjOTk5OTk5Jz48L3BhdGg+PC9zdmc+");
|
||||||
|
}
|
||||||
|
|
||||||
|
._list ._reddot{
|
||||||
|
background: var(--dag5);
|
||||||
|
border:1px solid var(--dag6);
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
color:var(--bg1);
|
||||||
|
height:2.5em;
|
||||||
|
width:2.5em;
|
||||||
|
line-height: 2.5em;
|
||||||
|
font-size:0.6em;
|
||||||
|
margin:0 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
more: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
noborder: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
reddot: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<view style="background: linear-gradient(354deg, #f3fcff, #ffffff);" :style="{minHeight:height}">
|
||||||
|
<swiper v-if="banner && banner.length > 0" :indicator-dots="banner.length > 1" :autoplay="false" :interval="interval" :style="{height:height}">
|
||||||
|
<swiper-item v-for="(item,index) in banner" :key="item.id">
|
||||||
|
<view v-if="isvideo(item.img)">
|
||||||
|
<cover-image v-if="vmuted" @tap="vmute" class="_swiper_mute" :style="{opacity: vop}" :src="file_stor('/img/wav2.png')"></cover-image>
|
||||||
|
<cover-image v-else @tap="vmute" class="_swiper_mute" :style="{opacity: vop}" :src="file_stor('/img/wav1.png')"></cover-image>
|
||||||
|
<video @tap="showop" object-fit="cover" :poster="file_stor(item.img + '.jpg')" :src="file_stor(item.img)" controls autoplay loop show-mute-btn :muted="vmuted" :enable-progress-gesture="false" style="width:100%;height:80vw;"></video>
|
||||||
|
</view>
|
||||||
|
<image v-else @tap="gourl" :data-url="item.url" :src="file_stor(item.img)" style="width:100%;height:100%;" />
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
banner: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''//min-height:80vw;
|
||||||
|
},
|
||||||
|
interval: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '3000'//min-height:80vw;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
vmuted: false,
|
||||||
|
vop: 0.2,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showop() {
|
||||||
|
this.vop = 2;
|
||||||
|
},
|
||||||
|
vmute() {
|
||||||
|
this.vmuted = !this.vmuted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._swiper_mute {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5em;
|
||||||
|
top: 0.5em;
|
||||||
|
z-index: 100;
|
||||||
|
height: 1.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,283 @@
|
||||||
|
<template>
|
||||||
|
<view class="_switch" :class="{_disabled:disabled}" @tap="clickswitch(!this.tvalue)" :animation="anidatabg">
|
||||||
|
<switch :name="name" :checked="tvalue" @change="chg" style="display:none;" />
|
||||||
|
<view class="_y" :animation="anidatay">{{y}}</view>
|
||||||
|
<view class="_n" :animation="anidatan">{{n}}</view>
|
||||||
|
<ciy-gesture :pxlen="10" @toleft="gestureto(false)" @toright="gestureto(true)">
|
||||||
|
<view class="_bn" :animation="anidatabn"></view>
|
||||||
|
</ciy-gesture>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import '@/pages/demo/zdemo.css';
|
||||||
|
|
||||||
|
._switch {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 2em;
|
||||||
|
height: 2em;
|
||||||
|
font-size: 1em;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid var(--e-switch-br);
|
||||||
|
background: var(--e-switch-bg);
|
||||||
|
color: var(--e-switch-txt);
|
||||||
|
border-radius: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch._disabled {
|
||||||
|
background: var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch ._n {
|
||||||
|
position: relative;
|
||||||
|
margin-top: -2em;
|
||||||
|
margin-left: 2em;
|
||||||
|
margin-right: 0.8em;
|
||||||
|
color: var(--e-switch-txt);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch ._y {
|
||||||
|
margin-right: 2em;
|
||||||
|
margin-left: 0.8em;
|
||||||
|
color: var(--e-switch-chktxt);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch ._bn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 1.6em;
|
||||||
|
height: 1.6em;
|
||||||
|
margin: 0.1em;
|
||||||
|
border-radius: 0.8em;
|
||||||
|
background: var(--e-switch-bg);
|
||||||
|
box-shadow: var(--e-switch-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
._switch._disabled ._bn {
|
||||||
|
background: var(--bg5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import zmixin from '@/pages/demo/zmixin.js';
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: -998
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: -998
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
y: { //选中文字
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
n: { //未选中文字
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
ms: { //动画毫秒数
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
v: false,
|
||||||
|
anidatabg: {},
|
||||||
|
anidatay: {},
|
||||||
|
anidatan: {},
|
||||||
|
anidatabn: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
tvalue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (this.v == 'modelValue' || this.v == 'value')
|
||||||
|
this.ani();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD === -998)
|
||||||
|
return;
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'value';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
handler(newD, oldD) {
|
||||||
|
if (newD === -998)
|
||||||
|
return;
|
||||||
|
if (newD || oldD)
|
||||||
|
this.v = 'modelValue';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
if (this.v == 'modelValue') {
|
||||||
|
if (typeof(this.modelValue) == 'boolean')
|
||||||
|
return this.modelValue;
|
||||||
|
else if (typeof(this.modelValue) == 'number')
|
||||||
|
return this.modelValue != 0;
|
||||||
|
else if (this.modelValue.toLowerCase() == 'true')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (this.v == 'value') {
|
||||||
|
if (typeof(this.value) == 'boolean')
|
||||||
|
return this.value;
|
||||||
|
else if (typeof(this.value) == 'number')
|
||||||
|
return this.value != 0;
|
||||||
|
else if (this.value.toLowerCase() == 'true')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.v;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.tvalue)
|
||||||
|
this.ani();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
chg(e) {
|
||||||
|
this.clickswitch(!this.tvalue);
|
||||||
|
},
|
||||||
|
ani() {
|
||||||
|
var query = uni.createSelectorQuery().in(this);
|
||||||
|
query.select('._switch').boundingClientRect(data => {
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
var ln = data.width - data.height;
|
||||||
|
var time = this.ms;
|
||||||
|
var len = this.y.length > this.n.length ? this.y.length : this.n.length;
|
||||||
|
len = 0;
|
||||||
|
if (this.tvalue) {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
if (len > 0) {
|
||||||
|
animation.translateX((ln / 2) + 'px');
|
||||||
|
animation.translateY('4px');
|
||||||
|
animation.scale(0.9);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
animation.translateX(ln + 'px');
|
||||||
|
//animation.translateY(0);
|
||||||
|
animation.scale(1);
|
||||||
|
animation.step({
|
||||||
|
duration: (len > 0 ? time / 2 : time)
|
||||||
|
});
|
||||||
|
this.anidatabn = animation.export();
|
||||||
|
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.backgroundColor(this.disabled ? 'var(--e-switch-chkbgdis)' : 'var(--e-switch-chkbg)');
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatabg = animation.export();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('20px');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatan = animation.export();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatay = animation.export();
|
||||||
|
} else {
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
if (len > 0) {
|
||||||
|
animation.translateX((ln / 2) + 'px');
|
||||||
|
animation.translateY('-4px');
|
||||||
|
animation.scale(0.9);
|
||||||
|
animation.step({
|
||||||
|
duration: time / 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
animation.translateX(0);
|
||||||
|
//animation.translateY(0);
|
||||||
|
animation.scale(1);
|
||||||
|
animation.step({
|
||||||
|
duration: (len > 0 ? time / 2 : time)
|
||||||
|
});
|
||||||
|
this.anidatabn = animation.export();
|
||||||
|
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.backgroundColor(this.disabled ? 'var(--e-switch-br)' : 'var(--e-switch-bg)');
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatabg = animation.export();
|
||||||
|
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.opacity(1);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatan = animation.export();
|
||||||
|
var animation = uni.createAnimation({});
|
||||||
|
animation.translateX('-20px');
|
||||||
|
animation.opacity(0);
|
||||||
|
animation.step({
|
||||||
|
duration: time
|
||||||
|
});
|
||||||
|
this.anidatay = animation.export();
|
||||||
|
}
|
||||||
|
}).exec();
|
||||||
|
},
|
||||||
|
gestureto(chk) {
|
||||||
|
if (chk == this.v)
|
||||||
|
return;
|
||||||
|
this.clickswitch(chk);
|
||||||
|
},
|
||||||
|
clickswitch(chk) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
this.v = chk;
|
||||||
|
this.ani();
|
||||||
|
this.$emit('update:modelValue', this.tvalue);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'input',
|
||||||
|
value: this.tvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
<template>
|
||||||
|
<view :style="{height:seatheight+'px'}"></view>
|
||||||
|
<view class="_footer">
|
||||||
|
<!-- <view class="mid"></view> -->
|
||||||
|
<view class="_tabbarsafe">
|
||||||
|
<view class="_tabbar">
|
||||||
|
<template v-for="(item,index) in tabbarArr" :key="index">
|
||||||
|
<view v-if="!item.hide" @tap="gotab(item.fullpath)" class="_bar" :class="{_active:item.fullpath == fullpath}">
|
||||||
|
<view class="_icon" :style="{backgroundImage:svg2bg(item.fullpath == fullpath?item.selecticon:item.icon)}">
|
||||||
|
</view>
|
||||||
|
<view class="_name">{{lang(item.name)}}</view>
|
||||||
|
<view v-if="item.reddot" class="_reddot"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<view class="_footer_safe" :style="{height:footer_safe_height+'px'}"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
._mid {
|
||||||
|
left: calc(50% - 3em);
|
||||||
|
height: 6em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5em;
|
||||||
|
width: 6em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--bg3);
|
||||||
|
}
|
||||||
|
|
||||||
|
._footer {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 990;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbarsafe {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin: 1em;
|
||||||
|
border-radius: 2.5em;
|
||||||
|
background: #dddddd22;
|
||||||
|
/* box-shadow: 0 0 50px 5px #ffffff; */
|
||||||
|
border: 1px solid var(--bg6);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar ._bar {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--txt1);
|
||||||
|
margin: 0.5em 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar ._bar._active {
|
||||||
|
color: var(--txt9);
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar ._icon {
|
||||||
|
width: 1.6em;
|
||||||
|
height: 1.6em;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar ._name {
|
||||||
|
color: var(--txt6);
|
||||||
|
padding-top: 0.2em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
text-shadow: 0 0 3px var(--bg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar ._active ._name {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--man5);
|
||||||
|
}
|
||||||
|
|
||||||
|
._tabbar ._reddot {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: calc(50% + 1em);
|
||||||
|
background: var(--dag5);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._footer_safe {
|
||||||
|
/* background-color: #1cf11899; */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
footer_safe_height: 0,
|
||||||
|
seatheight: 0,
|
||||||
|
fullpath: '',
|
||||||
|
tabbarArr: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
mounted() { //h5 wx ok
|
||||||
|
var app = getApp();
|
||||||
|
var pg = app.getpage();
|
||||||
|
if (pg.route)
|
||||||
|
this.fullpath = '/' + pg.route;
|
||||||
|
else if (pg.__route__)
|
||||||
|
this.fullpath = '/' + pg.__route__;
|
||||||
|
this.footer_safe_height = app.globalData._footer_safe_height;
|
||||||
|
if(this.tabbarArr == null)
|
||||||
|
this.loadtabbardata();
|
||||||
|
setTimeout(() => { //ios版本微信小程序存在执行顺序问题
|
||||||
|
uni.createSelectorQuery().in(this).select('._footer').boundingClientRect(data => {
|
||||||
|
if (data)
|
||||||
|
this.seatheight = data.height;
|
||||||
|
}).exec();
|
||||||
|
}, 10);
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.loadtabbardata();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
Getheight() {
|
||||||
|
return this.seatheight;
|
||||||
|
},
|
||||||
|
loadtabbardata() {
|
||||||
|
var app = getApp();
|
||||||
|
this.tabbarArr = this.objclone(app.globalData.tabbarArr);
|
||||||
|
},
|
||||||
|
gotab(url) {
|
||||||
|
uni.switchTab({
|
||||||
|
url: url,
|
||||||
|
fail: res => {
|
||||||
|
console.warn(res.errMsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<template>
|
||||||
|
<slot></slot>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
lifetimes: {
|
||||||
|
attached: function() {
|
||||||
|
console.log("lifetimes attached");
|
||||||
|
},
|
||||||
|
detached: function() {
|
||||||
|
console.log("lifetimes detached");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pageLifetime: {
|
||||||
|
show: function() {
|
||||||
|
console.log("pageLifetime show");
|
||||||
|
},
|
||||||
|
hide: function() {
|
||||||
|
console.log("pageLifetime hide");
|
||||||
|
},
|
||||||
|
attached: function() {
|
||||||
|
console.log("pageLifetime attached");
|
||||||
|
},
|
||||||
|
detached: function() {
|
||||||
|
console.log("pageLifetime detached");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ready() {
|
||||||
|
console.log("ready");
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
console.log("mounted");
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
console.log("activated");
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
console.log("show");
|
||||||
|
},
|
||||||
|
detached() {
|
||||||
|
console.log("detached");
|
||||||
|
},
|
||||||
|
deactivated() {
|
||||||
|
console.log("deactivated");
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
console.log("unmounted");
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
console.log("hide");
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
Rander() {
|
||||||
|
console.log('rander');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
<template>
|
||||||
|
<textarea class="_textarea" :class="{_bb:bb,_disabled:disabled}" :name="name" :value="txtvalue" :placeholder="placeholder" :cursor="cursor" :cursor-spacing="120" :disabled="disabled" :maxlength="maxlength" :auto-height="!ciystyle.height" :fixed="fixed" @input="textinput" :style="ciystyle" @focus="textfocus" @blur="textblur" @linechange="textline"></textarea>
|
||||||
|
<view v-if="showtotal" class="txt-right txt1 txt-smmm" style="line-height:1em;margin:-0.5em 0.4em 0.6em 0;">{{totaltxt}}<text v-if="maxlength>-1">/{{maxlength}}</text>字</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
virtualHost: true
|
||||||
|
},
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue', 'focus', 'blur', 'linechange', 'input'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
bb: { //传统文本框效果
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showtotal: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: -1
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
totaltxt: '0字',
|
||||||
|
cursor: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
txtvalue() {
|
||||||
|
var val = '';
|
||||||
|
if (this.modelValue)
|
||||||
|
val = this.modelValue;
|
||||||
|
else if (this.value)
|
||||||
|
val = this.value;
|
||||||
|
this.total(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.txtvalue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
textfocus(e) {
|
||||||
|
this.$emit('focus', e);
|
||||||
|
},
|
||||||
|
textblur(e) {
|
||||||
|
this._cursor = e.detail.cursor;
|
||||||
|
this.$emit('blur', e);
|
||||||
|
},
|
||||||
|
textline(e) {
|
||||||
|
this.$emit('linechange', e);
|
||||||
|
},
|
||||||
|
textinput(e) {
|
||||||
|
this._cursor = e.detail.cursor;
|
||||||
|
var txt = e.detail.value;
|
||||||
|
if (txt === undefined)
|
||||||
|
txt = e.data;
|
||||||
|
this.total(txt);
|
||||||
|
this.$emit('update:modelValue', txt);
|
||||||
|
this.$emit('input', {
|
||||||
|
name: this.name,
|
||||||
|
value: txt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
total(val) {
|
||||||
|
if (!val) {
|
||||||
|
this.totaltxt = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var linelen = val.split('\n').length;
|
||||||
|
this.totaltxt = linelen + '行,' + val.length;
|
||||||
|
},
|
||||||
|
Getcursor() {
|
||||||
|
return this._cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._textarea {
|
||||||
|
text-align: left;
|
||||||
|
display: block;
|
||||||
|
padding: 1rem 0.5rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 1.6em;
|
||||||
|
font-size: 1em;
|
||||||
|
min-height: 3em;
|
||||||
|
overflow: auto;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
max-height: 50vh;
|
||||||
|
/* 解决微信覆盖bug */
|
||||||
|
}
|
||||||
|
|
||||||
|
._textarea._bb {
|
||||||
|
border: 1px solid var(--bg4);
|
||||||
|
border-radius: 0.2em;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
background: var(--bg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
._textarea._disabled {
|
||||||
|
color: var(--txt1);
|
||||||
|
background: var(--bg4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
<template>
|
||||||
|
<view @tap="showall" :style="{maxHeight:more?'':height + 'px'}" class="_divmore">
|
||||||
|
<slot></slot>
|
||||||
|
<view v-if="!more" class="_mark" :style="{background:maskbg?'linear-gradient(0deg, '+maskbg+', transparent)':''}">
|
||||||
|
<view class="itm" v-if="arrow">»</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._divmore {
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._mark {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 1;
|
||||||
|
height: 3em;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._mark>.itm {
|
||||||
|
font-size: 2em;
|
||||||
|
color: var(--txt1);
|
||||||
|
animation: _slideDown 3s ease-in infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes _slideDown {
|
||||||
|
0% {
|
||||||
|
transform: rotate(75deg) translateX(-1em);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
12% {
|
||||||
|
transform: rotate(90deg) translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
95% {
|
||||||
|
transform: rotate(90deg) translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(110deg) translateX(0.5em);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 100
|
||||||
|
},
|
||||||
|
maskbg: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--bg1)'
|
||||||
|
},
|
||||||
|
arrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
more: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {
|
||||||
|
setTimeout(async () => {
|
||||||
|
var rect = await this.getrect('._divmore');
|
||||||
|
if (rect.height < this.height)
|
||||||
|
this.more = true;
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showall() {
|
||||||
|
this.more = true;
|
||||||
|
this.$emit('change', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
<template>
|
||||||
|
<view class="_dialog" @tap="close('click')" v-if="popsh">
|
||||||
|
<view class="_content" :style="dialogstyle" v-html="tobr(content, true)"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._dialog {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
z-index:50030;
|
||||||
|
}
|
||||||
|
|
||||||
|
._dialog ._content {
|
||||||
|
border-radius: 0.5em;
|
||||||
|
background: var(--txt7);
|
||||||
|
color: var(--bg2);
|
||||||
|
display: inline-block;
|
||||||
|
max-width:100%;
|
||||||
|
padding: 1em 2em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
popsh: false,
|
||||||
|
dialogstyle: {},
|
||||||
|
content: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async Open(res) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
this.cb = resolve;
|
||||||
|
res = res || {};
|
||||||
|
if (typeof(res) == 'string') {
|
||||||
|
res = {
|
||||||
|
content: res,
|
||||||
|
sec: 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var sec = this.toint(res.sec);
|
||||||
|
this.content = res.content;
|
||||||
|
var app = getApp();
|
||||||
|
this.dialogstyle.marginTop = (app.globalData._sysinfo.windowHeight / 3) + 'px';
|
||||||
|
this.popsh = true;
|
||||||
|
if (sec <= 0)
|
||||||
|
return;
|
||||||
|
this._tick = setTimeout(() => {
|
||||||
|
this.close('timeout');
|
||||||
|
}, sec * 1000);
|
||||||
|
}).catch(e => {
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close(act) {
|
||||||
|
clearTimeout(this._tick);
|
||||||
|
this.popsh = false;
|
||||||
|
this.cb(act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<template>
|
||||||
|
<view v-for="(item,index) in sem" :key="index" class="flex1" @tap="clkitem(index)">
|
||||||
|
<view :class="numclass">
|
||||||
|
<ciy-shownum :value="item.num" :unit="item.unit"></ciy-shownum>
|
||||||
|
</view>
|
||||||
|
<view :class="nameclass">{{item.name}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
sem: {
|
||||||
|
type: [Array],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
numclass: {
|
||||||
|
type: [String],
|
||||||
|
default: 'txt-lgg'
|
||||||
|
},
|
||||||
|
nameclass: {
|
||||||
|
type: [String],
|
||||||
|
default: 'txt-sm py2'
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
clkitem(idx) {
|
||||||
|
if (this.sem[idx].url)
|
||||||
|
this.gourl(this.sem[idx].url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,694 @@
|
||||||
|
<template>
|
||||||
|
<view class="_vphoto" :class="{left}">
|
||||||
|
<input type="hidden" :maxlength="-1" :name="name" :value="tvalue.value" style="display:none;" />
|
||||||
|
<view class="_btn" :class="{_disabled:disabled}" @tap="photo_select" v-if="tvalue.imgs.length < num">
|
||||||
|
<view class="_icon _photo"></view>
|
||||||
|
</view>
|
||||||
|
<ciy-gesture class="_pimg" v-for="(item,index) in tvalue.imgs" :key="index" :style="{'display':'block','width':showwh}" @toleft="toleft(index)" @toright="toright(index)">
|
||||||
|
<view v-if="!disabled" class="_del" :data-idx="index" @tap="photo_delone"></view>
|
||||||
|
<image v-if="isimg(item)" :src="file_stor(item, '?50')" @tap="preview(index)" mode="widthFix" style="display:block;"></image>
|
||||||
|
<video v-else-if="isvideo(item)" :id="'video' + index" :src="file_stor(item)" controls @tap="fullvideo('video' + index)" :show-fullscreen-btn="false" :style="{width:showwh,height:showwh}"></video>
|
||||||
|
<view v-else class="_file">{{file_ext(item)}}</view>
|
||||||
|
</ciy-gesture>
|
||||||
|
<view class="_tip">{{tip}}</view>
|
||||||
|
<canvas type="2d" :canvas-id="cvid" :id="cvid" :style="{'width':cvwidth+'px','height':cvheight+'px','top':-cvheight + 'px'}" :width="cvwidth" :height="cvheight" style="position:fixed;z-index:-999;left:100vw;"></canvas>
|
||||||
|
<!-- <canvas type="2d" :canvas-id="cvid" :id="cvid" :style="{'width':cvwidth+'px','height':cvheight+'px','top':'2px'}" :width="cvwidth" :height="cvheight" style="position:fixed;z-index:999;left:2px;border:2px solid #ff0000"></canvas> -->
|
||||||
|
</view>
|
||||||
|
<view v-if="showrecam" :style="{top:header_height+'px'}" style="z-index:50005;position: fixed;left:0;right:0;bottom:0;background:linear-gradient(327deg,var(--bg1),var(--man3))">
|
||||||
|
<image v-if="cammaskpng" :src="file_stor(cammaskpng)" class="abs t0 l0" :style="{pointerEvents: 'none',zIndex:50006,opacity:0.8,width: '100%', height: cameraheight + 'vw'}"></image>
|
||||||
|
<camera style="border: 1px solid #cccccc;" device-position="back" flash="off" :style="{width: '100%', height: cameraheight + 'vw'}"></camera>
|
||||||
|
<view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<view style="opacity: 0.7;position: absolute;bottom:8em;left:0;right:0;text-align:center;">
|
||||||
|
<button class="btn lg cc" @tap="recamphoto" style="margin-top:0.5em;">拍照</button>
|
||||||
|
</view>
|
||||||
|
<view style="position: absolute;bottom:1em;left:0;right:0;">
|
||||||
|
<view v-if="!camheight">
|
||||||
|
<view style="position: absolute;bottom:0.5em;right:0.8em;">
|
||||||
|
<ciy-select :rows="2" itemalign="center" :minselectsearch="20" :range="recamrange" v-model="cameraheight" @change="setcamheight"></ciy-select>
|
||||||
|
</view>
|
||||||
|
<view style="position: absolute;bottom:0.2em;left:0.5em;">
|
||||||
|
<button class="btn def" @tap="setcamaddheight(2)">↓</button>
|
||||||
|
<button class="btn def" @tap="setcamaddheight(-2)">↑</button>
|
||||||
|
<button class="btn smm def" @tap="setcamswapheight()" style="padding:0.8em 1em;">转向</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="px3 flex flex-center" style="gap:0.2em;" v-if="recamimgs.length > 0">
|
||||||
|
<image v-for="img in recamimgs.slice(-6)" :src="img" style="height:3em;width:3em;border:1px solid var(--bg9);border-radius: 5px;"></image>
|
||||||
|
<view class="flex1 px2" style="font-size:1.5em;">x{{recamimgs.length}}</view>
|
||||||
|
</view>
|
||||||
|
<view style="text-align: center;">
|
||||||
|
<button class="btn cc" @tap="closerecam" style="margin-top:0.5em;">完成</button>
|
||||||
|
<!-- <view @tap="showrecam=false" style="display:inline-block;background: var(--man6);color: #ffffff;width: 1.5em;height: 1.5em;line-height:1.5em;border-radius: 50%;text-align: center;font-size: 2em;">✔</view> -->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
behaviors: ['uni://form-field-group'],
|
||||||
|
emits: ['change', 'update:modelValue'],
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
initevent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
sourcetype: {
|
||||||
|
type: String,
|
||||||
|
default: 'camera,album,message' //rehcam
|
||||||
|
},
|
||||||
|
camheight: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
cammaskpng: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
filetype: {
|
||||||
|
type: String,
|
||||||
|
default: 'image' //all image video
|
||||||
|
},
|
||||||
|
ext: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
num: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
stor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
imgwidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
imgheight: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
maxkb: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
zipjpg: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 70
|
||||||
|
},
|
||||||
|
waterfont: {
|
||||||
|
type: String,
|
||||||
|
default: '28px Arial'
|
||||||
|
},
|
||||||
|
watertext: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
watertype: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
watercolors: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
wateralpha: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
waterpadding: {
|
||||||
|
type: String,
|
||||||
|
default: '30'
|
||||||
|
},
|
||||||
|
waterangle: {
|
||||||
|
type: String,
|
||||||
|
default: '-20'
|
||||||
|
},
|
||||||
|
showwh: {
|
||||||
|
type: String,
|
||||||
|
default: '4em'
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: String,
|
||||||
|
default: 'nopath'
|
||||||
|
},
|
||||||
|
saas: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tip: '',
|
||||||
|
updatevalue: false,
|
||||||
|
val: '',
|
||||||
|
showrecam: false,
|
||||||
|
header_height: 0,
|
||||||
|
cameraheight: '141.4',
|
||||||
|
recamrange: [],
|
||||||
|
recamimgs: [],
|
||||||
|
cvid: '',
|
||||||
|
cvwidth: 88,
|
||||||
|
cvheight: 88
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
async handler(newD, oldD) {
|
||||||
|
this.val = newD;
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
async handler(newD, oldD) {
|
||||||
|
if (this.updatevalue) {
|
||||||
|
this.updatevalue = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.val = newD;
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
camheight: {
|
||||||
|
async handler(newD, oldD) {
|
||||||
|
var val = 0;
|
||||||
|
if (newD)
|
||||||
|
val = this.tofloat(newD);
|
||||||
|
else {
|
||||||
|
var dh = this.getstorage('_cameraheight_' + this.name);
|
||||||
|
if (dh)
|
||||||
|
val = this.tofloat(dh);
|
||||||
|
}
|
||||||
|
if (val < 10 || val > 200)
|
||||||
|
return;
|
||||||
|
this.cameraheight = val + '';
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
camrefheight: {
|
||||||
|
async handler(newD, oldD) {
|
||||||
|
if (newD) {
|
||||||
|
var url = this.file_stor(newD);
|
||||||
|
url = url.replace('http://', 'https://');
|
||||||
|
uni.getImageInfo({
|
||||||
|
src: url,
|
||||||
|
success: res => {
|
||||||
|
this.cameraheight = this.toint(res.height * 100 / res.width) + '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tvalue() {
|
||||||
|
var v = this.val;
|
||||||
|
var ret = {};
|
||||||
|
ret.value = v;
|
||||||
|
var pimgs = v.split('~');
|
||||||
|
ret.imgs = [];
|
||||||
|
for (var i in pimgs) {
|
||||||
|
if (!pimgs[i])
|
||||||
|
continue;
|
||||||
|
ret.imgs.push(pimgs[i]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
var app = getApp();
|
||||||
|
this.cvid = 'offcanvas_' + parseInt(Math.random() * 1000000);
|
||||||
|
this.header_height = app.globalData._header_statusbar_height;
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '100',
|
||||||
|
name: '1:1'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '63',
|
||||||
|
name: '名片'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '75',
|
||||||
|
name: '4:3'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '134',
|
||||||
|
name: '3:4'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '56',
|
||||||
|
name: '16:9'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '179',
|
||||||
|
name: '9:16'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '162',
|
||||||
|
name: '黄金 纵向'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '62',
|
||||||
|
name: '黄金 横向'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '141',
|
||||||
|
name: 'A4 纵向'
|
||||||
|
});
|
||||||
|
this.recamrange.push({
|
||||||
|
id: '71',
|
||||||
|
name: 'A4 横向'
|
||||||
|
});
|
||||||
|
if (this.initevent) {
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'init',
|
||||||
|
value: this.tvalue.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toleft(idx) {
|
||||||
|
if (idx == 0)
|
||||||
|
return;
|
||||||
|
var imgs = [...this.tvalue.imgs];
|
||||||
|
var swap = imgs[idx];
|
||||||
|
imgs[idx] = imgs[idx - 1];
|
||||||
|
imgs[idx - 1] = swap;
|
||||||
|
this.val = imgs.join('~');
|
||||||
|
this.updatevalue = true;
|
||||||
|
this.$emit('update:modelValue', this.val);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'toleft',
|
||||||
|
value: this.val
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toright(idx) {
|
||||||
|
if (this.tvalue.imgs.length == idx + 1)
|
||||||
|
return;
|
||||||
|
var imgs = [...this.tvalue.imgs];
|
||||||
|
var swap = imgs[idx];
|
||||||
|
imgs[idx] = imgs[idx + 1];
|
||||||
|
imgs[idx + 1] = swap;
|
||||||
|
this.val = imgs.join('~');
|
||||||
|
this.updatevalue = true;
|
||||||
|
this.$emit('update:modelValue', this.val);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'toright',
|
||||||
|
value: this.val
|
||||||
|
});
|
||||||
|
},
|
||||||
|
preview(idx) {
|
||||||
|
var imgs = [...this.tvalue.imgs];
|
||||||
|
for (var i in imgs) {
|
||||||
|
imgs[i] = this.file_stor(imgs[i]);
|
||||||
|
}
|
||||||
|
uni.previewImage({
|
||||||
|
current: idx,
|
||||||
|
indicator: 'default',
|
||||||
|
urls: imgs
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fullvideo(id) {
|
||||||
|
const videoContext = uni.createVideoContext(id, this);
|
||||||
|
videoContext.requestFullScreen({
|
||||||
|
direction: 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async photo_select(b) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
if (this.tip)
|
||||||
|
return this.toast(this.lang('upload.uploadingmsg'));
|
||||||
|
|
||||||
|
var items = [];
|
||||||
|
var sourcetypes = this.sourcetype.split(',');
|
||||||
|
if (sourcetypes.includes('rehcam')) {
|
||||||
|
items.push({
|
||||||
|
act: 'rehcam',
|
||||||
|
name: this.lang('upload.menu_rehcam')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (sourcetypes.includes('camera')) {
|
||||||
|
items.push({
|
||||||
|
act: 'camera',
|
||||||
|
name: this.lang('upload.menu_camera')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (sourcetypes.includes('album')) {
|
||||||
|
items.push({
|
||||||
|
act: 'album',
|
||||||
|
name: this.lang('upload.menu_album')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (sourcetypes.includes('message')) {
|
||||||
|
items.push({
|
||||||
|
act: 'message',
|
||||||
|
name: this.lang('upload.menu_message')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var item = await this.popmenu({
|
||||||
|
items,
|
||||||
|
one: true
|
||||||
|
});
|
||||||
|
if (item.act == 'rehcam')
|
||||||
|
this.vrehcam();
|
||||||
|
if (item.act == 'camera')
|
||||||
|
this.vcamera();
|
||||||
|
if (item.act == 'album')
|
||||||
|
this.valbum();
|
||||||
|
if (item.act == 'message')
|
||||||
|
this.vmessage();
|
||||||
|
},
|
||||||
|
photo_delone(b) {
|
||||||
|
if (this.disabled)
|
||||||
|
return;
|
||||||
|
if (this.tip)
|
||||||
|
return this.toast(this.lang('upload.uploading'));
|
||||||
|
var imgs = [...this.tvalue.imgs];
|
||||||
|
imgs.splice(b.currentTarget.dataset.idx, 1);
|
||||||
|
this.val = imgs.join('~');
|
||||||
|
this.updatevalue = true;
|
||||||
|
this.$emit('update:modelValue', this.val);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: 'del',
|
||||||
|
value: this.val
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addfile(url, from) {
|
||||||
|
var imgs = [...this.tvalue.imgs, url];
|
||||||
|
this.val = imgs.join('~');
|
||||||
|
if (!from)
|
||||||
|
return;
|
||||||
|
this.updatevalue = true;
|
||||||
|
this.$emit('update:modelValue', this.val);
|
||||||
|
this.$emit('change', {
|
||||||
|
name: this.name,
|
||||||
|
from: from,
|
||||||
|
value: this.val
|
||||||
|
});
|
||||||
|
if (from == 'rehcam') {
|
||||||
|
if (this.tvalue.imgs.length < this.num) {
|
||||||
|
this.vrehcam();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setcamheight(e) {
|
||||||
|
this.cameraheight = e.value.id;
|
||||||
|
this.setstorage('_cameraheight_' + this.name, this.cameraheight);
|
||||||
|
},
|
||||||
|
setcamaddheight(hei) {
|
||||||
|
var h = this.tofloat(this.cameraheight) + hei;
|
||||||
|
if (h < 10)
|
||||||
|
return;
|
||||||
|
this.cameraheight = h + '';
|
||||||
|
this.setstorage('_cameraheight_' + this.name, this.cameraheight);
|
||||||
|
},
|
||||||
|
setcamswapheight(hei) {
|
||||||
|
var h = this.tofloat(this.cameraheight);
|
||||||
|
this.cameraheight = Math.ceil(10000 / h) + '';
|
||||||
|
this.setstorage('_cameraheight_' + this.name, this.cameraheight);
|
||||||
|
},
|
||||||
|
recamphoto() {
|
||||||
|
const ctx = wx.createCameraContext();
|
||||||
|
ctx.takePhoto({
|
||||||
|
quality: 'high',
|
||||||
|
success: async (res) => {
|
||||||
|
this.showrecam = false;
|
||||||
|
this.recamimgs.push(res.tempImagePath);
|
||||||
|
this.upfiles([res], 'rehcam');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
closerecam() {
|
||||||
|
this.showrecam = false;
|
||||||
|
this.recamimgs = [];
|
||||||
|
},
|
||||||
|
async vrehcam(b) {
|
||||||
|
this.showrecam = true;
|
||||||
|
},
|
||||||
|
async vcamera(b) {
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
return this.vh5(b, ['camera']);
|
||||||
|
// #endif
|
||||||
|
var count = this.toint(this.num) - this.tvalue.imgs.length;
|
||||||
|
if (count <= 0)
|
||||||
|
return this.toast(this.lang('upload.maxmsg').replace('{n}', this.num));
|
||||||
|
var opt = {};
|
||||||
|
opt.count = 1;
|
||||||
|
if (this.filetype == 'all') {
|
||||||
|
opt.mediaType = ['mix'];
|
||||||
|
}
|
||||||
|
if (this.filetype == 'image') {
|
||||||
|
opt.mediaType = ['image'];
|
||||||
|
}
|
||||||
|
if (this.filetype == 'video') {
|
||||||
|
opt.mediaType = ['video'];
|
||||||
|
}
|
||||||
|
opt.sizeType = ['original', 'compressed'];
|
||||||
|
opt.sourceType = ['camera'];
|
||||||
|
opt.maxDuration = 60;
|
||||||
|
var [err, retchoose] = await this.go(uni.chooseMedia(opt));
|
||||||
|
if (err)
|
||||||
|
return console.warn('chooseMedia', err);
|
||||||
|
this.upfiles(retchoose.tempFiles, 'camera');
|
||||||
|
},
|
||||||
|
async valbum(b) {
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
return this.vh5(b, ['album']);
|
||||||
|
// #endif
|
||||||
|
var count = this.toint(this.num) - this.tvalue.imgs.length;
|
||||||
|
if (count <= 0)
|
||||||
|
return this.toast(this.lang('upload.maxmsg').replace('{n}', this.num));
|
||||||
|
var opt = {};
|
||||||
|
opt.count = count;
|
||||||
|
if (this.filetype == 'all') {
|
||||||
|
opt.mediaType = ['mix'];
|
||||||
|
}
|
||||||
|
if (this.filetype == 'image') {
|
||||||
|
opt.mediaType = ['image'];
|
||||||
|
}
|
||||||
|
if (this.filetype == 'video') {
|
||||||
|
opt.mediaType = ['video'];
|
||||||
|
}
|
||||||
|
opt.sizeType = ['original', 'compressed'];
|
||||||
|
opt.sourceType = ['album'];
|
||||||
|
var [err, retchoose] = await this.go(uni.chooseMedia(opt));
|
||||||
|
if (err)
|
||||||
|
return console.warn('chooseMedia', err);
|
||||||
|
this.upfiles(retchoose.tempFiles, 'album');
|
||||||
|
},
|
||||||
|
async vmessage(b) {
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
return this.vh5(b, ['album']);
|
||||||
|
// #endif
|
||||||
|
var count = this.toint(this.num) - this.tvalue.imgs.length;
|
||||||
|
if (count <= 0)
|
||||||
|
return this.toast(this.lang('upload.maxmsg').replace('{n}', this.num));
|
||||||
|
var opt = {};
|
||||||
|
opt.count = count;
|
||||||
|
if (this.filetype == 'all') {
|
||||||
|
if (this.ext) {
|
||||||
|
opt.type = 'file';
|
||||||
|
opt.extension = this.ext.split(',');
|
||||||
|
} else {
|
||||||
|
opt.type = 'all';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.filetype == 'image') {
|
||||||
|
opt.type = 'image';
|
||||||
|
}
|
||||||
|
if (this.filetype == 'video') {
|
||||||
|
opt.type = 'video';
|
||||||
|
}
|
||||||
|
var [err, retchoose] = await this.go(uni.chooseMessageFile(opt));
|
||||||
|
if (err)
|
||||||
|
return console.warn('chooseMessageFile', err);
|
||||||
|
this.upfiles(retchoose.tempFiles, 'message');
|
||||||
|
},
|
||||||
|
async vh5(b, source) {
|
||||||
|
var count = this.toint(this.num) - this.tvalue.imgs.length;
|
||||||
|
if (count <= 0)
|
||||||
|
return this.toast(this.lang('upload.maxmsg').replace('{n}', this.num));
|
||||||
|
var opt = {};
|
||||||
|
opt.count = count;
|
||||||
|
opt.sizeType = ['compressed']; //'original',
|
||||||
|
opt.sourceType = source;
|
||||||
|
var [err, retchoose] = await this.go(uni.chooseImage(opt));
|
||||||
|
if (err)
|
||||||
|
return console.warn('chooseImage', err);
|
||||||
|
await this.upfiles(retchoose.tempFiles, 'h5');
|
||||||
|
},
|
||||||
|
async upfiles(temps, from) {
|
||||||
|
var thos = this;
|
||||||
|
var app = getApp();
|
||||||
|
this.upcount = temps.length;
|
||||||
|
this.tip = this.lang('upload.tip') + ' 0/' + this.upcount;
|
||||||
|
this.upidx = 0;
|
||||||
|
var opn = {};
|
||||||
|
opn.offcanvas = {
|
||||||
|
id: this.cvid,
|
||||||
|
dom: this
|
||||||
|
};
|
||||||
|
opn.post = {
|
||||||
|
from: from
|
||||||
|
};
|
||||||
|
opn.basepath = this.path;
|
||||||
|
opn.saas = this.saas;
|
||||||
|
if (this.stor)
|
||||||
|
opn.stor = this.stor;
|
||||||
|
else
|
||||||
|
opn.stor = app.globalData.stordefault;
|
||||||
|
opn.action = this.action;
|
||||||
|
opn.maxkb = this.toint(this.maxkb);
|
||||||
|
opn.imgwidth = this.toint(this.imgwidth);
|
||||||
|
opn.imgheight = this.toint(this.imgheight);
|
||||||
|
opn.zipjpg = this.toint(this.zipjpg);
|
||||||
|
opn.watertext = this.watertext;
|
||||||
|
opn.watertype = this.watertype;
|
||||||
|
opn.waterpadding = this.toint(this.waterpadding);
|
||||||
|
opn.waterangle = this.toint(this.waterangle);
|
||||||
|
opn.wateralpha = this.tofloat(this.wateralpha);
|
||||||
|
if (opn.wateralpha <= 0) {
|
||||||
|
if (this.watertype == 'full')
|
||||||
|
opn.wateralpha = 0.1;
|
||||||
|
else
|
||||||
|
opn.wateralpha = 1;
|
||||||
|
}
|
||||||
|
if (this.watercolors)
|
||||||
|
opn.watercolors = this.watercolors.split(',');
|
||||||
|
await this.file_uploads(temps, opn, {
|
||||||
|
success(url, file) {
|
||||||
|
thos.upidx++;
|
||||||
|
thos.tip = thos.lang('upload.tip') + ' ' + thos.upidx + '/' + thos.upcount;
|
||||||
|
if (thos.upidx == thos.upcount) {
|
||||||
|
thos.tip = '';
|
||||||
|
thos.addfile(url, from);
|
||||||
|
} else {
|
||||||
|
thos.addfile(url);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail(err, gf, al) {
|
||||||
|
console.warn(err, gf, al);
|
||||||
|
thos.upidx++;
|
||||||
|
thos.tip = '';
|
||||||
|
return thos.alert('Upload Fail:' + err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._vphoto ._photo {
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zycgd2lkdGg9JzIwMCcgaGVpZ2h0PScyMDAnPjxwYXRoIGQ9J00xMjUuOTUyIDIzNC40OTZoMTY2LjkxMmMyMS41MDQgMCAyOS42OTYtNDguMTI4IDU0LjI3Mi03MS42OCA3LjE2OC03LjE2OCAyOC42NzItMTIuMjg4IDM2Ljg2NC0xMi4yODhoMjc4LjUyOGM4LjE5MiAwIDI5LjY5NiAxMS4yNjQgMzYuODY0IDI1LjYgMTMuMzEyIDI0LjU3NiAxMi4yODggNTguMzY4IDI1LjYgNTguMzY4aDE4MS4yNDhjNDYuMDggMCA4My45NjggMzcuODg4IDgzLjk2OCA4My45Njh2NDc0LjExMmMwIDQ2LjA4LTM3Ljg4OCA4My45NjgtODMuOTY4IDgzLjk2OEgxMjUuOTUyYy00Ni4wOCAwLTgzLjk2OC0zNy44ODgtODMuOTY4LTgzLjk2OFYzMTcuNDRjMS4wMjQtNDYuMDggMzcuODg4LTgyLjk0NCA4My45NjgtODIuOTQ0eicgZmlsbD0nIzNFQkRGRic+PC9wYXRoPjxwYXRoIGQ9J002MzQuODggMjc1LjQ1NmgxNC4zMzZjMTEuMjY0IDAgMjAuNDggOS4yMTYgMjAuNDggMjAuNDhzLTkuMjE2IDIwLjQ4LTIwLjQ4IDIwLjQ4SDYzNC44OGMtMTEuMjY0IDAtMjAuNDgtOS4yMTYtMjAuNDgtMjAuNDggMC0xMC4yNCA5LjIxNi0yMC40OCAyMC40OC0yMC40OHpNNzMyLjE2IDI3NS40NTZoMTY2LjkxMmMxMS4yNjQgMCAyMC40OCA5LjIxNiAyMC40OCAyMC40OHMtOS4yMTYgMjAuNDgtMjAuNDggMjAuNDhINzMyLjE2Yy0xMS4yNjQgMC0yMC40OC05LjIxNi0yMC40OC0yMC40OCAwLTEwLjI0IDkuMjE2LTIwLjQ4IDIwLjQ4LTIwLjQ4eicgZmlsbD0nI0ZGRkZGRic+PC9wYXRoPjxwYXRoIGQ9J001MzAuNDMyIDM1OS40MjRjMTIyLjg4IDAgMjIzLjIzMiA5OS4zMjggMjIzLjIzMiAyMjMuMjMyIDAgMTIyLjg4LTk5LjMyOCAyMjMuMjMyLTIyMy4yMzIgMjIzLjIzMi0xMjIuODggMC0yMjMuMjMyLTk5LjMyOC0yMjMuMjMyLTIyMy4yMzIgMC0xMjIuODggMTAwLjM1Mi0yMjMuMjMyIDIyMy4yMzItMjIzLjIzMnonIGZpbGw9JyNBMkRFRkQnPjwvcGF0aD48L3N2Zz4=");
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto {
|
||||||
|
margin: 0.5em auto 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto.left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto ._tip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.1em;
|
||||||
|
left: 0.2em;
|
||||||
|
line-height: 1em;
|
||||||
|
font-size: 0.7em;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto>._btn {
|
||||||
|
padding: 0.5em;
|
||||||
|
width: 3em;
|
||||||
|
height: 3em;
|
||||||
|
margin: 0 0.5em 0.5em 0;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto>._btn._disabled {
|
||||||
|
background: #ebebeb;
|
||||||
|
filter: grayscale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto ._icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto ._pimg {
|
||||||
|
margin: 0 0.5em 0.5em 0;
|
||||||
|
background: #ffffff;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto ._pimg ._file {
|
||||||
|
margin: 1.2em 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto ._pimg image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._vphoto ._pimg ._del {
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PScwIDAgMTAyNCAxMDI0JyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PHBhdGggZD0nTTUxMiAzMC4xMTc2NDdhNDgxLjg4MjM1MyA0ODEuODgyMzUzIDAgMSAwIDQ4MS44ODIzNTMgNDgxLjg4MjM1MyA0ODEuODgyMzUzIDQ4MS44ODIzNTMgMCAwIDAtNDgxLjg4MjM1My00ODEuODgyMzUzeicgZmlsbD0nI0ZENDgzNyc+PC9wYXRoPjxwYXRoIGQ9J003MDUuMTc0NTg4IDY1Ny43MDkxNzZhMzMuOTcyNzA2IDMzLjk3MjcwNiAwIDEgMS00OC4xODgyMzUgNDcuODI2ODI0TDUxMiA1NjAuMDA3NTI5bC0xNDUuMjI3Mjk0IDE0NS44ODk4ODNhMzMuOTcyNzA2IDMzLjk3MjcwNiAwIDEgMS00OC4xODgyMzUtNDcuODI2ODI0bDE0NS40MDgtMTQ1Ljc2OTQxMkwzMTguNzY1MTc2IDM2Ni4yMzA1ODhhMzMuOTcyNzA2IDMzLjk3MjcwNiAwIDAgMSA0OC4xODgyMzYtNDcuODI2ODIzTDUxMiA0NjMuOTkyNDcxbDE0NS4yMjcyOTQtMTQ1LjcwOTE3N2EzMy45NzI3MDYgMzMuOTcyNzA2IDAgMSAxIDQ4LjE4ODIzNSA0Ny44MjY4MjRMNTU5Ljc2NjU4OCA1MTJ6JyBmaWxsPScjRkZGRkZGJz48L3BhdGg+PC9zdmc+");
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
position: absolute;
|
||||||
|
top: -0.3em;
|
||||||
|
right: -0.3em;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<view :style="ciystyle" v-if="user>0">
|
||||||
|
<text style="font-size:0.7em;" v-if="!usrinfo" @tap.stop="getname">No.</text>
|
||||||
|
<text @tap.stop="getname">{{showtxt}}</text>
|
||||||
|
<button class="btn def smm" style="margin-left:1em;" @tap.stop="showinfo">用户详情</button>
|
||||||
|
</view>
|
||||||
|
<view :style="ciystyle" v-else>
|
||||||
|
<text style="color:var(--bg6)">暂无</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//支持本地缓存,自动翻译
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
user: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
ciystyle: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
usrinfo: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
showtxt() {
|
||||||
|
if (this.usrinfo)
|
||||||
|
return this.usrinfo.name;
|
||||||
|
return this.user;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.usrinfo = this.getstorage('d' + this.user);
|
||||||
|
if (!this.usrinfo)
|
||||||
|
this.getuserinfo();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async getuserinfo() {
|
||||||
|
if(this.user < 1)
|
||||||
|
return;
|
||||||
|
if (this.usrinfo) {
|
||||||
|
if (this.usrinfo._times > this.tostamp())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const app = getApp();
|
||||||
|
app.globalData.mqfunc.push({
|
||||||
|
name: 'userinfo_' + this.user,
|
||||||
|
func: 'dao.userinfo_get',
|
||||||
|
data: {
|
||||||
|
id: this.user,
|
||||||
|
},
|
||||||
|
callback: retjson => {
|
||||||
|
if (retjson.code != 1)
|
||||||
|
return;
|
||||||
|
retjson.user._times = this.tostamp() + 60;
|
||||||
|
this.setstorage('d' + this.user, retjson.user);
|
||||||
|
this.usrinfo = retjson.user;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async getname() {
|
||||||
|
this.getuserinfo();
|
||||||
|
},
|
||||||
|
async showinfo() {
|
||||||
|
await this.getuserinfo();
|
||||||
|
this.gourl('/pages/me/user_show', '', this.usrinfo, 'userinfo');
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<template>
|
||||||
|
<view class="_main" @tap="gourl" :data-url="'/pages/?id=' + data.id">
|
||||||
|
<image class="_img" :src="file_stor(data.avar, '?100')" mode="scaleToFill" />
|
||||||
|
<view class="flex1 rel">
|
||||||
|
<view class="_name" style="min-height:3em;">{{data.name}}</view>
|
||||||
|
<view>
|
||||||
|
金额 <ciy-shownum style="font-size:1.6em;" :value="data.bankmoney" unit="元,100,2|万元,1000000,3|亿元,10000000000,3"></ciy-shownum>
|
||||||
|
</view>
|
||||||
|
<view class="abs r0 b0 kbd">{{ccode(initdata.zc_menu,data.menuid)}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
initdata: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
._main {
|
||||||
|
background: var(--bg1);
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
border-bottom: 1px solid var(--bg6);
|
||||||
|
border-top: 1px solid var(--bg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
._img {
|
||||||
|
width: 5em;
|
||||||
|
height: 5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
background: linear-gradient(329deg, #f3ffef, #f1f8ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
._name {
|
||||||
|
margin-top: 0.3em;
|
||||||
|
font-size: 1em;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
color: var(--txt9);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"pages": [{
|
||||||
|
"path": "pages/main/index",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"ciycfg": {
|
||||||
|
"mainpackage": ["main", "pub"]
|
||||||
|
},
|
||||||
|
"globalStyle": {
|
||||||
|
"navigationBarTitleText": "众产Ciyon",
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
},
|
||||||
|
"tabBar": {
|
||||||
|
"list": [{
|
||||||
|
"pagePath": "pages/main/index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/main/me"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"preloadRule": {
|
||||||
|
"pages/main/index": {
|
||||||
|
"packages": ["pages/demo"],
|
||||||
|
"network": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"condition" : {
|
||||||
|
"current": 0,
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "custompage",
|
||||||
|
"path": "/pages/demo/comform/upload",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script>
|
||||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||||
|
CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||||
|
</script>
|
||||||
|
<title></title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
=================================================================================
|
||||||
|
* License: GPL-2.0 license
|
||||||
|
* Author: 众产® https://ciy.cn/code
|
||||||
|
* Version: 0.1.0
|
||||||
|
=================================================================================
|
||||||
|
支持i18n多语言、深色模式、通用css色系
|
||||||
|
在ciy.js中混入了常用函数库。自定义组件与页面均可调用。
|
||||||
|
app.* 系统函数
|
||||||
|
c.* 独立函数
|
||||||
|
this.* 页面函数
|
||||||
|
*/
|
||||||
|
import messages from './util/langload';
|
||||||
|
let lang = uni.getStorageSync("_lang");
|
||||||
|
if(!lang)
|
||||||
|
lang = uni.getLocale();
|
||||||
|
let i18nConfig = {
|
||||||
|
locale: lang,
|
||||||
|
silentTranslationWarn: true,
|
||||||
|
silentFallbackWarn: true,
|
||||||
|
messages
|
||||||
|
};
|
||||||
|
import App from './App';
|
||||||
|
import { createSSRApp } from 'vue';
|
||||||
|
import { createI18n } from 'vue-i18n';
|
||||||
|
import ciy from './util/ciy';
|
||||||
|
|
||||||
|
import './util/style.css';
|
||||||
|
import './prod.css';
|
||||||
|
const i18n = createI18n(i18nConfig);
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App);
|
||||||
|
app.use(i18n);
|
||||||
|
app.use(ciy, App);
|
||||||
|
return {
|
||||||
|
app
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
{
|
||||||
|
"name" : "众产DAO",
|
||||||
|
"appid" : "__UNI__0372782",
|
||||||
|
"description" : "",
|
||||||
|
"versionName" : "1.0.1",
|
||||||
|
"versionCode" : 1000001,
|
||||||
|
"transformPx" : false,
|
||||||
|
/* 5+App特有相关 */
|
||||||
|
"app-plus" : {
|
||||||
|
"usingComponents" : true,
|
||||||
|
"nvueStyleCompiler" : "uni-app",
|
||||||
|
"compilerVersion" : 3,
|
||||||
|
"splashscreen" : {
|
||||||
|
"alwaysShowBeforeRender" : true,
|
||||||
|
"waiting" : true,
|
||||||
|
"autoclose" : true,
|
||||||
|
"delay" : 0
|
||||||
|
},
|
||||||
|
"permissions" : {
|
||||||
|
"plus" : {
|
||||||
|
"description" : "访问系统文件",
|
||||||
|
"features" : [ "io" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 模块配置 */
|
||||||
|
"modules" : {
|
||||||
|
"Bluetooth" : {},
|
||||||
|
"iBeacon" : {}
|
||||||
|
},
|
||||||
|
/* 应用发布信息 */
|
||||||
|
"distribute" : {
|
||||||
|
/* android打包配置 */
|
||||||
|
"android" : {
|
||||||
|
"permissions" : [
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||||
|
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||||
|
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
/* ios打包配置 */
|
||||||
|
"ios" : {
|
||||||
|
"dSYMs" : false
|
||||||
|
},
|
||||||
|
/* SDK配置 */
|
||||||
|
"sdkConfigs" : {
|
||||||
|
"push" : {
|
||||||
|
"unipush" : {
|
||||||
|
"version" : "2",
|
||||||
|
"offline" : true,
|
||||||
|
"hms" : {},
|
||||||
|
"oppo" : {},
|
||||||
|
"vivo" : {},
|
||||||
|
"mi" : {},
|
||||||
|
"meizu" : {},
|
||||||
|
"honor" : {},
|
||||||
|
"fcm" : {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share" : {
|
||||||
|
"weixin" : {
|
||||||
|
"appid" : "",
|
||||||
|
"UniversalLinks" : ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"speech" : {
|
||||||
|
"baidu" : {
|
||||||
|
"appid" : "",
|
||||||
|
"apikey" : "",
|
||||||
|
"secretkey" : ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payment" : {},
|
||||||
|
"oauth" : {},
|
||||||
|
"maps" : {
|
||||||
|
"amap" : {
|
||||||
|
"name" : "",
|
||||||
|
"appkey_ios" : "",
|
||||||
|
"appkey_android" : ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ad" : {}
|
||||||
|
},
|
||||||
|
"icons" : {
|
||||||
|
"android" : {
|
||||||
|
"hdpi" : "unpackage/res/icons/72x72.png",
|
||||||
|
"xhdpi" : "unpackage/res/icons/96x96.png",
|
||||||
|
"xxhdpi" : "unpackage/res/icons/144x144.png",
|
||||||
|
"xxxhdpi" : "unpackage/res/icons/192x192.png"
|
||||||
|
},
|
||||||
|
"ios" : {
|
||||||
|
"appstore" : "unpackage/res/icons/1024x1024.png",
|
||||||
|
"ipad" : {
|
||||||
|
"app" : "unpackage/res/icons/76x76.png",
|
||||||
|
"app@2x" : "unpackage/res/icons/152x152.png",
|
||||||
|
"notification" : "unpackage/res/icons/20x20.png",
|
||||||
|
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||||
|
"proapp@2x" : "unpackage/res/icons/167x167.png",
|
||||||
|
"settings" : "unpackage/res/icons/29x29.png",
|
||||||
|
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||||
|
"spotlight" : "unpackage/res/icons/40x40.png",
|
||||||
|
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
||||||
|
},
|
||||||
|
"iphone" : {
|
||||||
|
"app@2x" : "unpackage/res/icons/120x120.png",
|
||||||
|
"app@3x" : "unpackage/res/icons/180x180.png",
|
||||||
|
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||||
|
"notification@3x" : "unpackage/res/icons/60x60.png",
|
||||||
|
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||||
|
"settings@3x" : "unpackage/res/icons/87x87.png",
|
||||||
|
"spotlight@2x" : "unpackage/res/icons/80x80.png",
|
||||||
|
"spotlight@3x" : "unpackage/res/icons/120x120.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"h5" : {
|
||||||
|
"router" : {
|
||||||
|
"base" : "./"
|
||||||
|
},
|
||||||
|
"sdkConfigs" : {
|
||||||
|
"maps" : {
|
||||||
|
"qqmap" : {
|
||||||
|
"key" : "TCEBZ-PACWI-OQCGA-5ST3L-CYEDS-OJFW4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 快应用特有相关 */
|
||||||
|
"quickapp" : {},
|
||||||
|
/* 小程序特有相关 */
|
||||||
|
"mp-weixin" : {
|
||||||
|
"appid" : "wx0408640a187feb35",
|
||||||
|
"setting" : {
|
||||||
|
"urlCheck" : false,
|
||||||
|
"minified" : false
|
||||||
|
},
|
||||||
|
"usingComponents" : true,
|
||||||
|
"requiredBackgroundModes" : [ "audio" ],
|
||||||
|
"libVersion" : "3.4",
|
||||||
|
"plugins" : {
|
||||||
|
"WechatSI" : {
|
||||||
|
"version" : "0.3.6",
|
||||||
|
"provider" : "wx069ba97219f66d99"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"permission" : {
|
||||||
|
"scope.userLocation" : {
|
||||||
|
"desc" : "用户位置自动获取"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requiredPrivateInfos" : [ "chooseLocation", "getLocation", "chooseAddress" ]
|
||||||
|
},
|
||||||
|
"mp-alipay" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-baidu" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-toutiao" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"uniStatistics" : {
|
||||||
|
"enable" : false
|
||||||
|
},
|
||||||
|
"vueVersion" : "3"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,406 @@
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "pages/main/index",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/main/me",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/pub/camera"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/pub/paper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/pub/part"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/pub/psection",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/pub/web",
|
||||||
|
"style": {
|
||||||
|
"navigationBarBackgroundColor": "#ffffff",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ciycfg": {
|
||||||
|
"mainpackage": [
|
||||||
|
"main",
|
||||||
|
"pub"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"globalStyle": {
|
||||||
|
"navigationBarTitleText": "众产Ciyon",
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
},
|
||||||
|
"tabBar": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"pagePath": "pages/main/index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/main/me"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"preloadRule": {
|
||||||
|
"pages/main/index": {
|
||||||
|
"packages": [
|
||||||
|
"pages/demo"
|
||||||
|
],
|
||||||
|
"network": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"subPackages": [
|
||||||
|
{
|
||||||
|
"root": "pages/demo",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "case/comlife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "case/dict"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "case/pagecal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "case/pagefix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "case/promise"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "case/proxy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "case/vproject"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/calendar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/capcode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/checkbox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/checkitem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/define"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/handsign"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/input"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputbet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputcyc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputdaterange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputdatetime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputnumber"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputtimepoint"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/inputunitedit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/radiobox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/ratestar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/selbool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/selcas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/select"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/selmap"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/selpage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/slider"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/switch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/textarea"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comform/upload"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/alert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/ani"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/aniheight"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/anipop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/audio"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/auth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/cameraocr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/gesture"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/header"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/listend",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/markdown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/movable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/popmenu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/searchbar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/segment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/showemoney"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/showimgs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/shownum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/svgimg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/swipelist"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/swiper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/tabbar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/textmore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "comview/toast"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/chart_pie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/cssdemo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/grid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/pageflex"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/skeleton"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/tailwind"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/waterfall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "css/zindex"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "curd/demo_edit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "curd/demo_list",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "curd/me"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "page/func"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "page/lang"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "page/oldfont"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "page/sysinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "page/theme"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/me",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "cashie_lst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cashin_lst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cashoe_lst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cashout_cash"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cashout_lst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cash_charge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "invoicetitle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "invoice_lst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "invoicing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "me_bank_info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pnt_buylst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pnt_buynow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pnt_lst",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "problem_chat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "problem_pub",
|
||||||
|
"style": {
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "safe_ccub"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "safe_password"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "safe_real"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "share_qrcode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "suggest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "user_bank"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "user_info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "user_shipaddr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "user_show"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header title="组件生命周期事件"></ciy-header>
|
||||||
|
<ciy-test></ciy-test>
|
||||||
|
<view class="txt-lggg txt-center py4">
|
||||||
|
<view @tap="gourl" data-url="/pages/pub/paper?id=1">跳转测试</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">H5页面</view>
|
||||||
|
<view class="content">
|
||||||
|
mounted: 页面建立<br/>
|
||||||
|
activated: 二次进入<br/>
|
||||||
|
deactivated: 页面离开<br/>
|
||||||
|
unmounted: 页面销毁<br/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">event</view>
|
||||||
|
<view class="content">
|
||||||
|
ready、mounted、activated、show、detached、deactivated、unmounted、hide<br/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">lifetimes</view>
|
||||||
|
<view class="content">
|
||||||
|
attached、detached
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">pageLifetime</view>
|
||||||
|
<view class="content">
|
||||||
|
show、hide、attached、detached
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
ciy_arearpc: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
async loadjs(js) {
|
||||||
|
var retjson = await this.load_ciydict(this.file_stor('/dict/' + js + '.js'));
|
||||||
|
if (json.code != 1)
|
||||||
|
return this.alert(json.errmsg);
|
||||||
|
this.ciy_arearpc = retjson.arr;
|
||||||
|
},
|
||||||
|
demo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header title="字典模式"></ciy-header>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">传统字典</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>总控表名为zc_cata,其他saas主体xx_cata。</view>
|
||||||
|
<view>字段一般以字典名称命名,注解支持CATA/CATM/CATS/TBIN。</view>
|
||||||
|
<view>例如:状态、分类、型号、方案、属性等。</view>
|
||||||
|
<view>字典项较多,但每一项包含数据应不超过百条。</view>
|
||||||
|
<view>框架在用户登录时加载,并缓存到本地localstorage。</view>
|
||||||
|
<view>写页面代码时可直接使用,当字典变更时,框架在最近一次请求中感知并异步更新。</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">SaaS字典</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>字典表名为xx_catsaas,带saasid租户。</view>
|
||||||
|
<view>例如:自定义合同分类、自定义客户分类等。</view>
|
||||||
|
<view>当用户字典中无数据,则使用传统字典的数据。</view>
|
||||||
|
<view>框架在用户登录时加载,并缓存到本地localstorage。</view>
|
||||||
|
<view>写页面代码时可直接使用,当字典变更时,框架在最近一次请求中感知并异步更新。</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">表字典/页字典</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>字段一般以xxid或xxuser命名,注解为DB,表名。</view>
|
||||||
|
<view>例如:所属用户、所属合同、所属订单等。</view>
|
||||||
|
<view>可按估算数据量,少于百条可用表字典,否则用页字典。</view>
|
||||||
|
<view>表字典: 放入once初始化页面首次初始化加载。</view>
|
||||||
|
<view>页字典: 每次调用list时动态加载。</view>
|
||||||
|
<view>若更新频率低且数据量适中,可当传统字典在登录时加载。</view>
|
||||||
|
<view>数据量特别大且使用频率很高,可集中下载到本地indexdb中。</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">静态字典</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>字段一般以xxcode命名,注解为,CATx,ciy_xxx。</view>
|
||||||
|
<view>例如:省市区ciy_arearpc、行业分类等。</view>
|
||||||
|
<view>适用于数据量较大,且基本不变化。</view>
|
||||||
|
<view>导出成ciy_xxx.js文件,可同时兼容PC和小程序。</view>
|
||||||
|
<view>JS文件内容var ciy_xxx=[]。</view>
|
||||||
|
<view>页面需要时,调用ajax动态加载。</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">当前传统/用户字典项</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>
|
||||||
|
<button class="btn" @tap="demo">登录后加载</button>
|
||||||
|
</view>
|
||||||
|
<view v-for="(item,index) in g">
|
||||||
|
<view style="font-weight: bolder;color:var(--man6);">{{index}}</view>
|
||||||
|
<view style="margin-left:1em;">
|
||||||
|
<view v-for="(item2,index2) in item">
|
||||||
|
{{item2}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">加载静态字典</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>
|
||||||
|
<button class="btn" @tap="loadjs('ciy_arearpc')">加载ciy_arearpc</button>
|
||||||
|
</view>
|
||||||
|
<view v-for="(item,index) in ciy_arearpc">
|
||||||
|
{{item}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
ciy_arearpc: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
async loadjs(js) {
|
||||||
|
var retjson = await this.load_ciydict(this.file_stor('/dict/' + js + '.js'));
|
||||||
|
if (json.code != 1)
|
||||||
|
return this.alert(json.errmsg);
|
||||||
|
this.ciy_arearpc = retjson.arr;
|
||||||
|
},
|
||||||
|
demo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header title="watch computed示例"></ciy-header>
|
||||||
|
<view>
|
||||||
|
<view class="ciy-card" style="padding:1em;">
|
||||||
|
<view>compute: {{compute}}</view>
|
||||||
|
<view>test: {{test}}</view>
|
||||||
|
<view>tobj: {{tobj}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="px2 py2">
|
||||||
|
<button @tap="test='bbbb'">改变test=bbbb</button>
|
||||||
|
<button @tap="test='ccc'">改变test=ccc</button>
|
||||||
|
<button @tap="tobj.x=11.3">改变tobj.x</button>
|
||||||
|
<button @tap="tobj.y=12">改变tobj.y</button>
|
||||||
|
<button @tap="tobj={c:3,b:0}">改变tobj</button>
|
||||||
|
<button @tap="tnor='aaaa'">改变tnor=aaaa</button>
|
||||||
|
<button @tap="tnor='bbbb'">改变tnor=bbbb</button>
|
||||||
|
<view v-for="item in log" :key="item">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tnor: 'nnn',
|
||||||
|
test: 'tt',
|
||||||
|
tobj: {
|
||||||
|
y: 34
|
||||||
|
},
|
||||||
|
log: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
watch: {
|
||||||
|
tnor(newVal, oldval) {
|
||||||
|
this.log.unshift('watch tnor:' + newVal + ',' + oldval);
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
handler(newVal, oldval) {
|
||||||
|
this.log.unshift('watch test:' + newVal + ',' + oldval);
|
||||||
|
},
|
||||||
|
immediate: true //立即执行一次
|
||||||
|
},
|
||||||
|
tobj: {
|
||||||
|
handler(newVal, oldval) {
|
||||||
|
this.log.unshift('watch tobj:' + JSON.stringify(newVal) + ',' + JSON.stringify(oldval));
|
||||||
|
},
|
||||||
|
deep: true, //同时监听obj子属性
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
'tobj.y': { //监听某个属性,减少性能开销
|
||||||
|
handler(newVal, oldval) {
|
||||||
|
this.log.unshift('watch tobj.y:' + newVal + ',' + oldval);
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
compute() {
|
||||||
|
this.log.unshift('computed test:' + this.test);
|
||||||
|
return 'computed-' + this.test;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header :title="'fix页面位置计算'" transparent></ciy-header>
|
||||||
|
<view style="position: fixed;bottom:0;z-index: 2;">
|
||||||
|
<button class="btn" @tap="addscroll">滚动切换</button>
|
||||||
|
<button class="btn" @tap="addheight">高度切换</button>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:hei+'px'}"></view>
|
||||||
|
<view class="viw">
|
||||||
|
<view>view:{{viw}}</view>
|
||||||
|
<view>screenHeight:{{sys.screenHeight}} windowHeight:{{sys.windowHeight}}</view>
|
||||||
|
<view>statusBarHeight:{{sys.statusBarHeight}} windowBottom:{{sys.windowBottom}}</view>
|
||||||
|
<view>sA:{{tostr(sys.safeArea)}}</view>
|
||||||
|
<view>safeAreaInsets:{{tostr(sys.safeAreaInsets)}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="sw fix l dat_f">
|
||||||
|
Fix: 0{{dat_f}}
|
||||||
|
<view style="top:250px;" class="sw fix l dat_ff">
|
||||||
|
f-Fix: 250{{dat_ff}}
|
||||||
|
<view style="top:300px;" class="sw fix l dat_fff">
|
||||||
|
f-f-Fix: 300{{dat_fff}}
|
||||||
|
</view>
|
||||||
|
<view style="top:100px;" class="sw abs l dat_ffa">
|
||||||
|
f-f-Abs: 100{{dat_ffa}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="top:300px;" class="sw abs l dat_fa">
|
||||||
|
f-Abs: 300{{dat_fa}}
|
||||||
|
<view style="top:500px;" class="sw fix l dat_faf">
|
||||||
|
f-a-Fix: 500{{dat_faf}}
|
||||||
|
</view>
|
||||||
|
<view style="top:150px;" class="sw abs l dat_faa">
|
||||||
|
f-a-Abs: 150{{dat_faa}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="border-top: 1px solid #ee00ff;" class="sw abs r dat_a">
|
||||||
|
Abs: 0{{dat_a}}
|
||||||
|
<view style="top:250px;" class="sw fix r dat_af">
|
||||||
|
a-Fix: 250{{dat_af}}
|
||||||
|
<view style="top:300px;" class="sw fix r dat_aff">
|
||||||
|
a-f-Fix: 300{{dat_aff}}
|
||||||
|
</view>
|
||||||
|
<view style="top:100px;" class="sw abs r dat_afa">
|
||||||
|
a-f-Abs: 100{{dat_afa}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="top:300px;" class="sw abs r dat_aa">
|
||||||
|
a-Abs: 300{{dat_aa}}
|
||||||
|
<view style="top:500px;" class="sw fix r dat_aaf">
|
||||||
|
a-a-Fix: 500{{dat_aaf}}
|
||||||
|
</view>
|
||||||
|
<view style="top:150px;" class="sw abs r dat_aaa">
|
||||||
|
a-a-Abs: 150{{dat_aaa}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="fx">
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
</view>
|
||||||
|
<view :style="{height:hei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view :style="{height:tophei+'px'}"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
<view style="height:100px"></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.viw {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viw>view {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.abs {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sw {
|
||||||
|
z-index: 2;
|
||||||
|
border-top: 1px solid #00aaff;
|
||||||
|
white-space: nowrap;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fx {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fx>view:nth-child(odd) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 50px;
|
||||||
|
border-left: 8px solid #00aa00;
|
||||||
|
border-right: 8px solid #00aa00;
|
||||||
|
border-bottom: 1px dashed #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fx>view:nth-child(even) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 50px;
|
||||||
|
border-left: 8px solid #cc0000;
|
||||||
|
border-right: 8px solid #cc0000;
|
||||||
|
border-bottom: 1px solid #eea3a5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l {
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.r {
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sys: {},
|
||||||
|
stdata: false,
|
||||||
|
hei: 0,
|
||||||
|
tophei: 0,
|
||||||
|
viw: 0,
|
||||||
|
dat_a: 0,
|
||||||
|
dat_af: 0,
|
||||||
|
dat_aff: 0,
|
||||||
|
dat_afa: 0,
|
||||||
|
dat_aa: 0,
|
||||||
|
dat_aaa: 0,
|
||||||
|
dat_aaf: 0,
|
||||||
|
dat_f: 0,
|
||||||
|
dat_ff: 0,
|
||||||
|
dat_fff: 0,
|
||||||
|
dat_ffa: 0,
|
||||||
|
dat_fa: 0,
|
||||||
|
dat_faa: 0,
|
||||||
|
dat_faf: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getdata2();
|
||||||
|
this._tick = setInterval(() => {
|
||||||
|
this.getdata2();
|
||||||
|
}, 1000);
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
onUnload() {
|
||||||
|
clearInterval(this._tick);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addscroll() {
|
||||||
|
if (this.hei)
|
||||||
|
this.hei = 0;
|
||||||
|
else
|
||||||
|
this.hei = 1000;
|
||||||
|
},
|
||||||
|
addheight() {
|
||||||
|
if (this.tophei)
|
||||||
|
this.tophei = 0;
|
||||||
|
else
|
||||||
|
this.tophei = 100;
|
||||||
|
},
|
||||||
|
getdata2() {
|
||||||
|
this.sys = uni.getWindowInfo();
|
||||||
|
this.classrect('viw');
|
||||||
|
this.classrect('dat_f');
|
||||||
|
this.classrect('dat_ff');
|
||||||
|
this.classrect('dat_fff');
|
||||||
|
this.classrect('dat_ffa');
|
||||||
|
this.classrect('dat_fa');
|
||||||
|
this.classrect('dat_faf');
|
||||||
|
this.classrect('dat_faa');
|
||||||
|
this.classrect('dat_a');
|
||||||
|
this.classrect('dat_af');
|
||||||
|
this.classrect('dat_aff');
|
||||||
|
this.classrect('dat_afa');
|
||||||
|
this.classrect('dat_aa');
|
||||||
|
this.classrect('dat_aaf');
|
||||||
|
this.classrect('dat_aaa');
|
||||||
|
},
|
||||||
|
classrect(cls) {
|
||||||
|
uni.createSelectorQuery().in(this).select('.' + cls).boundingClientRect(data => {
|
||||||
|
if (!data)
|
||||||
|
return this.alert('data.' + cls + '未获取到');
|
||||||
|
this[cls] = '/' + this.toint(data.top) + '; h:' + this.toint(data.height) + '; l:' + this
|
||||||
|
.toint(data.left);
|
||||||
|
}).exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header title="Promise极简示例"></ciy-header>
|
||||||
|
<view>
|
||||||
|
<view class="txt-center py4">
|
||||||
|
<button class="btn long" @tap="prom(true)">请求Promise success</button>
|
||||||
|
</view>
|
||||||
|
<view class="txt-center py4">
|
||||||
|
<button class="btn long" @tap="prom(false)">请求Promise fail</button>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card" style="padding:1em;">
|
||||||
|
Result: {{msg}}
|
||||||
|
</view>
|
||||||
|
<view class="px4 py1" v-for="item in log" :key="item">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
msg: '--',
|
||||||
|
log: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
watch: {},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
async prom(ret) {
|
||||||
|
this.msg = '... ...';
|
||||||
|
var res = await this.dopromise({
|
||||||
|
ret: ret
|
||||||
|
});
|
||||||
|
this.log.unshift('prom: ' + res);
|
||||||
|
console.log('prom', res);
|
||||||
|
this.msg = res ? res : 'undefined';
|
||||||
|
},
|
||||||
|
async dopromise(opt) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.log.unshift('run 1');
|
||||||
|
console.log('run 1');
|
||||||
|
setTimeout(() => {
|
||||||
|
if (opt.ret)
|
||||||
|
resolve('success');
|
||||||
|
else
|
||||||
|
return reject('fail');
|
||||||
|
this.log.unshift('result 3');
|
||||||
|
console.log('result 3');
|
||||||
|
}, 1000);
|
||||||
|
this.log.unshift('run 2');
|
||||||
|
console.log('run 2');
|
||||||
|
}).catch(e => {
|
||||||
|
this.log.unshift('catch 4: ' + e);
|
||||||
|
console.log('catch 4', e);
|
||||||
|
return e; //不返回,res为 undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header title="Vue3 Proxy"></ciy-header>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">Proxy响应式数据</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>相比Vue2,Vue3更少的考虑$set绑定问题。</view>
|
||||||
|
<view class="txt-center py4">
|
||||||
|
<button @tap="addstart" class="btn">新增到头部</button>
|
||||||
|
<button @tap="addend" class="btn">新增到底部</button>
|
||||||
|
</view>
|
||||||
|
<view v-for="(item,index) in list" :key="index" style="display: flex;align-items: center;gap: 6px;margin: 16px 0;">
|
||||||
|
<button @tap="edit(index)" class="btn def">更新</button>
|
||||||
|
<button @tap="del(index)" class="btn def">删除</button>
|
||||||
|
<view style="flex:1;">
|
||||||
|
{{item.id}}|{{item.name}}|{{item.ext}}|{{item.ext2}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
methods: {
|
||||||
|
addstart() {
|
||||||
|
var edited = {
|
||||||
|
id: 5,
|
||||||
|
name: Math.random().toFixed(2),
|
||||||
|
ext2: '头部ext2'
|
||||||
|
};
|
||||||
|
this.list.unshift(edited);
|
||||||
|
},
|
||||||
|
addend() {
|
||||||
|
var edited = {
|
||||||
|
id: 5,
|
||||||
|
name: Math.random().toFixed(2),
|
||||||
|
ext: '底部ext'
|
||||||
|
};
|
||||||
|
this.list.push(edited);
|
||||||
|
},
|
||||||
|
edit(index) {
|
||||||
|
// this.$set(this.list, index, json.edited);
|
||||||
|
this.list[index] = {
|
||||||
|
id: 6,
|
||||||
|
name: this.lang('tabbar.me') + Math.random().toFixed(2),
|
||||||
|
ext2: 'ass'
|
||||||
|
};
|
||||||
|
console.log(this.list);
|
||||||
|
},
|
||||||
|
del(index) {
|
||||||
|
this.list.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header title="工程化改进"></ciy-header>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title mk">
|
||||||
|
页面自动添加通用组件
|
||||||
|
</view>
|
||||||
|
<view class="right">template</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>在vite.config.js中添加htmlPlugin_ciy plugins。</view>
|
||||||
|
<view>在每个页面的template后添加通用组件。</view>
|
||||||
|
<view>例如: ciy-auth、ciy-alert、ciy-toast、ciy-popmenu等。</view>
|
||||||
|
<!-- 修改vite工具
|
||||||
|
D:\Program Files\HBuilderX\plugins\uniapp-cli-vite\node_modules\@dcloudio\vite-plugin-uni\dist\utils\polyfill.js
|
||||||
|
在if (options?.filename) {下加入
|
||||||
|
if (options.filename.indexOf('/pages/') > -1)
|
||||||
|
source = source.replace('<template>','<template>\n<ciy-auth id="auth" ref="auth"></ciy-auth>'); -->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">自动生成pages.json路由</view>
|
||||||
|
<view class="content">
|
||||||
|
<view>将所有vue文件放入/pages/目录下。</view>
|
||||||
|
<view>配置defpages.json,只保留pages数组第一行。</view>
|
||||||
|
<view>自建公用目录xx,复制createpages.js。</view>
|
||||||
|
<view>外部命令中添加ctrl+alt+p快捷键。</view>
|
||||||
|
<view>[{</view>
|
||||||
|
<view> "name":"Create Pages",</view>
|
||||||
|
<view> "command": ["node", "xx\createpages.js","${projectDir}"],</view>
|
||||||
|
<view> "workingDir" : "xx\createpages",</view>
|
||||||
|
<view> "key": "ctrl+alt+p",</view>
|
||||||
|
<view> "type": "shell"</view>
|
||||||
|
<view>}]</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
watch: {
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header ref="header" title="ciy-calendar组件"></ciy-header>
|
||||||
|
<view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">日历选择器</view>
|
||||||
|
<view class="content">
|
||||||
|
显示日历,选择某个日期<br />
|
||||||
|
可定制周框和日框显示效果。<br />
|
||||||
|
原生开发,无依赖。<br />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<form @submit="submitlog">
|
||||||
|
<view class="tip">默认效果:</view>
|
||||||
|
<ciy-calendar name="ciy1" v-model="formvalue" @change="chglog('change', $event)" @viewchange="chglog('viewchange', $event)"></ciy-calendar>
|
||||||
|
|
||||||
|
<view class="tip">简单定制:</view>
|
||||||
|
<view style="margin: 0 2em;background:linear-gradient(45deg,var(--man7),var(--man4))">
|
||||||
|
<ciy-calendar name="ciy2" weekmonday clearbtn hasmore bordercolor="#ff0000" selecttextcolor="#ff0000" selectbg="linear-gradient(335deg, #8fffac, #32bcf1);" :value="formvalue" mindate="2024-6-10" :maxdate="maxdate" @change="chglog('change', $event)" @viewchange="chglog('viewchange', $event)"></ciy-calendar>
|
||||||
|
</view>
|
||||||
|
<view class="tip">
|
||||||
|
多语言:
|
||||||
|
<text v-for="(item,index) in locales" class="lang" :class="{selected:locale == item.id}" @tap="setlocale(item.id)">{{item.name}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="tip">选择月份:</view>
|
||||||
|
<view>
|
||||||
|
<ciy-calendar name="ciy3" selectmonth weekmonday clearbtn hasmore :value="formvalue" @change="chglog('change', $event)" @viewchange="chglog('viewchange', $event)"></ciy-calendar>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="tip">Slot定制:</view>
|
||||||
|
<view style="margin: 0 0.5em;background:#ffffff;border-radius: 0.5em;border:1px solid #dddddd;box-shadow: 2px 2px 5px #cccccc;">
|
||||||
|
<ciy-calendar name="ciy4" height="29em" :value="formvalue" @change="chglog('change', $event)" @viewchange="chglog('viewchange', $event)">
|
||||||
|
<template v-slot:header="{itm}">
|
||||||
|
<view class="week">周{{itm.week}}</view>
|
||||||
|
</template>
|
||||||
|
<template v-slot:data="{itm}">
|
||||||
|
<view class="day" :class="{qdday:qd(itm),qdsel:itm.select}">{{itm.day}}</view>
|
||||||
|
</template>
|
||||||
|
</ciy-calendar>
|
||||||
|
</view>
|
||||||
|
<view class="txt-center px4 py4">
|
||||||
|
<button class="btn" form-type="submit">提交表单</button>
|
||||||
|
<button class="btn" @tap="formvalue=1723456700">改变值</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="ciy-card formcard" v-if="formdata">
|
||||||
|
<view class="content">
|
||||||
|
<view v-html="tobr(formdata, true)" class="formdata"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</form>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">属性</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="prp">name,value,v-model</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">initevent</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否产生初始事件。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">hasmore</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否form携带更多格式的数据。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">bordercolor</view>
|
||||||
|
<view class="tip">
|
||||||
|
选中日期边框和周列分隔线颜色。<br />
|
||||||
|
默认 var(--bg6)
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">selecttextcolor</view>
|
||||||
|
<view class="tip">
|
||||||
|
选中日期、选择年、选择月的文字色。<br />
|
||||||
|
默认 var(--man5)
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">selectbg</view>
|
||||||
|
<view class="tip">
|
||||||
|
选中日期背景色。<br />
|
||||||
|
默认 var(--bg1)
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">height</view>
|
||||||
|
<view class="tip">
|
||||||
|
组件高度。<br />
|
||||||
|
默认 23em
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">selectmonth</view>
|
||||||
|
<view class="tip">
|
||||||
|
选择月份模式。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">weekmonday</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否周一在第一列。<br />
|
||||||
|
默认 false 周日在第一列
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">mindate,maxdate</view>
|
||||||
|
<view class="tip">
|
||||||
|
可选日期范围,如果不设则不限制。<br />
|
||||||
|
数据格式: 2020-12-12、1607702400
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">clearbtn</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否显示不选日期按钮。点击则清空日期<br />
|
||||||
|
默认 false 不显示
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">方法</view>
|
||||||
|
<view class="content">
|
||||||
|
无
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">事件</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="evt">@change, update:modelValue</view>
|
||||||
|
<view class="tip">
|
||||||
|
数值变更事件<br />
|
||||||
|
from: init,click,today,nodate
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="evt">@viewchange</view>
|
||||||
|
<view class="tip">
|
||||||
|
数值变更事件<br />
|
||||||
|
from: year,month
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="log" v-for="(item, index) in eventlog" :key="index">
|
||||||
|
<text class="code">{{eventlog.length - index}}</text>
|
||||||
|
{{item}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '@/pages/demo/zdemo.css';
|
||||||
|
|
||||||
|
.week {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 2em;
|
||||||
|
background: linear-gradient(0deg, #ffffff, #d3ebf3);
|
||||||
|
border-right: 1px solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day {
|
||||||
|
line-height: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qdday {
|
||||||
|
background: linear-gradient(45deg, var(--man4), var(--man7));
|
||||||
|
color: var(--bg1);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qdday::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1.8em;
|
||||||
|
right: 0;
|
||||||
|
background-color: var(--bg3);
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
border: 1px solid var(--man5);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
transform-origin: right bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qdsel {
|
||||||
|
color: var(--dag6);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import zmixin from '@/pages/demo/zmixin.js';
|
||||||
|
export default {
|
||||||
|
mixins: [zmixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formvalue: 0,
|
||||||
|
maxdate: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.maxdate = this.tostamp() + 86400 * 7;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
qd(e) {
|
||||||
|
if (e.day == '')
|
||||||
|
return false;
|
||||||
|
return Math.random() > 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header ref="header" title="ciy-capcode组件"></ciy-header>
|
||||||
|
<view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">验证码组件</view>
|
||||||
|
<view class="content">
|
||||||
|
数秒倒计时,后台交互联动。<br />
|
||||||
|
判断真人点击。
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<form @submit="submitlog">
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>账号</label>
|
||||||
|
<view>
|
||||||
|
<ciy-input name="account" bb v-model="account"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>验证码</label>
|
||||||
|
<view>
|
||||||
|
<ciy-capcode hasmore name="ciy1" btntxt="发送短信" :account="account" :btntxt="props.btntxt" :func="props.func" :placeholder="props.placeholder" :maxlength="props.maxlength" :maxsec="props.maxsec" @change="chglog('change', $event)"></ciy-capcode>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="txt-center px4 py4">
|
||||||
|
<button class="btn" form-type="submit">提交表单</button>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card formcard" v-if="formdata">
|
||||||
|
<view class="content">
|
||||||
|
<view v-html="tobr(formdata, true)" class="formdata"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</form>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">属性</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="prp">name</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">hasmore</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">placeholder</view>
|
||||||
|
<view class="tip">
|
||||||
|
占位文字。<br />
|
||||||
|
默认 请选择
|
||||||
|
</view>
|
||||||
|
<ciy-input bb v-model="props.placeholder"></ciy-input>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">btntxt</view>
|
||||||
|
<view class="tip">
|
||||||
|
按钮文字。<br />
|
||||||
|
</view>
|
||||||
|
<ciy-input bb v-model="props.btntxt"></ciy-input>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">account</view>
|
||||||
|
<view class="tip">
|
||||||
|
外部账号数据。<br />
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">func</view>
|
||||||
|
<view class="tip">
|
||||||
|
调用的函数名称。<br />
|
||||||
|
</view>
|
||||||
|
<ciy-input bb v-model="props.func"></ciy-input>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">codelength</view>
|
||||||
|
<view class="tip">
|
||||||
|
生成的验证码长度。<br />
|
||||||
|
默认 4
|
||||||
|
</view>
|
||||||
|
<ciy-input bb v-model="props.codelength" style="width:4em;"></ciy-input>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">maxsec</view>
|
||||||
|
<view class="tip">
|
||||||
|
数秒倒计时。<br />
|
||||||
|
默认 60
|
||||||
|
</view>
|
||||||
|
<ciy-input bb v-model="props.maxsec" style="width:4em;"></ciy-input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">方法</view>
|
||||||
|
<view class="content">
|
||||||
|
无
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">事件</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="evt">@change</view>
|
||||||
|
<view class="tip">
|
||||||
|
发送事件<br />
|
||||||
|
from: send,tickend
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="log" v-for="(item, index) in eventlog" :key="index">
|
||||||
|
<text class="code">{{eventlog.length - index}}</text>
|
||||||
|
{{item}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '@/pages/demo/zdemo.css';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import zmixin from '@/pages/demo/zmixin.js';
|
||||||
|
export default {
|
||||||
|
mixins: [zmixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formvalue: 0,
|
||||||
|
account: '',
|
||||||
|
props:{
|
||||||
|
btntxt:'发送短信',
|
||||||
|
placeholder:'请选择',
|
||||||
|
func:'login.sendsms',
|
||||||
|
codelength:4,
|
||||||
|
maxsec:60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
<template>
|
||||||
|
<ciy-header ref="header" title="ciy-checkbox组件"></ciy-header>
|
||||||
|
<view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">复选框</view>
|
||||||
|
<view class="content">
|
||||||
|
相比传统checkbox-group组件,可与字典联动。<br />
|
||||||
|
选项数据格式,[{id,name}]数组。<br />
|
||||||
|
数据用小写逗号分隔,两边都有逗号。<br />
|
||||||
|
方便like数据库查询法(简单低效)。<br />
|
||||||
|
大数据量的多选筛选,应独立建副表或用ES。<br />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<form @submit="submitlog">
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>原始组件</label>
|
||||||
|
<view>
|
||||||
|
<checkbox-group name="ori">
|
||||||
|
<label>
|
||||||
|
<checkbox value="r1" />选项1
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<checkbox value="r2" />选项2
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<checkbox value="r3" />选项3
|
||||||
|
</label>
|
||||||
|
</checkbox-group>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>v-model绑定</label>
|
||||||
|
<view>
|
||||||
|
<ciy-checkbox v-model="formvalue" name="ciy1" :range="rang" @change="chglog('change', $event)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>整行排列</label>
|
||||||
|
<view>
|
||||||
|
<ciy-checkbox line itemright hasmore :value="formvalue" name="ciy2" :range="rang" @change="chglog('change', $event)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>禁用</label>
|
||||||
|
<view>
|
||||||
|
<ciy-checkbox left disabled :value="formvalue" name="ciy3" :range="rang" @change="chglog('change', $event)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label class="imp">每行一条</label>
|
||||||
|
<view>
|
||||||
|
<ciy-checkbox hasmore moreno line :value="formvalue" name="ciy4" :range="rang" @change="chglog('change', $event)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>十六进制</label>
|
||||||
|
<view>
|
||||||
|
<ciy-checkbox bin :value="formvalue16" name="ciy5" :range="rang" @change="chglog('change', $event)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-form">
|
||||||
|
<label>简易range</label>
|
||||||
|
<view>
|
||||||
|
<ciy-checkbox :value="formvalue" name="ciy6" range="10:待处理,20:已处理" @change="chglog('change', $event)"></ciy-checkbox>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="txt-center px4 py4">
|
||||||
|
<button class="btn" form-type="submit">提交表单</button>
|
||||||
|
<button class="btn" @tap="formvalue='1,3'">改变值</button>
|
||||||
|
<button class="btn" @tap="formvalue16=5">改变hex</button>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card formcard" v-if="formdata">
|
||||||
|
<view class="content">
|
||||||
|
<view v-html="tobr(formdata, true)" class="formdata"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</form>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">属性</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="prp">name,value,v-model</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">disabled</view>
|
||||||
|
<view class="tip">
|
||||||
|
禁止选择。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">initevent</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否产生初始事件。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">hasmore</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否form携带更多格式的数据。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">moreno</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否form携带未选中数据。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">left</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否左侧显示。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">range</view>
|
||||||
|
<view class="tip">
|
||||||
|
选项数组,object需包含id,name,upid。<br />
|
||||||
|
简易字符串,id1.name1,id2.name2,...<br />
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">bin</view>
|
||||||
|
<view class="tip">
|
||||||
|
十六进制,按位返回整数。<br />
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">itemright</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否选项方块在右侧。<br />
|
||||||
|
默认 false 在左侧
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">line</view>
|
||||||
|
<view class="tip">
|
||||||
|
是否每一个选项单独一行。<br />
|
||||||
|
默认 false
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="prp">byname (即将废弃)</view>
|
||||||
|
<view class="tip">
|
||||||
|
以name匹配选项。<br />
|
||||||
|
默认 false 以id匹配。
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">方法</view>
|
||||||
|
<view class="content">
|
||||||
|
无
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ciy-card">
|
||||||
|
<view class="title">事件</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="evt">@change, update:modelValue</view>
|
||||||
|
<view class="tip">
|
||||||
|
数值变更事件<br />
|
||||||
|
from: init,check
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
<view class="log" v-for="(item, index) in eventlog" :key="index">
|
||||||
|
<text class="code">{{eventlog.length - index}}</text>
|
||||||
|
{{item}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="hr"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '@/pages/demo/zdemo.css';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import zmixin from '@/pages/demo/zmixin.js';
|
||||||
|
export default {
|
||||||
|
mixins: [zmixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formvalue: '',
|
||||||
|
formvalue16: 0,
|
||||||
|
rang: [{
|
||||||
|
id: 1,
|
||||||
|
name: '选项1'
|
||||||
|
}, {
|
||||||
|
id: 2,
|
||||||
|
name: '选项2'
|
||||||
|
}, {
|
||||||
|
id: 3,
|
||||||
|
name: '选项3'
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
methods: {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user