├── LICENSE ├── README.md ├── images ├── 个人信息.png ├── 体质分析.png ├── 体质记录.png ├── 使用说明.png ├── 症状匹配.png ├── 膳食推荐.png └── 首页.jpg └── mini-program ├── backend └── ai_tongue │ ├── 3597134_www.aitongue.tech.crt │ ├── 3597134_www.aitongue.tech.key │ ├── RecWholeModel_5.pt │ ├── __pycache__ │ ├── app.cpython-36.pyc │ ├── app.cpython-37.pyc │ ├── constant.cpython-36.pyc │ ├── constant.cpython-37.pyc │ ├── picSegment.cpython-36.pyc │ ├── runModel.cpython-37.pyc │ ├── runModel2.cpython-36.pyc │ ├── runModel2.cpython-37.pyc │ └── runModel3.cpython-36.pyc │ ├── app.py │ ├── app.pyc │ ├── cert.pem │ ├── constant.py │ ├── information.csv │ ├── key.pem │ ├── nohup.out │ ├── picSegment.py │ ├── runModel.py │ ├── runModel2.py │ ├── runModel3.py │ └── upload_picture │ ├── 58957275.jpg │ └── __pycache__ │ ├── api.cpython-37.pyc │ ├── craws_proxy_ip.cpython-37.pyc │ ├── douban.cpython-37.pyc │ └── task.cpython-37.pyc ├── crawler └── 爬取百度贴吧指定吧图片.py └── frontend ├── .gitignore ├── app.js ├── app.json ├── app.wxss ├── colorUI └── icon.wxss ├── image-cropper ├── image-cropper.js ├── image-cropper.json ├── image-cropper.wxml └── image-cropper.wxss ├── images ├── ac_down.png ├── ac_icon.png ├── ac_up.png ├── air.png ├── bg_image.png ├── camera.png ├── cameraIcon.png ├── card.png ├── damp.png ├── diet.png ├── drink.png ├── eye.png ├── food-and-restaurant.png ├── food.png ├── food_rec.png ├── ganmao.png ├── help.png ├── icon_component_1.png ├── icon_component_2.png ├── icon_component_3.png ├── icon_component_4.png ├── info.png ├── info_card.png ├── like.png ├── next.png ├── risk.png ├── scan.png ├── shop.png ├── shopp.png ├── solar.png ├── solar_text.png ├── spit_rec.png ├── sym.png ├── tongue.png ├── tongue2.png └── ziwai.png ├── package.json ├── pages ├── crop │ ├── crop.js │ ├── crop.json │ ├── crop.wxml │ └── crop.wxss ├── detail │ ├── detail.js │ ├── detail.json │ ├── detail.wxml │ └── detail.wxss ├── drinks │ ├── drinks.js │ ├── drinks.json │ ├── drinks.wxml │ └── drinks.wxss ├── help │ ├── help.js │ ├── help.json │ ├── help.wxml │ └── help.wxss ├── index │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── logs │ ├── logs.js │ ├── logs.json │ ├── logs.wxml │ └── logs.wxss ├── optional │ ├── optional.js │ ├── optional.json │ ├── optional.wxml │ └── optional.wxss └── result │ ├── result.js │ ├── result.json │ ├── result.wxml │ └── result.wxss ├── project.config.json ├── sitemap.json └── utils └── util.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 charfole 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 多模态信息融合主导的体质分析与膳食推荐小程序 2 | 3 | 本项目基于多模态信息融合的思想,打造了一款具有症状分析、智能舌诊功能的体质分析与膳食推荐微信小程序。 4 | 5 | ## 项目结构 6 | 项目的开发主要分为以下四个模块: 7 | 8 | - **数据获取与预处理模块** 9 | 10 | 主要用到的技术是网络爬虫,使用Python对网上的舌象图片爬取并下载到本地,之后删除掉一些冗余的图片,建立起初步的数据集并做好每张图片的数据标注。 11 | 12 | - **算法开发模块** 13 | 14 | 利用OpenCV进行图片分割、去除噪声,并且利用imgaug进行数据增广扩充数据集。舌象分类采用PyTorch框架进行开发,选择ResNet50构建模型。 15 | 16 | - **后端部署模块** 17 | 18 | 使用Gunicorn+Flask+阿里云服务器部署,将舌象分类模型与症状匹配模块信息融合后综合部署。 19 | 20 | - **微信小程序模块** 21 | 22 | 依托WXML、WXSS、JavaScript和众多开源的微信小程序组件,构建并提供一个界面精美,交互友好的小程序给用户。 23 | 24 | ## 小程序截图 25 | 26 | ### 1. 首页 27 | 28 |
29 | 30 | ### 2. 使用说明 31 | 32 |
33 | 34 | ### 3. 症状匹配 35 | 36 |
37 | 38 | ### 4. 体质分析 39 | 40 |
41 | 42 | ### 5. 个人信息 43 | 44 |
45 | 46 | ### 6. 膳食推荐 47 | 48 |
49 | 50 | ### 7. 体质记录 51 | 52 |
53 | 54 | ## License 55 | 56 | [MIT License](https://github.com/charfole/HeyConstitution/blob/master/LICENSE). -------------------------------------------------------------------------------- /images/个人信息.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/个人信息.png -------------------------------------------------------------------------------- /images/体质分析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/体质分析.png -------------------------------------------------------------------------------- /images/体质记录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/体质记录.png -------------------------------------------------------------------------------- /images/使用说明.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/使用说明.png -------------------------------------------------------------------------------- /images/症状匹配.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/症状匹配.png -------------------------------------------------------------------------------- /images/膳食推荐.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/膳食推荐.png -------------------------------------------------------------------------------- /images/首页.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/images/首页.jpg -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/3597134_www.aitongue.tech.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFnDCCBISgAwIBAgIQDEqw8CI+bV1UL2Xmr5EpKTANBgkqhkiG9w0BAQsFADBu 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg 5 | RFYgVExTIENBIC0gRzEwHhcNMjAwMzEzMDAwMDAwWhcNMjEwMzE0MTIwMDAwWjAc 6 | MRowGAYDVQQDExF3d3cuYWl0b25ndWUudGVjaDCCASIwDQYJKoZIhvcNAQEBBQAD 7 | ggEPADCCAQoCggEBAMN/2z3aTAWj7KG41/7VJiwr6lG3cFoZAy05amD5Lx4X5Wju 8 | fc4SG83sUkqDMdyaCceMzBxwP2ePZn3XiegRDbPPukuUYfYv06+iJesLN4hsl0pI 9 | QVE+c1cG5UQiNEyz46a6k0WP+A6FutspKc6uK1cyhhB6GQvQzyHFAt/jEhA/ebm9 10 | 5s6aXnsI6q5EgJAf0aUds8bOU7Due7C2Fi668AlAvOPC/NhC+tW9Yl5hLxMlxm/j 11 | oOhk/Xh5ut9sBXeI0uSYiObcWh5pJr4F7Y2/fIsSrdz0feVqVFWrtiPQ4XhlPcVV 12 | g5Wui+H04wXOHxeQzS4VvcZbSFlMVicJQO5hlTcCAwEAAaOCAoYwggKCMB8GA1Ud 13 | IwQYMBaAFFV0T7JyT/VgulDR1+ZRXJoBhxrXMB0GA1UdDgQWBBRmKpZ+BdPtG06G 14 | ooKESgstRWucxTArBgNVHREEJDAighF3d3cuYWl0b25ndWUudGVjaIINYWl0b25n 15 | dWUudGVjaDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG 16 | AQUFBwMCMEwGA1UdIARFMEMwNwYJYIZIAYb9bAECMCowKAYIKwYBBQUHAgEWHGh0 17 | dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQIBMIGABggrBgEFBQcB 18 | AQR0MHIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBKBggr 19 | BgEFBQcwAoY+aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0VuY3J5cHRpb25F 20 | dmVyeXdoZXJlRFZUTFNDQS1HMS5jcnQwCQYDVR0TBAIwADCCAQYGCisGAQQB1nkC 21 | BAIEgfcEgfQA8gB3ALvZ37wfinG1k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAAB 22 | cNTXLBEAAAQDAEgwRgIhALuZe6ABSmbJKu2EVbSEuLQ+jvAqCk2d4jN/9BxUPH5Q 23 | AiEA8+gABTOHj209eH5jFOP0O36S0SEj+nXezedbKFRwU6MAdwBc3EOS/uarRUSx 24 | XprUVuYQN/vV+kfcoXOUsl7m9scOygAAAXDU1yxBAAAEAwBIMEYCIQDD86Iw3jlh 25 | ocdyuLxIR8LoEeHxjjzBL5geppBFX2iEbQIhAJbnPQWrVNjcuedX1XS9qKXILMwX 26 | PXXUF8L0fgKkti8bMA0GCSqGSIb3DQEBCwUAA4IBAQAtZxDFmgnzt83K20oZ0/vs 27 | uDThJEzEw6WGKoyburs3qxeHaPmWNhERiBlmHAJkFPikE3QWwnSLPaKBpMpSheXG 28 | ANQ9taupwkkXG5YLu2LuML3gY7eRxxPJfmIITf2YyZEp2NQ7ZhphNOO9Hxmf2UNj 29 | 0fyhYTeAGcEjKw3D+W/S1NyE66D89uu8JXparHs5tce/Jyv1S6JwT++RWlPHZpkp 30 | oddA8JYv8OcuS0cqt4qNpCuyfKS6GNBPPzrWcbmALuZNGRr7Oo3AJMQmEza7YNIr 31 | 2r5+75+5k+UQmy4lipr5jqnfoCuavn1b1mJuv9hHikIEMrP+d+TBv4LJr6EvgSh2 32 | -----END CERTIFICATE----- 33 | -----BEGIN CERTIFICATE----- 34 | MIIEqjCCA5KgAwIBAgIQAnmsRYvBskWr+YBTzSybsTANBgkqhkiG9w0BAQsFADBh 35 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 36 | d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 37 | QTAeFw0xNzExMjcxMjQ2MTBaFw0yNzExMjcxMjQ2MTBaMG4xCzAJBgNVBAYTAlVT 38 | MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 39 | b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH 40 | MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPeP6wkab41dyQh6mKc 41 | oHqt3jRIxW5MDvf9QyiOR7VfFwK656es0UFiIb74N9pRntzF1UgYzDGu3ppZVMdo 42 | lbxhm6dWS9OK/lFehKNT0OYI9aqk6F+U7cA6jxSC+iDBPXwdF4rs3KRyp3aQn6pj 43 | pp1yr7IB6Y4zv72Ee/PlZ/6rK6InC6WpK0nPVOYR7n9iDuPe1E4IxUMBH/T33+3h 44 | yuH3dvfgiWUOUkjdpMbyxX+XNle5uEIiyBsi4IvbcTCh8ruifCIi5mDXkZrnMT8n 45 | wfYCV6v6kDdXkbgGRLKsR4pucbJtbKqIkUGxuZI2t7pfewKRc5nWecvDBZf3+p1M 46 | pA8CAwEAAaOCAU8wggFLMB0GA1UdDgQWBBRVdE+yck/1YLpQ0dfmUVyaAYca1zAf 47 | BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYw 48 | HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C 49 | AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp 50 | Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu 51 | Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG 52 | /WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT 53 | MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAK3Gp6/aGq7aBZsxf/oQ+TD/B 54 | SwW3AU4ETK+GQf2kFzYZkby5SFrHdPomunx2HBzViUchGoofGgg7gHW0W3MlQAXW 55 | M0r5LUvStcr82QDWYNPaUy4taCQmyaJ+VB+6wxHstSigOlSNF2a6vg4rgexixeiV 56 | 4YSB03Yqp2t3TeZHM9ESfkus74nQyW7pRGezj+TC44xCagCQQOzzNmzEAP2SnCrJ 57 | sNE2DpRVMnL8J6xBRdjmOsC3N6cQuKuRXbzByVBjCqAA8t1L0I+9wXJerLPyErjy 58 | rMKWaBFLmfK/AHNF4ZihwPGOc7w6UHczBZXH5RFzJNnww+WnKuTPI0HfnVH8lg== 59 | -----END CERTIFICATE----- 60 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/3597134_www.aitongue.tech.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAw3/bPdpMBaPsobjX/tUmLCvqUbdwWhkDLTlqYPkvHhflaO59 3 | zhIbzexSSoMx3JoJx4zMHHA/Z49mfdeJ6BENs8+6S5Rh9i/Tr6Il6ws3iGyXSkhB 4 | UT5zVwblRCI0TLPjprqTRY/4DoW62ykpzq4rVzKGEHoZC9DPIcUC3+MSED95ub3m 5 | zppeewjqrkSAkB/RpR2zxs5TsO57sLYWLrrwCUC848L82EL61b1iXmEvEyXGb+Og 6 | 6GT9eHm632wFd4jS5JiI5txaHmkmvgXtjb98ixKt3PR95WpUVau2I9DheGU9xVWD 7 | la6L4fTjBc4fF5DNLhW9xltIWUxWJwlA7mGVNwIDAQABAoIBAED/WEgHNPFHH9xg 8 | 1Uc/XJKhAyWqBGugF0NI7IpTLowly7sIV8FUmfPr1yw41DIQ8KFsuUvXMe1faub5 9 | 6zrBuLmIndqU+cDdA9dH5K1xrEPqPp6OyVCWn8hWXZE6ggLiaBS9wUsGY6WIZqiI 10 | 1gKGO5ihDpuZzIv2H3eNxbfkCdRmgNsjoYSR6myIAuZA/F4uISuLBR1A5OYn4OrT 11 | jD33ElusRibi73lbc2Uwp2S9ws9tY4MJxO4SEmHc+U2TvK1ITWKg4Zzsoflt5udq 12 | S3TpseCAwYv0p6HhN+o9/k+lln8Spka58Fijbb7qkBdnpcG7ZtMP7r9LxMwKuGcj 13 | 8d8a2akCgYEA9JmACdCvNGlz6katihG+Hh0FxP+y/N5BEKW4UaTxD0msWd7gHuSY 14 | 05FR/z1rPAy0Is7RigBYsI3ZfQGvD0ze+E44Fj0vjnCiFu2BgSwy7YVSYTQ6gyvV 15 | 2RCeoI+9JBleVjVRCGTG7xM29z17ITUMNliXoDbdVekLe1to7+a6ATsCgYEAzJyB 16 | b6EemgspdR3Xn1BUzvgwXO8Bp2i6JDkf09FWK2SfcdgxGYQbu/2tigx39TJQAJsr 17 | Wa2btzwB5dX4ttnOic1A4BiAOI53w3cp1vdJ9K9FT1FYsLwhnQ34/6ivpd2G+hAa 18 | ZHAnCocjufeI8QPiI+w93Lb/eqvBlXFCniNovDUCgYEAh04GWueak7alzXnNc6v+ 19 | 7C+HyoLb4y+a9HeHr3o7cwaBFbHJbq1rsNUZc8To9e3dE8gud1VbukatgY4V5bPT 20 | P64dLogoL3Y049P8KJVnkqaGfIjkuTzdbdbYuN7qdPanja6upaMBvKx3YmsbGrJ6 21 | j/GP5quS4nwowtM9CEAsspMCgYBvUH3Cgz8owwXM521VCNj6uF9nT8fwkbMi3ckI 22 | 7YwZk2aDAwDDRvHntjzhK6NfS/3mNoTBBwf+CbFmnp/uqlQI+BdhUzL+kdNqDbw/ 23 | bM1ZRrlIS5Mao18OGHnsbJMSg5BZHsWc+r7ipV60X4yqwlgW/wEwwIYA8MwiRznc 24 | 2pqyOQKBgDuVTqY6QUhNduIh+0SHb+TXuHCgNSfBDlaLMTDQ1NdLPTagFgNCOL5t 25 | v1h/b0miku9nNIZGf6KhArxz/Sx7xBIkpz7U4oR72RiLmrrFFvkZlr50CruJMmb+ 26 | lNU5BDgazorRMZQqK3DZr2u8k8YXRU7PvDYozzFdLhq4g3epDkk+ 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/RecWholeModel_5.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/RecWholeModel_5.pt -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/app.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/app.cpython-36.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/app.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/app.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/constant.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/constant.cpython-36.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/constant.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/constant.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/picSegment.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/picSegment.cpython-36.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/runModel.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/runModel.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/runModel2.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/runModel2.cpython-36.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/runModel2.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/runModel2.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/__pycache__/runModel3.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/__pycache__/runModel3.cpython-36.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/app.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # author:Tang Gaozhi 4 | 5 | import os 6 | import random 7 | from flask import Flask, request, url_for, send_from_directory,jsonify 8 | 9 | # from werkzeug import secure_filename 10 | from werkzeug.utils import secure_filename 11 | 12 | 13 | # import runModel 14 | # import runModel2 15 | import runModel3 16 | import picSegment 17 | 18 | from constant import value2Dict, type2Dict, weights2Dict 19 | from constant import imgUrl 20 | 21 | import time 22 | 23 | #保存信息用 24 | import csv 25 | 26 | 27 | ALLOWED_EXTENSIONS = set(['bmp','png', 'jpg', 'jpeg', 'gif']) 28 | 29 | app = Flask(__name__) 30 | app.config['UPLOAD_FOLDER'] = os.getcwd()+'/upload_picture' 31 | app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 32 | 33 | 34 | html = ''' 35 | 36 | Upload File 37 |

Photo Upload

38 |
39 | 40 | 41 |
42 | ''' 43 | 44 | 45 | def allowed_file(filename): 46 | return '.' in filename and \ 47 | filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS 48 | 49 | 50 | @app.route('/uploads/') 51 | def uploaded_file(filename): 52 | return send_from_directory(app.config['UPLOAD_FOLDER'], 53 | filename) 54 | 55 | 56 | @app.route('/', methods=['GET', 'POST']) 57 | def upload_file(): 58 | 59 | message = "null" 60 | isTongue = True 61 | predictedTypeRate = 0.0 62 | tags = [] 63 | result = -1 64 | maxConfidence = 0.0 65 | 66 | #下面那几个变量只是为了写入信息,不需要时应该删掉 67 | writeName = "未命名" 68 | typeList = [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0] 69 | writePredictRate = [] 70 | writeTotalRate = {} 71 | weight2Dict = {} 72 | 73 | try: 74 | 75 | if request.method == 'POST': 76 | file = request.files['file'] 77 | # print(request.values.get("tags")) 78 | if file and allowed_file(file.filename): 79 | # filename = secure_filename(file.filename) 80 | fileTime = time.strftime("%Y-%m-%d", time.localtime())+"-"+time.strftime("%H:%M:%S", time.localtime()) 81 | try: 82 | name = secure_filename(file.filename) 83 | suffix = name[name.rfind("."):] 84 | if request.values.get("name")!="null": 85 | filename = request.values.get("name")+fileTime+suffix 86 | writeName = request.values.get("name") 87 | else: 88 | filename = secure_filename(file.filename) 89 | writeName = filename 90 | except: 91 | filename = secure_filename(file.filename) 92 | writeName = filename 93 | 94 | file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) 95 | file_url = url_for('uploaded_file', filename=filename) 96 | 97 | isTongue = picSegment.pictureProcess(os.path.join(app.config['UPLOAD_FOLDER'], filename)) 98 | 99 | try: 100 | tagsString = request.values.get("tags") 101 | # print(tagsString) 102 | if tagsString!="": 103 | tags = tagsString.split(",") 104 | except: 105 | tagsString = "" 106 | pass 107 | 108 | try: 109 | 110 | if isTongue==True: 111 | rate = runModel3.getResult(os.path.join(app.config['UPLOAD_FOLDER'], filename).replace(".", "_mask."))#这里需要注意,模型2是rec,模型3是mask 112 | # print(os.path.join(app.config['UPLOAD_FOLDER'], filename).replace(".", "_rec.")) 113 | # print(rate) 114 | # rate = rate.tolist()#转为list,方便处理 115 | writePredictRate =rate 116 | # print(rate) 117 | predictedTypeRate = max(rate)#留一手,若无tags传过来,这两个就用上了 118 | maxConfidence = predictedTypeRate#看看纯预测的置信度最高的是多少 119 | result = rate.index(predictedTypeRate) 120 | 121 | 122 | if len(tags)!=0: 123 | # weight2Dict = {} 124 | 125 | for i in range(0,len(rate)): 126 | weight2Dict[i] = 0.4*rate[i] 127 | for tag in tags: 128 | # print(tags) 129 | weight2Dict[int(type2Dict[tag])-1] += weights2Dict[tag]*0.6 130 | typeList[int(type2Dict[tag])-1] += weights2Dict[tag] 131 | if tag=="身体水肿":#因为有重叠的,还要算上另一个 132 | weight2Dict[6] += weights2Dict["水肿"]*0.6 133 | if tag=="大便稀溏": 134 | weight2Dict[3] += weights2Dict["大便稀"]*0.6 135 | if tag=="胸胁疼痛": 136 | weight2Dict[2] += 0.3*0.6 137 | if tag=="乏力": 138 | weight2Dict[1] += 0.5*0.6 139 | 140 | writeTotalRate = weight2Dict 141 | typeWeight = sorted(weight2Dict.items(),key=lambda item:item[1]) 142 | 143 | result = typeWeight[-1][0]#预测体质名称下标 144 | predictedTypeRate = typeWeight[-1][1]#置信度 145 | # print(predictedTypeRate) 146 | 147 | else: 148 | writeTotalRate = writePredictRate#这句干嘛来着我忘了 149 | 150 | for i in range(0,len(rate)): 151 | weight2Dict[i] = rate[i] 152 | 153 | # type = value2Dict[str(result+1)] 154 | # # print(type) 155 | 156 | # newname = filename[:filename.find(".")] + "," + tagsString +","+ type +filename[filename.find("."):] 157 | 158 | # os.chdir(os.getcwd()+'/upload_picture') 159 | 160 | # os.rename(filename,newname) 161 | 162 | else: 163 | message = "上传照片未检测到舌头,请重新上传!" 164 | 165 | except: 166 | message = "服务器异常1,请过几分钟再试!若仍不行,请联系1348040397@qq.com" 167 | pass 168 | 169 | else: 170 | message = "请求方式错误!正确请求为POST" 171 | return html 172 | 173 | except: 174 | message = "服务器异常2,请过几分钟再试!若仍不行,请联系1348040397@qq.com" 175 | 176 | # num = str(random.randint(0,9)) 177 | 178 | # print(predictedTypeRate) 179 | # print(maxConfidence) 180 | 181 | # 8月10日注释掉,修改代码 182 | # if len(tags)!=0 and predictedTypeRate>0.25: 183 | # num = str(result+1) 184 | # elif len(tags)==0 and predictedTypeRate>0.50: 185 | # num = str(result+1) 186 | # # elif maxConfidence<0.40: 187 | # # num = str(0) 188 | # else: 189 | # num = str(1) 190 | 191 | 192 | num = str(0) 193 | 194 | 195 | 196 | # judgeFlag = True 197 | 198 | # for i in range(0,len(rate)-1): 199 | # if weight2Dict[i+2]>=0.5: 200 | # judgeFlag = False 201 | 202 | # print(weight2Dict) 203 | 204 | if weight2Dict=={} and isTongue==True: 205 | message = "服务器已宕机,请联系我们重启程序!" 206 | 207 | if isTongue==True and weight2Dict!={}: 208 | 209 | if weight2Dict[1]>0.5: 210 | num = str(1) 211 | elif maxConfidence<0.5: 212 | message = "未知体质,请检查上传图片是否正确!!" 213 | else: 214 | num = str(result+1) 215 | 216 | t = {'message':message,'confidence':str( round(predictedTypeRate, 3) ) ,'body':value2Dict[num],'imgUrl':imgUrl[value2Dict[num]],'year_month_day':time.strftime("%Y-%m-%d", time.localtime()),'time':time.strftime("%H:%M", time.localtime()) } 217 | 218 | path = "information.csv" 219 | 220 | with open(path,'a+',newline=None,encoding='gbk') as f: 221 | csv_write = csv.writer(f) 222 | writeTime = time.strftime("%Y-%m-%d", time.localtime())+"-"+time.strftime("%H:%M", time.localtime()) 223 | data_row = [writeName,filename,writeTime,tagsString,typeList,writePredictRate,writeTotalRate,value2Dict[num]] 224 | csv_write.writerow(data_row) 225 | 226 | # t = {'body':value2Dict['0'],'imgUrl':imgUrl[value2Dict['0']],'year_month_day':time.strftime("%Y-%m-%d", time.localtime()),'time':time.strftime("%H:%M", time.localtime()) } 227 | return jsonify(t) 228 | 229 | 230 | if __name__ == '__main__': 231 | # app.run(host='0.0.0.0') 232 | app.run(host='0.0.0.0',ssl_context=('3597134_www.aitongue.tech.pem', '3597134_www.aitongue.tech.key')) 233 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/app.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/app.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 33 | /57P 34 | -----END CERTIFICATE----- 35 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/constant.py: -------------------------------------------------------------------------------- 1 | imgUrl = {"未知体质":"https://s1.ax1x.com/2020/05/06/YExgxK.png", 2 | "湿热质":"https://s1.ax1x.com/2020/05/06/YEx4VH.png", 3 | "气虚质":"https://s1.ax1x.com/2020/05/06/YExIIA.png", 4 | "血瘀质":"https://s1.ax1x.com/2020/05/06/YExLM8.png", 5 | "特禀质":"https://s1.ax1x.com/2020/05/06/YExvZQ.png", 6 | "痰湿质":"https://s1.ax1x.com/2020/05/06/YExzIs.png", 7 | "阴虚质":"https://s1.ax1x.com/2020/05/06/YEzCR0.png", 8 | "阳虚质":"https://s1.ax1x.com/2020/05/06/YEzALF.png", 9 | "平和质":"https://s1.ax1x.com/2020/05/06/YEzZdJ.png", 10 | "气郁质":"https://s1.ax1x.com/2020/05/06/YEzeo9.png", 11 | } 12 | 13 | # value2Dict ={"0":"未知体质", 14 | # "1":"湿热质", 15 | # "2":"气虚质", 16 | # "3":"血瘀质", 17 | # "4":"特禀质", 18 | # "5":"痰湿质", 19 | # "6":"阴虚质", 20 | # "7":"阳虚质", 21 | # "8":"平和质", 22 | # "9":"气郁质"} 23 | 24 | ###下面是version2版本,对应新模型,上面对应旧模型 25 | 26 | value2Dict ={"0":"未知体质", 27 | "1":"平和质", 28 | "2":"气虚质", 29 | "3":"气郁质", 30 | "4":"湿热质", 31 | "5":"痰湿质", 32 | "6":"血瘀质", 33 | "7":"阳虚质", 34 | "8":"阴虚质"} 35 | 36 | # type2Dict = { 37 | # "不易疲劳":"1", 38 | # "耐寒受热":"1", 39 | # "乏力":"2", 40 | # "自汗":"2", 41 | # "容易生气":"3", 42 | # "多愁善感":"3", 43 | # "口腔溃疡":"4", 44 | # "长痘痘":"4", 45 | # "头胀胸闷":"5", 46 | # "多痰":"5", 47 | # "面色晦暗":"6", 48 | # "胸胁疼痛":"6", 49 | # "怕冷":"7", 50 | # "乏力":"7", 51 | # "口渴":"8", 52 | # "自觉发热":"8", 53 | # } 54 | 55 | type2Dict = { 56 | "耐受寒热":"1","不易疲劳":"1", 57 | "乏力":"2","少气懒言":"2","自汗":"2","容易感冒":"2", 58 | "容易生气":"3","胸胁胀痛":"3","嗳气叹气":"3","多愁善感": "3", 59 | "消化不良":"4","大便稀":"4","易长痘痘":"4","口苦":"4","身体困重":"4","口腔溃疡":"4", 60 | "痰多":"5","身体水肿":"5","头胀胸闷":"5","关节疼痛":"5", 61 | "月经血块":"6","皮肤粗糙有瘀斑":"6","面色晦暗":"6","胸胁疼痛":"6", 62 | "畏寒肢冷":"7","大便稀溏":"7","乏力":"7","水肿":"7", 63 | "口渴":"8","自觉发热":"8","心烦":"8","失眠":"8","皮肤干燥":"8" 64 | } 65 | 66 | weights2Dict = { 67 | "耐受寒热":0.4,"不易疲劳":0.6, 68 | "乏力":0.5,"少气懒言":0.2,"自汗":0.2,"容易感冒":0.1, 69 | "容易生气":0.3,"胸胁胀痛":0.3,"嗳气叹气":0.2,"多愁善感": 0.2, 70 | "消化不良":0.1,"大便稀":0.1,"易长痘痘":0.1,"口苦":0.3,"身体困重":0.2,"口腔溃疡":0.2, 71 | "痰多":0.3,"身体水肿":0.3,"头胀胸闷":0.2,"关节疼痛":0.2, 72 | "月经血块":0.3,"皮肤粗糙有瘀斑":0.3,"面色晦暗":0.2,"胸胁疼痛":0.2, 73 | "畏寒肢冷":0.3,"大便稀溏":0.3,"乏力":0.2,"水肿":0.2, 74 | "口渴":0.3,"自觉发热":0.2,"心烦":0.2,"失眠":0.2,"皮肤干燥":0.1 75 | } 76 | 77 | # type2List = [ 78 | # {"乏力":0.5,"少气懒言":0.2,"自汗":0.2,"容易感冒":0.1}, 79 | # {"容易生气":0.3,"胸胁胀痛":0.3,"嗳气叹气":0.2,"多愁善感": 0.2}, 80 | # {"消化不良":0.1,"大便稀":0.1,"易长痘痘":0.1,"口苦":0.3,"身体困重":0.2,"口腔溃疡":0.2}, 81 | # {"痰多":0.3,"身体水肿":0.3,"头胀胸闷":0.2,"关节疼痛":0.2}, 82 | # {"月经血块":0.3,"皮肤粗糙有瘀斑":0.3,"面色晦暗":0.2,"胸胁疼痛":0.2}, 83 | # {"畏寒肢冷":0.3,"大便稀溏":0.3,"乏力":0.2,"水肿":0.2} 84 | # {"口渴":0.3,"自觉发热":0.2,"心烦":0.2,"失眠":0.2,"皮肤干噪":0.1 } 85 | # ] -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/information.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/information.csv -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | 8zXYzktr0dTPS4mj35UIxl/yeRQV02Q= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/nohup.out: -------------------------------------------------------------------------------- 1 | [2020-04-21 08:31:45 -0400] [12890] [INFO] Starting gunicorn 20.0.4 2 | [2020-04-21 08:31:45 -0400] [12890] [INFO] Listening at: https://0.0.0.0:8666 (12890) 3 | [2020-04-21 08:31:45 -0400] [12890] [INFO] Using worker: sync 4 | [2020-04-21 08:31:45 -0400] [12893] [INFO] Booting worker with pid: 12893 5 | [2020-04-21 08:31:46 -0400] [12894] [INFO] Booting worker with pid: 12894 6 | [2020-04-21 08:31:46 -0400] [12896] [INFO] Booting worker with pid: 12896 7 | [2020-04-21 08:31:46 -0400] [12897] [INFO] Booting worker with pid: 12897 8 | [2020-04-21 08:31:54 -0400] [12890] [INFO] Handling signal: hup 9 | [2020-04-21 08:31:54 -0400] [12890] [INFO] Hang up: Master 10 | [2020-04-21 08:31:54 -0400] [12905] [INFO] Booting worker with pid: 12905 11 | [2020-04-21 08:31:54 -0400] [12906] [INFO] Booting worker with pid: 12906 12 | [2020-04-21 08:31:54 -0400] [12907] [INFO] Booting worker with pid: 12907 13 | [2020-04-21 08:31:54 -0400] [12908] [INFO] Booting worker with pid: 12908 14 | [2020-04-21 08:32:25 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:12905) 15 | [2020-04-21 08:32:26 -0400] [12953] [INFO] Booting worker with pid: 12953 16 | [2020-04-25 10:40:32 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:12906) 17 | [2020-04-25 10:40:33 -0400] [22448] [INFO] Booting worker with pid: 22448 18 | [2020-04-25 10:40:54 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:12908) 19 | [2020-04-25 10:40:55 -0400] [22460] [INFO] Booting worker with pid: 22460 20 | [2020-04-25 10:41:03 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:22448) 21 | [2020-04-25 10:41:04 -0400] [22472] [INFO] Booting worker with pid: 22472 22 | [2020-04-25 10:41:18 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:12907) 23 | [2020-04-25 10:41:18 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:12953) 24 | Using TensorFlow backend. 25 | [2020-04-25 10:41:18 -0400] [12907] [INFO] Worker exiting (pid: 12907) 26 | [2020-04-25 10:41:19 -0400] [22480] [INFO] Booting worker with pid: 22480 27 | [2020-04-25 10:41:19 -0400] [22481] [INFO] Booting worker with pid: 22481 28 | [2020-04-25 10:41:49 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:22480) 29 | [2020-04-25 10:41:50 -0400] [22505] [INFO] Booting worker with pid: 22505 30 | [2020-04-25 10:43:42 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:22460) 31 | [2020-04-25 10:43:43 -0400] [22583] [INFO] Booting worker with pid: 22583 32 | [2020-04-25 10:44:14 -0400] [12890] [CRITICAL] WORKER TIMEOUT (pid:22481) 33 | [2020-04-25 10:44:15 -0400] [22605] [INFO] Booting worker with pid: 22605 34 | [2020-04-25 10:44:32 -0400] [22625] [INFO] Starting gunicorn 20.0.4 35 | [2020-04-25 10:44:32 -0400] [22625] [INFO] Listening at: https://0.0.0.0:8666 (22625) 36 | [2020-04-25 10:44:32 -0400] [22625] [INFO] Using worker: sync 37 | [2020-04-25 10:44:32 -0400] [22628] [INFO] Booting worker with pid: 22628 38 | [2020-04-25 10:44:32 -0400] [22629] [INFO] Booting worker with pid: 22629 39 | [2020-04-25 10:44:32 -0400] [22630] [INFO] Booting worker with pid: 22630 40 | [2020-04-25 10:44:32 -0400] [22631] [INFO] Booting worker with pid: 22631 41 | [2020-04-25 10:45:02 -0400] [22625] [CRITICAL] WORKER TIMEOUT (pid:22628) 42 | [2020-04-25 10:45:03 -0400] [22660] [INFO] Booting worker with pid: 22660 43 | [2020-04-25 10:45:12 -0400] [22625] [CRITICAL] WORKER TIMEOUT (pid:22631) 44 | [2020-04-25 10:45:13 -0400] [22667] [INFO] Booting worker with pid: 22667 45 | [2020-04-25 10:45:34 -0400] [22625] [CRITICAL] WORKER TIMEOUT (pid:22660) 46 | [2020-04-25 10:45:35 -0400] [22687] [INFO] Booting worker with pid: 22687 47 | [2020-04-25 10:45:43 -0400] [22625] [CRITICAL] WORKER TIMEOUT (pid:22630) 48 | [2020-04-25 10:45:44 -0400] [22693] [INFO] Booting worker with pid: 22693 49 | [2020-04-25 10:52:25 -0400] [23123] [INFO] Starting gunicorn 20.0.4 50 | [2020-04-25 10:52:25 -0400] [23123] [INFO] Listening at: https://0.0.0.0:8666 (23123) 51 | [2020-04-25 10:52:25 -0400] [23123] [INFO] Using worker: sync 52 | [2020-04-25 10:52:25 -0400] [23126] [INFO] Booting worker with pid: 23126 53 | [2020-04-25 10:52:25 -0400] [23127] [INFO] Booting worker with pid: 23127 54 | [2020-04-25 10:52:25 -0400] [23128] [INFO] Booting worker with pid: 23128 55 | [2020-04-25 10:52:25 -0400] [23129] [INFO] Booting worker with pid: 23129 56 | [2020-04-25 10:52:29 -0400] [23123] [INFO] Handling signal: hup 57 | [2020-04-25 10:52:29 -0400] [23123] [INFO] Hang up: Master 58 | [2020-04-25 10:52:29 -0400] [23143] [INFO] Booting worker with pid: 23143 59 | [2020-04-25 10:52:29 -0400] [23144] [INFO] Booting worker with pid: 23144 60 | [2020-04-25 10:52:29 -0400] [23146] [INFO] Booting worker with pid: 23146 61 | [2020-04-25 10:52:29 -0400] [23145] [INFO] Booting worker with pid: 23145 62 | Using TensorFlow backend. 63 | [2020-04-26 03:20:16,440] ERROR in app: Exception on / [POST] 64 | Traceback (most recent call last): 65 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app 66 | response = self.full_dispatch_request() 67 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request 68 | rv = self.handle_user_exception(e) 69 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception 70 | reraise(exc_type, exc_value, tb) 71 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise 72 | raise value 73 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request 74 | rv = self.dispatch_request() 75 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request 76 | return self.view_functions[rule.endpoint](**req.view_args) 77 | File "/home1/user/jcf/root/flask/app.py", line 60, in upload_file 78 | except: 79 | File "/home1/user/jcf/anaconda3/lib/python3.7/posixpath.py", line 94, in join 80 | genericpath._check_arg_types('join', a, *p) 81 | File "/home1/user/jcf/anaconda3/lib/python3.7/genericpath.py", line 149, in _check_arg_types 82 | (funcname, s.__class__.__name__)) from None 83 | TypeError: join() argument must be str or bytes, not 'NoneType' 84 | [2020-04-26 03:20:46 -0400] [23123] [CRITICAL] WORKER TIMEOUT (pid:23146) 85 | Using TensorFlow backend. 86 | [2020-04-26 03:20:46 -0400] [23146] [INFO] Worker exiting (pid: 23146) 87 | [2020-04-26 03:20:46 -0400] [31143] [INFO] Booting worker with pid: 31143 88 | Using TensorFlow backend. 89 | [2020-04-26 03:21:09,034] ERROR in app: Exception on / [POST] 90 | Traceback (most recent call last): 91 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app 92 | response = self.full_dispatch_request() 93 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request 94 | rv = self.handle_user_exception(e) 95 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception 96 | reraise(exc_type, exc_value, tb) 97 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise 98 | raise value 99 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request 100 | rv = self.dispatch_request() 101 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request 102 | return self.view_functions[rule.endpoint](**req.view_args) 103 | File "/home1/user/jcf/root/flask/app.py", line 60, in upload_file 104 | except: 105 | File "/home1/user/jcf/anaconda3/lib/python3.7/posixpath.py", line 94, in join 106 | genericpath._check_arg_types('join', a, *p) 107 | File "/home1/user/jcf/anaconda3/lib/python3.7/genericpath.py", line 149, in _check_arg_types 108 | (funcname, s.__class__.__name__)) from None 109 | TypeError: join() argument must be str or bytes, not 'NoneType' 110 | [2020-04-26 03:21:19,869] ERROR in app: Exception on / [POST] 111 | Traceback (most recent call last): 112 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app 113 | response = self.full_dispatch_request() 114 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request 115 | rv = self.handle_user_exception(e) 116 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception 117 | reraise(exc_type, exc_value, tb) 118 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise 119 | raise value 120 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request 121 | rv = self.dispatch_request() 122 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request 123 | return self.view_functions[rule.endpoint](**req.view_args) 124 | File "/home1/user/jcf/root/flask/app.py", line 60, in upload_file 125 | except: 126 | File "/home1/user/jcf/anaconda3/lib/python3.7/posixpath.py", line 94, in join 127 | genericpath._check_arg_types('join', a, *p) 128 | File "/home1/user/jcf/anaconda3/lib/python3.7/genericpath.py", line 149, in _check_arg_types 129 | (funcname, s.__class__.__name__)) from None 130 | TypeError: join() argument must be str or bytes, not 'NoneType' 131 | [2020-04-26 03:21:59 -0400] [31195] [INFO] Starting gunicorn 20.0.4 132 | [2020-04-26 03:21:59 -0400] [31195] [INFO] Listening at: https://0.0.0.0:8666 (31195) 133 | [2020-04-26 03:21:59 -0400] [31195] [INFO] Using worker: sync 134 | [2020-04-26 03:21:59 -0400] [31198] [INFO] Booting worker with pid: 31198 135 | [2020-04-26 03:21:59 -0400] [31199] [INFO] Booting worker with pid: 31199 136 | [2020-04-26 03:21:59 -0400] [31200] [INFO] Booting worker with pid: 31200 137 | [2020-04-26 03:21:59 -0400] [31201] [INFO] Booting worker with pid: 31201 138 | [2020-04-26 03:22:30 -0400] [31195] [CRITICAL] WORKER TIMEOUT (pid:31199) 139 | [2020-04-26 03:22:31 -0400] [31228] [INFO] Booting worker with pid: 31228 140 | [2020-04-26 03:22:33 -0400] [31195] [CRITICAL] WORKER TIMEOUT (pid:31200) 141 | Using TensorFlow backend. 142 | [2020-04-26 03:22:33 -0400] [31200] [INFO] Worker exiting (pid: 31200) 143 | [2020-04-26 03:22:33 -0400] [31231] [INFO] Booting worker with pid: 31231 144 | [2020-04-26 03:23:05 -0400] [31195] [CRITICAL] WORKER TIMEOUT (pid:31231) 145 | [2020-04-26 03:23:06 -0400] [31255] [INFO] Booting worker with pid: 31255 146 | [2020-04-26 03:23:09 -0400] [31195] [CRITICAL] WORKER TIMEOUT (pid:31201) 147 | Using TensorFlow backend. 148 | [2020-04-26 03:23:09 -0400] [31201] [INFO] Worker exiting (pid: 31201) 149 | [2020-04-26 03:23:09 -0400] [31264] [INFO] Booting worker with pid: 31264 150 | [2020-04-26 03:23:39 -0400] [31195] [CRITICAL] WORKER TIMEOUT (pid:31264) 151 | [2020-04-26 03:23:40 -0400] [31287] [INFO] Booting worker with pid: 31287 152 | [2020-04-26 03:23:44 -0400] [31195] [CRITICAL] WORKER TIMEOUT (pid:31198) 153 | Using TensorFlow backend. 154 | [2020-04-26 03:23:44 -0400] [31198] [INFO] Worker exiting (pid: 31198) 155 | [2020-04-26 03:23:45 -0400] [31291] [INFO] Booting worker with pid: 31291 156 | [2020-04-26 03:28:16 -0400] [31560] [INFO] Starting gunicorn 20.0.4 157 | [2020-04-26 03:28:16 -0400] [31560] [INFO] Listening at: https://0.0.0.0:8666 (31560) 158 | [2020-04-26 03:28:16 -0400] [31560] [INFO] Using worker: sync 159 | [2020-04-26 03:28:16 -0400] [31563] [INFO] Booting worker with pid: 31563 160 | [2020-04-26 03:28:16 -0400] [31564] [INFO] Booting worker with pid: 31564 161 | [2020-04-26 03:28:16 -0400] [31565] [INFO] Booting worker with pid: 31565 162 | [2020-04-26 03:28:16 -0400] [31566] [INFO] Booting worker with pid: 31566 163 | Using TensorFlow backend. 164 | [2020-04-26 03:28:28,009] ERROR in app: Exception on / [POST] 165 | Traceback (most recent call last): 166 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app 167 | response = self.full_dispatch_request() 168 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request 169 | rv = self.handle_user_exception(e) 170 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception 171 | reraise(exc_type, exc_value, tb) 172 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise 173 | raise value 174 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request 175 | rv = self.dispatch_request() 176 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request 177 | return self.view_functions[rule.endpoint](**req.view_args) 178 | File "/home1/user/jcf/root/flask/app.py", line 63, in upload_file 179 | result = runModel.getResult(os.path.join(app.config['UPLOAD_FOLDER'], filename)) 180 | File "/home1/user/jcf/root/flask/runModel.py", line 33, in getResult 181 | newModel = load_model('20200203.model') 182 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/keras/models.py", line 240, in load_model 183 | model = model_from_config(model_config, custom_objects=custom_objects) 184 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/keras/models.py", line 314, in model_from_config 185 | return layer_module.deserialize(config, custom_objects=custom_objects) 186 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/keras/layers/__init__.py", line 55, in deserialize 187 | printable_module_name='layer') 188 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/keras/utils/generic_utils.py", line 139, in deserialize_keras_object 189 | list(custom_objects.items()))) 190 | File "/home1/user/jcf/anaconda3/lib/python3.7/site-packages/keras/models.py", line 1310, in from_config 191 | if 'class_name' not in config[0] or config[0]['class_name'] == 'Merge': 192 | KeyError: 0 193 | [2020-04-26 03:28:57 -0400] [31597] [INFO] Starting gunicorn 20.0.4 194 | [2020-04-26 03:28:57 -0400] [31597] [INFO] Listening at: https://0.0.0.0:8666 (31597) 195 | [2020-04-26 03:28:57 -0400] [31597] [INFO] Using worker: sync 196 | [2020-04-26 03:28:57 -0400] [31600] [INFO] Booting worker with pid: 31600 197 | [2020-04-26 03:28:57 -0400] [31601] [INFO] Booting worker with pid: 31601 198 | [2020-04-26 03:28:57 -0400] [31602] [INFO] Booting worker with pid: 31602 199 | [2020-04-26 03:28:57 -0400] [31603] [INFO] Booting worker with pid: 31603 200 | [2020-04-26 03:29:27 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31600) 201 | [2020-04-26 03:29:28 -0400] [31629] [INFO] Booting worker with pid: 31629 202 | [2020-04-26 03:29:45 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31602) 203 | Using TensorFlow backend. 204 | [2020-04-26 03:29:45 -0400] [31602] [INFO] Worker exiting (pid: 31602) 205 | [2020-04-26 03:29:45 -0400] [31645] [INFO] Booting worker with pid: 31645 206 | [2020-04-26 03:29:59 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31629) 207 | [2020-04-26 03:30:00 -0400] [31658] [INFO] Booting worker with pid: 31658 208 | [2020-04-26 03:30:16 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31645) 209 | [2020-04-26 03:30:17 -0400] [31674] [INFO] Booting worker with pid: 31674 210 | [2020-04-26 03:30:31 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31658) 211 | [2020-04-26 03:30:32 -0400] [31683] [INFO] Booting worker with pid: 31683 212 | [2020-04-26 03:30:47 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31674) 213 | [2020-04-26 03:30:48 -0400] [31699] [INFO] Booting worker with pid: 31699 214 | [2020-04-26 03:31:03 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31683) 215 | [2020-04-26 03:31:04 -0400] [31709] [INFO] Booting worker with pid: 31709 216 | [2020-04-26 03:31:19 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31699) 217 | [2020-04-26 03:31:20 -0400] [31725] [INFO] Booting worker with pid: 31725 218 | [2020-04-26 03:31:34 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31709) 219 | [2020-04-26 03:31:35 -0400] [31734] [INFO] Booting worker with pid: 31734 220 | [2020-04-26 03:31:51 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31725) 221 | [2020-04-26 03:31:52 -0400] [31750] [INFO] Booting worker with pid: 31750 222 | [2020-04-26 03:32:06 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31734) 223 | [2020-04-26 03:32:07 -0400] [31760] [INFO] Booting worker with pid: 31760 224 | [2020-04-26 03:32:22 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31750) 225 | [2020-04-26 03:32:23 -0400] [31776] [INFO] Booting worker with pid: 31776 226 | [2020-04-26 03:32:38 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31760) 227 | [2020-04-26 03:32:39 -0400] [31791] [INFO] Booting worker with pid: 31791 228 | [2020-04-26 03:32:54 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31776) 229 | [2020-04-26 03:32:55 -0400] [31801] [INFO] Booting worker with pid: 31801 230 | [2020-04-26 03:33:09 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31791) 231 | [2020-04-26 03:33:10 -0400] [31817] [INFO] Booting worker with pid: 31817 232 | [2020-04-26 03:33:26 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31801) 233 | [2020-04-26 03:33:27 -0400] [31827] [INFO] Booting worker with pid: 31827 234 | [2020-04-26 03:33:41 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31817) 235 | [2020-04-26 03:33:42 -0400] [31842] [INFO] Booting worker with pid: 31842 236 | [2020-04-26 03:33:57 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31827) 237 | [2020-04-26 03:33:58 -0400] [31852] [INFO] Booting worker with pid: 31852 238 | [2020-04-26 03:34:13 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31842) 239 | [2020-04-26 03:34:14 -0400] [31868] [INFO] Booting worker with pid: 31868 240 | [2020-04-26 03:34:29 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31852) 241 | [2020-04-26 03:34:30 -0400] [31878] [INFO] Booting worker with pid: 31878 242 | [2020-04-26 03:34:44 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31868) 243 | [2020-04-26 03:34:45 -0400] [31893] [INFO] Booting worker with pid: 31893 244 | [2020-04-26 03:35:00 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31878) 245 | [2020-04-26 03:35:01 -0400] [31906] [INFO] Booting worker with pid: 31906 246 | [2020-04-26 03:35:16 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31893) 247 | [2020-04-26 03:35:17 -0400] [31922] [INFO] Booting worker with pid: 31922 248 | [2020-04-26 03:35:32 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31906) 249 | [2020-04-26 03:35:33 -0400] [31932] [INFO] Booting worker with pid: 31932 250 | [2020-04-26 03:35:47 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31922) 251 | [2020-04-26 03:35:48 -0400] [31947] [INFO] Booting worker with pid: 31947 252 | [2020-04-26 03:36:04 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31932) 253 | [2020-04-26 03:36:05 -0400] [31957] [INFO] Booting worker with pid: 31957 254 | [2020-04-26 03:36:19 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31947) 255 | [2020-04-26 03:36:20 -0400] [31973] [INFO] Booting worker with pid: 31973 256 | [2020-04-26 03:36:35 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31957) 257 | [2020-04-26 03:36:36 -0400] [31983] [INFO] Booting worker with pid: 31983 258 | [2020-04-26 03:36:51 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31973) 259 | [2020-04-26 03:36:52 -0400] [31998] [INFO] Booting worker with pid: 31998 260 | [2020-04-26 03:37:07 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31983) 261 | [2020-04-26 03:37:08 -0400] [32015] [INFO] Booting worker with pid: 32015 262 | [2020-04-26 03:37:22 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:31998) 263 | [2020-04-26 03:37:23 -0400] [32025] [INFO] Booting worker with pid: 32025 264 | [2020-04-26 03:37:39 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:32015) 265 | [2020-04-26 03:37:40 -0400] [32041] [INFO] Booting worker with pid: 32041 266 | [2020-04-26 03:37:54 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:32025) 267 | [2020-04-26 03:37:55 -0400] [32050] [INFO] Booting worker with pid: 32050 268 | [2020-04-26 03:38:10 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:32041) 269 | [2020-04-26 03:38:11 -0400] [32066] [INFO] Booting worker with pid: 32066 270 | [2020-04-26 03:38:26 -0400] [31597] [CRITICAL] WORKER TIMEOUT (pid:32050) 271 | [2020-04-26 03:38:27 -0400] [32094] [INFO] Booting worker with pid: 32094 272 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/picSegment.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | 3 | #time:2020-8-26 17:26 4 | #task:图像分割 5 | 6 | import urllib.request 7 | import base64 8 | import json 9 | import pycocotools.mask as mask_util#先pip Cython再pip install pycocotools,好坑 10 | import cv2 11 | import numpy as np 12 | # from google.colab.patches import cv2_imshow 13 | import glob 14 | import os 15 | import requests 16 | 17 | 18 | # client_id 为官网获取的AK, client_secret 为官网获取的SK 19 | host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=udjj3x3uB16w2A5CAIUWfCy6&client_secret=IxwXNR6HQf8cKtPm2wVcBCjC4qmmTY6x' 20 | response = requests.get(host) 21 | token = "24.e02b5cdcccad55ba8599ad7168b4a127.2592000.1603329667.282335-22076750" 22 | if response: 23 | token = response.json()["access_token"]#随时更新access_token 24 | 25 | 26 | ''' 27 | 图像分割函数,三个参数依次为:图片路径、矩形分割图片的命名、mask分割图片的命名 28 | ''' 29 | 30 | def pictureProcess(path): 31 | 32 | # recString = path.split("/")[-1].split(".")[0] + "_rec.jpg" # 重命名矩形分割的图片,第1518张_rec.jpg 33 | recString = path.replace(".", "_rec.") 34 | maskString = path.replace(".", "_mask.") 35 | # maskString = imgPath.split("/")[-1].split(".")[0] + "_mask.jpg" # 重命名mask分割的图片,第1518张_mask.jpg 36 | 37 | # 第一部分:读图片 38 | 39 | with open(path, 'rb') as f: # 以二进制读取图片 40 | data = f.read() 41 | encodestr = base64.b64encode(data) # 得到 byte 编码的数据 42 | 43 | # 第二部分:请求分割API,获得结果参数 44 | 45 | params = { 46 | "image" : encodestr.decode('ascii'), 47 | "threshold" : 0.9 # 注意这里是图片分割置信度的阈值,百度建议的是0.4,模型只会返回大于0.4的分割结果。 48 | } 49 | params = json.dumps(params) 50 | params=bytes(params,'utf8') 51 | 52 | access_token = token # 根据上面AK和SK获取的access_token 53 | request_url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/segmentation/seg4miniProgram" # 模型API地址 54 | request_url = request_url + "?access_token=" + access_token 55 | request = urllib.request.Request(url=request_url,data=params) 56 | request.add_header('Content-Type', 'application/json') 57 | response = urllib.request.urlopen(request) 58 | content = response.read() 59 | 60 | # print(content) 61 | 62 | try: 63 | 64 | results = json.loads(content)['results'] 65 | 66 | # print(results) 67 | 68 | # 获取结果,并画图 69 | try: 70 | 71 | results = json.loads(content)['results'] 72 | # print(results) 73 | ori_img = cv2.imread(path).astype(np.float32) #读图片 74 | height, width = ori_img.shape[:2] 75 | 76 | if results==[]: 77 | return False 78 | 79 | for item in results: 80 | scores = float(item["score"]) 81 | if scores >= 0.0: 82 | # Draw bbox 83 | x1 = int(item["location"]["left"]) 84 | y1 = int(item["location"]["top"]) 85 | w = int(item["location"]["width"]) 86 | h = int(item["location"]["height"]) 87 | x2 = x1 + w 88 | y2 = y1 + h 89 | 90 | cv2.rectangle(ori_img, (x1, y1), (x2, y2), (0,255,0), 2) 91 | cv2.putText(ori_img, "{} score: {}".format(item["name"], round(float(item["score"]),4)), (x1, y1 - 10), cv2.FONT_HERSHEY_PLAIN, 0.7, (255, 255, 255), 1) 92 | 93 | # Draw mask 94 | rle_obj = {"counts": item['mask'], 95 | "size": [height, width]} 96 | mask = mask_util.decode(rle_obj) 97 | 98 | for i in range(0,height): 99 | for j in range(0,width): 100 | if mask[i][j]==1 : 101 | mask[i][j]=2 102 | elif mask[i][j]==0: 103 | mask[i][j]=1 104 | 105 | for i in range(0,height): 106 | for j in range(0,width): 107 | if mask[i][j]==2 : 108 | mask[i][j]=0 109 | 110 | new_rle_obj = mask_util.encode(mask) 111 | idx = np.nonzero(mask) 112 | 113 | #注释时间为2020-9-22 9:35 原因:这个模型用到的是mask 114 | # # 处理矩形分割,并保存矩形分割图 115 | # cropped_rec = ori_img[y1:y2,x1:x2] 116 | # cropped_rec2 = cv2.resize(cropped_rec, (350, 350), interpolation=cv2.INTER_LANCZOS4)#图片resize:https://blog.csdn.net/C_chuxin/article/details/82817407 117 | # # cv2_imshow(cropped_rec) 118 | # recString = "" + recString 119 | # cv2.imwrite(recString, cropped_rec2) 120 | # # print(recString.split('/')[-1] + " sussessfully processed") 121 | 122 | # 处理mask分割,并保存mask分割图 123 | ori_img[idx[0], idx[1], :] = np.array([255,255,255]) 124 | cropped_mask = ori_img[y1:y2,x1:x2] 125 | cropped_mask2 = cv2.resize(cropped_mask, (350, 350), interpolation=cv2.INTER_LANCZOS4)#图片resize:https://blog.csdn.net/C_chuxin/article/details/82817407 126 | 127 | # cv2_imshow(cropped_mask2) 128 | maskString = "" + maskString 129 | cv2.imwrite(maskString, cropped_mask2) 130 | # print(maskString.split('/')[-1] + " sussessfully processed") 131 | 132 | return True 133 | 134 | 135 | except ValueError: 136 | return False 137 | 138 | except Exception as e: 139 | # print(e) 140 | return False -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/runModel.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | from keras.models import load_model 3 | from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img 4 | import numpy as np 5 | 6 | WIDTH = 100 7 | HEIGHT = 100 8 | 9 | #定义图像读取 10 | def get_image_pixel(file): 11 | img = Image.open(file) 12 | img = img.resize((WIDTH,HEIGHT)) 13 | #图片灰度化-l 14 | img = img.convert("L") 15 | img_array = img_to_array(img) 16 | return img_array 17 | 18 | 19 | #获取要预测的图片的像素矩阵 20 | def get_test_image_pixel(file): 21 | X_test = [] 22 | img_array = get_image_pixel(file) 23 | X_test.append(img_array) 24 | X_test = np.array(X_test) 25 | X_test = X_test.reshape(1, WIDTH, HEIGHT, 1) 26 | X_test = X_test.astype('float32') 27 | X_test /= 255 #归一化 28 | return X_test 29 | 30 | #获取上传图片对应体质结果 31 | def getResult(filePath): 32 | #根据tag输出对应的分类 33 | newModel = load_model('20200203.model') 34 | # newModel.summary() 35 | 36 | predictions_array = newModel.predict(get_test_image_pixel(filePath)) 37 | 38 | predictions_list = predictions_array.tolist()[0] 39 | # print(predictions_list) 40 | #各个分类的预测列表 41 | 42 | predictions_tag = predictions_list.index(max(predictions_list)) 43 | # print(predictions_tag) 44 | return predictions_tag 45 | #预测值最大的那个tag 46 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/runModel2.py: -------------------------------------------------------------------------------- 1 | #@title 2 | import torch 3 | from torch.autograd import Variable 4 | from torch.utils.data import Dataset, DataLoader 5 | import torch.nn as nn 6 | import torch.nn.functional as F 7 | import torch.optim as optim 8 | from torch.optim.lr_scheduler import StepLR 9 | from torchvision import datasets, transforms, models 10 | from torchvision.datasets import ImageFolder 11 | import torchvision.models as models 12 | import numpy as np 13 | import cv2 14 | from PIL import Image 15 | import os 16 | 17 | # classes = ['pinghe', 'qixu', 'qiyu', 'shire', 'tanshi', 'xueyu', 'yangxu', 'yinxu'] 18 | WIDTH, HEIGHT=350,350 19 | 20 | def getResult(filePath): 21 | # 环境 22 | # use_cuda = not no_cuda and torch.cuda.is_available() 23 | use_cuda = torch.cuda.is_available() 24 | device = torch.device("cuda" if use_cuda else "cpu") 25 | 26 | normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 27 | preprocess = transforms.Compose([transforms.ToTensor(), normalize]) 28 | img_pil = Image.open(filePath) 29 | img_pil = img_pil.resize((WIDTH, HEIGHT),Image.ANTIALIAS) 30 | img = preprocess(img_pil) 31 | img = img.unsqueeze(0) 32 | img = img.to(device) 33 | 34 | #读模型参数 35 | # model = models.resnet18(pretrained=True) 36 | # model.fc = nn.Linear(512,8) 37 | # model=model.to(device) 38 | # model.load_state_dict(torch.load(model_path)) 39 | # model.eval() 40 | 41 | # #读整个模型 42 | model=(torch.load('RecWholeModel_5.pt')) 43 | model=model.to(device) 44 | model.eval() 45 | 46 | with torch.no_grad(): 47 | py = model(img) 48 | # print(py) 49 | 50 | py = F.softmax(py,1) 51 | confidence = py.numpy() 52 | 53 | return confidence[0]#返回置信度进行加权 54 | 55 | # print(py) 56 | 57 | ''' 58 | res,predicted = torch.max(py, 1) # 获取分类结果 59 | predicted = predicted.numpy() 60 | classIndex = predicted[0] 61 | res = res.numpy() #将tensor转换成numpy,再取出置信度的int 62 | rate = res[0] 63 | # print(rate,classIndex) 64 | return res,predicted 65 | ''' 66 | # return rate,classIndex 67 | 68 | # print("置信度:",rate) 69 | # print("种类:",classIndex) 70 | # print('预测结果:类{} {}'.format(classIndex, class_name[classIndex])) 71 | 72 | # predict(model_path,img_path,classes) -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/runModel3.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | #time: 2020-9-22 8:36 3 | #author:Tang Gaozhi 4 | #target:新的图像分类模型 5 | 6 | import requests 7 | import urllib.request 8 | import base64 9 | import json 10 | 11 | # client_id 为官网获取的AK, client_secret 为官网获取的SK 12 | host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=2lmGPrCIikIwRlqbeRT5Eg9E&client_secret=1rhxcHAG9OtEy3AR2o3sQij7WKdzUHz2' 13 | response = requests.get(host) 14 | token = "24.fe1b146c2966d72551635a05202c370f.2592000.1603179060.282335-22710328" 15 | if response: 16 | token = response.json()["access_token"] 17 | 18 | classes = ['pinghe', 'qixu', 'qiyu', 'shire', 'tanshi', 'xueyu', 'yangxu', 'yinxu'] 19 | 20 | def getResult(path): 21 | request_url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/classification/tongueClassfication" 22 | 23 | # 读入图片 24 | with open(path, 'rb') as f: 25 | base64_data = base64.b64encode(f.read()) 26 | s = base64_data.decode('UTF8') 27 | 28 | params = {"image": s, "top_num": "8"} # 两个参数分别为图片的base64编码和返回的分类结果数目 29 | params = json.dumps(params) 30 | params=bytes(params,'utf8') 31 | 32 | access_token = token 33 | request_url = request_url + "?access_token=" + access_token 34 | request = urllib.request.Request(url=request_url, data=params) 35 | request.add_header('Content-Type', 'application/json') 36 | response = urllib.request.urlopen(request) 37 | content = response.read() 38 | 39 | if content: 40 | # print(content) # 结果数组 41 | results = json.loads(content)['results'] 42 | results_dict = {} 43 | for result in results: 44 | results_dict[result["name"]] = result["score"] 45 | confidence = [] 46 | 47 | for i in range(0,len(results_dict)): 48 | confidence.append(results_dict[classes[i]]) 49 | 50 | return confidence 51 | -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/upload_picture/58957275.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/upload_picture/58957275.jpg -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/upload_picture/__pycache__/api.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/upload_picture/__pycache__/api.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/upload_picture/__pycache__/craws_proxy_ip.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/upload_picture/__pycache__/craws_proxy_ip.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/upload_picture/__pycache__/douban.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/upload_picture/__pycache__/douban.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/backend/ai_tongue/upload_picture/__pycache__/task.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/backend/ai_tongue/upload_picture/__pycache__/task.cpython-37.pyc -------------------------------------------------------------------------------- /mini-program/crawler/爬取百度贴吧指定吧图片.py: -------------------------------------------------------------------------------- 1 | #爬取百度贴吧指定吧图片 2 | 3 | # -*- coding: utf-8 -*- 4 | import requests 5 | import time 6 | from bs4 import BeautifulSoup 7 | 8 | import io 9 | import sys 10 | import urllib.request 11 | import re 12 | 13 | 14 | id_all=[] 15 | cnt=0 16 | 17 | class bdtbpicture: 18 | def __init__(self,baseurl,seeLZ): 19 | self.baseURL=baseurl 20 | self.seeLZ='?see_lz='+str(seeLZ) 21 | def getPage(self,pageNum): 22 | url=self.baseURL+self.seeLZ+'&pn='+str(pageNum) 23 | request=urllib.request.Request(url) 24 | response=urllib.request.urlopen(request) 25 | return response.read().decode('utf-8','ignore') 26 | def getPageNum(self,page): 27 | pattern = re.compile('
  • 我的人物设计和制作 64 | 65 | #发帖人: 66 | 新日落 67 | #发帖日期: 68 | 2016-09 69 | 70 | 71 | #回复数量: 72 |
    73 | 73 74 |
    75 | ''' 76 | #抓取网页的通用框架,获取页面的内容 77 | def getHtml(url): 78 | try: 79 | r= requests.get(url,timeout=30) 80 | #状态码不是200就发出httpError的异常 81 | r.raise_for_status() 82 | #获取正确的编码格式 83 | # r.encoding=r.apparent_encoding 84 | r.encoding="utf-8" 85 | #打印内容 86 | return r.text 87 | 88 | 89 | except: 90 | return "wrong!" 91 | 92 | 93 | 94 | #分析网页的html文件,整理信息,保存问列表文件中 95 | def get_content(url): 96 | #初始化一个列表来保存所有的帖子信息 97 | contents=[] 98 | 99 | #获取网页的内容 100 | html=getHtml(url) 101 | 102 | #将网页内容格式化利用bs4库 103 | soup = BeautifulSoup(html, 'lxml') 104 | 105 | #获取所有的li标签属性为 j_thread_list clearfix,用列表接收 106 | liTags = soup.find_all('li', attrs={'class': ' j_thread_list clearfix'}) 107 | print (len(liTags)) 108 | 109 | 110 | 111 | #循环这个内容li集合 112 | for li in liTags: 113 | 114 | #将爬取到了每一条信息。保存到字典里 115 | content={} 116 | 117 | #将异样抛出,避免无数据时,停止运 118 | try: 119 | #开始筛选信息 120 | content['title']=li.find('a',attrs={"class":"j_th_tit"}).text.strip()#.strip() 翻译为中文 121 | print (li.find('a',attrs={"class":"j_th_tit"}).text.strip()) 122 | 123 | #获取a标签的内部属性 124 | content['link'] ="http://tieba.baidu.com/"+li.find('a', attrs={"class": "j_th_tit"})["href"] 125 | 126 | # print("测试"+li.find('a', attrs={"class": "j_th_tit"})["href"][3:]) 127 | id_all.append(li.find('a', attrs={"class": "j_th_tit"})["href"][3:]) 128 | 129 | print("http://tieba.baidu.com/"+li.find('a', attrs={"class": "j_th_tit"})["href"]) 130 | 131 | 132 | content['author']=li.find('span',attrs={"class":'tb_icon_author '}).text.strip() 133 | print (li.find('span',attrs={"class":'tb_icon_author '}).text.strip()) 134 | 135 | 136 | content['responseNum']=li.find('span',attrs={'class': 'threadlist_rep_num center_text'}).text.strip() 137 | print(li.find( 138 | 'span', attrs={'class': 'threadlist_rep_num center_text'}).text.strip()) 139 | content['creatTime']=li.find('span',attrs={"class":'pull-right is_show_create_time'}).text.strip() 140 | print (li.find( 141 | 'span', attrs={'class': 'pull-right is_show_create_time'}).text.strip()) 142 | #将字典加入到列表中 143 | contents.append(content) 144 | 145 | 146 | except: 147 | print('出问题') 148 | 149 | 150 | 151 | #返回数据 152 | return contents 153 | 154 | 155 | def writeTxt(content): 156 | 157 | #这里不能写成 f=open("data.txt",'a+')否则会乱码,设置沉utf-8的格式,与getHtml(url):中的encoding一致 158 | f=open("data.txt",'a+',encoding='utf-8') 159 | 160 | for c in content: 161 | f.write('标题: {} \t 链接:{} \t 发帖人:{} \t 发帖时间:{} \t 回复数量: {} \n'.format( 162 | c['title'], c['link'], c['author'], c['creatTime'], c['responseNum'])) 163 | 164 | 165 | 166 | url="https://tieba.baidu.com/f?ie=utf-8&kw=%E8%88%8C%E8%AF%8A&red_tag=z0177533255" 167 | page=14 168 | 169 | 170 | def main(url,page): 171 | 172 | url_list=[] 173 | #将所需要爬取的url放到列表中 174 | for i in range(0,page): 175 | url_list.append(url+'&pn='+str(i*50)) 176 | 177 | for u in url_list: 178 | content=get_content(u) 179 | writeTxt(content) 180 | 181 | if __name__=="__main__": 182 | main(url,page) 183 | get_content("https://tieba.baidu.com/f?ie=utf-8&kw=%E8%88%8C%E8%AF%8A&red_tag=z0177533255") 184 | 185 | print("长度"+str(len(id_all))) 186 | 187 | for i in range(0,len(id_all)): 188 | print(i) 189 | baseURL = 'http://tieba.baidu.com/p/' + id_all[i] 190 | bdtb=bdtbpicture(baseURL,0) 191 | bdtb.start() 192 | -------------------------------------------------------------------------------- /mini-program/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Windows 2 | [Dd]esktop.ini 3 | Thumbs.db 4 | $RECYCLE.BIN/ 5 | 6 | # macOS 7 | .DS_Store 8 | .fseventsd 9 | .Spotlight-V100 10 | .TemporaryItems 11 | .Trashes 12 | 13 | # Node.js 14 | node_modules/ 15 | -------------------------------------------------------------------------------- /mini-program/frontend/app.js: -------------------------------------------------------------------------------- 1 | App({ 2 | 3 | globalData:{ 4 | log:[], 5 | userInfo: null, 6 | options:null, 7 | imgSrc:null, 8 | }, 9 | /** 10 | * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次) 11 | */ 12 | onLaunch: function () { 13 | const data = wx.getStorageSync('log') || []; 14 | console.log("加载本地存储:"+data); 15 | // 登录 16 | wx.login({ 17 | success: res => { 18 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 19 | } 20 | }) 21 | }, 22 | /** 23 | * 当小程序启动,或从后台进入前台显示,会触发 onShow 24 | */ 25 | onShow: function (options) { 26 | 27 | }, 28 | 29 | /** 30 | * 当小程序从前台进入后台,会触发 onHide 31 | */ 32 | onHide: function () { 33 | 34 | }, 35 | 36 | /** 37 | * 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息 38 | */ 39 | onError: function (msg) { 40 | 41 | }, 42 | // globalData: { 43 | // imgSrc:'' 44 | // }, 45 | }) 46 | -------------------------------------------------------------------------------- /mini-program/frontend/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/result/result", 5 | "pages/drinks/drinks", 6 | "pages/optional/optional", 7 | "pages/crop/crop", 8 | "pages/logs/logs", 9 | "pages/help/help", 10 | "pages/detail/detail" 11 | ], 12 | "tabBar": { 13 | "color": "#7A7E83", 14 | "selectedColor": "#3cc51f", 15 | "borderStyle": "white", 16 | "backgroundColor": "#ffffff", 17 | "list": [ 18 | { 19 | "pagePath": "pages/index/index", 20 | "iconPath": "images/icon_component_3.png", 21 | "selectedIconPath": "images/icon_component_3.png", 22 | "text": "舌诊" 23 | }, 24 | { 25 | "pagePath": "pages/help/help", 26 | "iconPath": "images/icon_component_1.png", 27 | "selectedIconPath": "images/icon_component_1.png", 28 | "text": "说明" 29 | }, 30 | { 31 | "pagePath": "pages/result/result", 32 | "iconPath": "images/icon_component_4.png", 33 | "selectedIconPath": "images/icon_component_4.png", 34 | "text": "我的" 35 | } 36 | ] 37 | }, 38 | "window": { 39 | "backgroundTextStyle": "light", 40 | "navigationBarBackgroundColor": "#729b89", 41 | "navigationBarTitleText": "智能舌诊", 42 | "navigationBarTextStyle": "white" 43 | }, 44 | "style": "v2", 45 | "sitemapLocation": "sitemap.json" 46 | } -------------------------------------------------------------------------------- /mini-program/frontend/app.wxss: -------------------------------------------------------------------------------- 1 | @import "/colorUI/icon.wxss"; -------------------------------------------------------------------------------- /mini-program/frontend/image-cropper/image-cropper.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | /** 4 | * 图片路径 5 | */ 6 | 'imgSrc': { 7 | type: String 8 | }, 9 | /** 10 | * 裁剪框高度 11 | */ 12 | 'height': { 13 | type: Number, 14 | value: 200 15 | }, 16 | /** 17 | * 裁剪框宽度 18 | */ 19 | 'width': { 20 | type: Number, 21 | value: 200 22 | }, 23 | /** 24 | * 裁剪框最小尺寸 25 | */ 26 | 'min_width': { 27 | type: Number, 28 | value: 50 29 | }, 30 | 'min_height': { 31 | type: Number, 32 | value: 50 33 | }, 34 | /** 35 | * 裁剪框最大尺寸 36 | */ 37 | 'max_width': { 38 | type: Number, 39 | value: 300 40 | }, 41 | 'max_height': { 42 | type: Number, 43 | value: 300 44 | }, 45 | /** 46 | * 裁剪框禁止拖动 47 | */ 48 | 'disable_width': { 49 | type: Boolean, 50 | value: false 51 | }, 52 | 'disable_height': { 53 | type: Boolean, 54 | value: false 55 | }, 56 | /** 57 | * 锁定裁剪框比例 58 | */ 59 | 'disable_ratio':{ 60 | type: Boolean, 61 | value: false 62 | }, 63 | /** 64 | * 生成的图片尺寸相对剪裁框的比例 65 | */ 66 | 'export_scale': { 67 | type: Number, 68 | value: 3 69 | }, 70 | /** 71 | * 生成的图片质量0-1 72 | */ 73 | 'quality': { 74 | type: Number, 75 | value: 1 76 | }, 77 | 'cut_top': { 78 | type: Number, 79 | value: null 80 | }, 81 | 'cut_left': { 82 | type: Number, 83 | value: null 84 | }, 85 | /** 86 | * canvas上边距(不设置默认不显示) 87 | */ 88 | 'canvas_top': { 89 | type: Number, 90 | value: null 91 | }, 92 | /** 93 | * canvas左边距(不设置默认不显示) 94 | */ 95 | 'canvas_left': { 96 | type: Number, 97 | value: null 98 | }, 99 | /** 100 | * 图片宽度 101 | */ 102 | 'img_width': { 103 | type: null, 104 | value: null 105 | }, 106 | /** 107 | * 图片高度 108 | */ 109 | 'img_height': { 110 | type: null, 111 | value: null 112 | }, 113 | /** 114 | * 图片缩放比 115 | */ 116 | 'scale': { 117 | type: Number, 118 | value: 1 119 | }, 120 | /** 121 | * 图片旋转角度 122 | */ 123 | 'angle': { 124 | type: Number, 125 | value: 0 126 | }, 127 | /** 128 | * 最小缩放比 129 | */ 130 | 'min_scale': { 131 | type: Number, 132 | value: 0.5 133 | }, 134 | /** 135 | * 最大缩放比 136 | */ 137 | 'max_scale': { 138 | type: Number, 139 | value: 2 140 | }, 141 | /** 142 | * 是否禁用旋转 143 | */ 144 | 'disable_rotate': { 145 | type: Boolean, 146 | value: false 147 | }, 148 | /** 149 | * 是否限制移动范围(剪裁框只能在图片内) 150 | */ 151 | 'limit_move':{ 152 | type: Boolean, 153 | value: false 154 | } 155 | }, 156 | data: { 157 | el: 'image-cropper', //暂时无用 158 | info: wx.getSystemInfoSync(), 159 | MOVE_THROTTLE:null,//触摸移动节流settimeout 160 | MOVE_THROTTLE_FLAG: true,//节流标识 161 | INIT_IMGWIDTH: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸) 162 | INIT_IMGHEIGHT: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸) 163 | TIME_BG: null,//背景变暗延时函数 164 | TIME_CUT_CENTER:null, 165 | _touch_img_relative: [{ 166 | x: 0, 167 | y: 0 168 | }], //鼠标和图片中心的相对位置 169 | _flag_cut_touch:false,//是否是拖动裁剪框 170 | _hypotenuse_length: 0, //双指触摸时斜边长度 171 | _flag_img_endtouch: false, //是否结束触摸 172 | _flag_bright: true, //背景是否亮 173 | _canvas_overflow:true,//canvas缩略图是否在屏幕外面 174 | _canvas_width:200, 175 | _canvas_height:200, 176 | origin_x: 0.5, //图片旋转中心 177 | origin_y: 0.5, //图片旋转中心 178 | _cut_animation: false,//是否开启图片和裁剪框过渡 179 | _img_top: wx.getSystemInfoSync().windowHeight / 2, //图片上边距 180 | _img_left: wx.getSystemInfoSync().windowWidth / 2, //图片左边距 181 | watch: { 182 | //监听截取框宽高变化 183 | width(value, that) { 184 | if (value < that.data.min_width){ 185 | that.setData({ 186 | width: that.data.min_width 187 | }); 188 | } 189 | that._computeCutSize(); 190 | }, 191 | height(value, that) { 192 | if (value < that.data.min_height) { 193 | that.setData({ 194 | height: that.data.min_height 195 | }); 196 | } 197 | that._computeCutSize(); 198 | }, 199 | angle(value, that){ 200 | //停止居中裁剪框,继续修改图片位置 201 | that._moveStop(); 202 | if(that.data.limit_move){ 203 | if (that.data.angle % 90) { 204 | that.setData({ 205 | angle: Math.round(that.data.angle / 90) * 90 206 | }); 207 | return; 208 | } 209 | } 210 | }, 211 | _cut_animation(value, that){ 212 | //开启过渡300毫秒之后自动关闭 213 | clearTimeout(that.data._cut_animation_time); 214 | if (value){ 215 | that.data._cut_animation_time = setTimeout(()=>{ 216 | that.setData({ 217 | _cut_animation:false 218 | }); 219 | },300) 220 | } 221 | }, 222 | limit_move(value, that){ 223 | if (value) { 224 | if (that.data.angle%90){ 225 | that.setData({ 226 | angle: Math.round(that.data.angle / 90)*90 227 | }); 228 | } 229 | that._imgMarginDetectionScale(); 230 | !that.data._canvas_overflow && that._draw(); 231 | } 232 | }, 233 | canvas_top(value, that){ 234 | that._canvasDetectionPosition(); 235 | }, 236 | canvas_left(value, that){ 237 | that._canvasDetectionPosition(); 238 | }, 239 | imgSrc(value, that){ 240 | that.pushImg(); 241 | }, 242 | cut_top(value, that) { 243 | that._cutDetectionPosition(); 244 | if (that.data.limit_move) { 245 | !that.data._canvas_overflow && that._draw(); 246 | } 247 | }, 248 | cut_left(value, that) { 249 | that._cutDetectionPosition(); 250 | if (that.data.limit_move) { 251 | !that.data._canvas_overflow && that._draw(); 252 | } 253 | } 254 | } 255 | }, 256 | attached() { 257 | this.data.info = wx.getSystemInfoSync(); 258 | //启用数据监听 259 | this._watcher(); 260 | this.data.INIT_IMGWIDTH = this.data.img_width; 261 | this.data.INIT_IMGHEIGHT = this.data.img_height; 262 | this.setData({ 263 | _canvas_height: this.data.height, 264 | _canvas_width: this.data.width, 265 | }); 266 | this._initCanvas(); 267 | this.data.imgSrc && (this.data.imgSrc = this.data.imgSrc); 268 | //根据开发者设置的图片目标尺寸计算实际尺寸 269 | this._initImageSize(); 270 | //设置裁剪框大小>设置图片尺寸>绘制canvas 271 | this._computeCutSize(); 272 | //检查裁剪框是否在范围内 273 | this._cutDetectionPosition(); 274 | //检查canvas是否在范围内 275 | this._canvasDetectionPosition(); 276 | //初始化完成 277 | this.triggerEvent('load', { 278 | cropper: this 279 | }); 280 | }, 281 | methods: { 282 | /** 283 | * 上传图片 284 | */ 285 | upload() { 286 | let that = this; 287 | wx.chooseImage({ 288 | count: 1, 289 | sizeType: ['original', 'compressed'], 290 | sourceType: ['album', 'camera'], 291 | success(res) { 292 | const tempFilePaths = res.tempFilePaths[0]; 293 | that.pushImg(tempFilePaths); 294 | } 295 | }) 296 | }, 297 | /** 298 | * 返回图片信息 299 | */ 300 | getImg(getCallback) { 301 | this._draw(()=>{ 302 | wx.canvasToTempFilePath({ 303 | width: this.data.width * this.data.export_scale, 304 | height: Math.round(this.data.height * this.data.export_scale), 305 | destWidth: this.data.width * this.data.export_scale, 306 | destHeight: Math.round(this.data.height) * this.data.export_scale, 307 | fileType: 'jpg', 308 | quality: this.data.quality, 309 | canvasId: this.data.el, 310 | success: (res) => { 311 | getCallback({ 312 | url: res.tempFilePath 313 | }); 314 | } 315 | }, this) 316 | }); 317 | }, 318 | /** 319 | * 设置图片动画 320 | * { 321 | * x:10,//图片在原有基础上向下移动10px 322 | * y:10,//图片在原有基础上向右移动10px 323 | * angle:10,//图片在原有基础上旋转10deg 324 | * scale:0.5,//图片在原有基础上增加0.5倍 325 | * } 326 | */ 327 | setTransform(transform) { 328 | if (!transform) return; 329 | if (!this.data.disable_rotate){ 330 | this.setData({ 331 | angle: transform.angle ? this.data.angle + transform.angle : this.data.angle 332 | }); 333 | } 334 | var scale = this.data.scale; 335 | if (transform.scale) { 336 | scale = this.data.scale + transform.scale; 337 | scale = scale <= this.data.min_scale ? this.data.min_scale : scale; 338 | scale = scale >= this.data.max_scale ? this.data.max_scale : scale; 339 | } 340 | this.data.scale = scale; 341 | let cutX = this.data.cut_left; 342 | let cutY = this.data.cut_top; 343 | if (transform.cutX){ 344 | this.setData({ 345 | cut_left: cutX + transform.cutX 346 | }); 347 | this.data.watch.cut_left(null, this); 348 | } 349 | if (transform.cutY){ 350 | this.setData({ 351 | cut_top: cutY + transform.cutY 352 | }); 353 | this.data.watch.cut_top(null, this); 354 | } 355 | this.data._img_top = transform.y ? this.data._img_top + transform.y : this.data._img_top; 356 | this.data._img_left = transform.x ? this.data._img_left + transform.x : this.data._img_left; 357 | //图像边缘检测,防止截取到空白 358 | this._imgMarginDetectionScale(); 359 | //停止居中裁剪框,继续修改图片位置 360 | this._moveDuring(); 361 | this.setData({ 362 | scale: this.data.scale, 363 | _img_top: this.data._img_top, 364 | _img_left: this.data._img_left 365 | }); 366 | !this.data._canvas_overflow && this._draw(); 367 | //可以居中裁剪框了 368 | this._moveStop();//结束操作 369 | }, 370 | /** 371 | * 设置剪裁框位置 372 | */ 373 | setCutXY(x,y){ 374 | this.setData({ 375 | cut_top: y, 376 | cut_left:x 377 | }); 378 | }, 379 | /** 380 | * 设置剪裁框尺寸 381 | */ 382 | setCutSize(w,h){ 383 | this.setData({ 384 | width: w, 385 | height:h 386 | }); 387 | this._computeCutSize(); 388 | }, 389 | /** 390 | * 设置剪裁框和图片居中 391 | */ 392 | setCutCenter() { 393 | let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5; 394 | let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5; 395 | //顺序不能变 396 | this.setData({ 397 | _img_top: this.data._img_top - this.data.cut_top + cut_top, 398 | cut_top: cut_top, //截取的框上边距 399 | _img_left: this.data._img_left - this.data.cut_left + cut_left, 400 | cut_left: cut_left, //截取的框左边距 401 | }); 402 | }, 403 | _setCutCenter(){ 404 | let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5; 405 | let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5; 406 | this.setData({ 407 | cut_top: cut_top, //截取的框上边距 408 | cut_left: cut_left, //截取的框左边距 409 | }); 410 | }, 411 | /** 412 | * 设置剪裁框宽度-即将废弃 413 | */ 414 | setWidth(width) { 415 | this.setData({ 416 | width: width 417 | }); 418 | this._computeCutSize(); 419 | }, 420 | /** 421 | * 设置剪裁框高度-即将废弃 422 | */ 423 | setHeight(height) { 424 | this.setData({ 425 | height: height 426 | }); 427 | this._computeCutSize(); 428 | }, 429 | /** 430 | * 是否锁定旋转 431 | */ 432 | setDisableRotate(value){ 433 | this.data.disable_rotate = value; 434 | }, 435 | /** 436 | * 是否限制移动 437 | */ 438 | setLimitMove(value){ 439 | this.setData({ 440 | _cut_animation: true, 441 | limit_move: !!value 442 | }); 443 | }, 444 | /** 445 | * 初始化图片,包括位置、大小、旋转角度 446 | */ 447 | imgReset() { 448 | this.setData({ 449 | scale: 1, 450 | angle: 0, 451 | _img_top: wx.getSystemInfoSync().windowHeight / 2, 452 | _img_left: wx.getSystemInfoSync().windowWidth / 2, 453 | }) 454 | }, 455 | /** 456 | * 加载(更换)图片 457 | */ 458 | pushImg(src) { 459 | if (src) { 460 | this.setData({ 461 | imgSrc: src 462 | }); 463 | //发现是手动赋值直接返回,交给watch处理 464 | return; 465 | } 466 | 467 | // getImageInfo接口传入 src: '' 会导致内存泄漏 468 | 469 | if (!this.data.imgSrc) return; 470 | wx.getImageInfo({ 471 | src: this.data.imgSrc, 472 | success: (res) => { 473 | this.data.imageObject = res; 474 | //图片非本地路径需要换成本地路径 475 | if (this.data.imgSrc.search(/tmp/) == -1){ 476 | this.setData({ 477 | imgSrc: res.path 478 | }); 479 | } 480 | //计算最后图片尺寸 481 | this._imgComputeSize(); 482 | if (this.data.limit_move) { 483 | //限制移动,不留空白处理 484 | this._imgMarginDetectionScale(); 485 | } 486 | this._draw(); 487 | }, 488 | fail: (err) => { 489 | this.setData({ 490 | imgSrc: '' 491 | }); 492 | } 493 | }); 494 | }, 495 | imageLoad(e){ 496 | setTimeout(()=>{ 497 | this.triggerEvent('imageload', this.data.imageObject); 498 | 499 | },1000) 500 | }, 501 | /** 502 | * 设置图片放大缩小 503 | */ 504 | setScale(scale) { 505 | if (!scale) return; 506 | this.setData({ 507 | scale: scale 508 | }); 509 | !this.data._canvas_overflow && this._draw(); 510 | }, 511 | /** 512 | * 设置图片旋转角度 513 | */ 514 | setAngle(angle) { 515 | if (!angle) return; 516 | this.setData({ 517 | _cut_animation: true, 518 | angle: angle 519 | }); 520 | this._imgMarginDetectionScale(); 521 | !this.data._canvas_overflow && this._draw(); 522 | }, 523 | _initCanvas() { 524 | //初始化canvas 525 | if (!this.data.ctx){ 526 | this.data.ctx = wx.createCanvasContext("image-cropper", this); 527 | } 528 | }, 529 | /** 530 | * 根据开发者设置的图片目标尺寸计算实际尺寸 531 | */ 532 | _initImageSize(){ 533 | //处理宽高特殊单位 %>px 534 | if (this.data.INIT_IMGWIDTH && typeof this.data.INIT_IMGWIDTH == "string" && this.data.INIT_IMGWIDTH.indexOf("%") != -1) { 535 | let width = this.data.INIT_IMGWIDTH.replace("%", ""); 536 | this.data.INIT_IMGWIDTH = this.data.img_width = this.data.info.windowWidth / 100 * width; 537 | } 538 | if (this.data.INIT_IMGHEIGHT && typeof this.data.INIT_IMGHEIGHT == "string" && this.data.INIT_IMGHEIGHT.indexOf("%") != -1) { 539 | let height = this.data.img_height.replace("%", ""); 540 | this.data.INIT_IMGHEIGHT = this.data.img_height = this.data.info.windowHeight / 100 * height; 541 | } 542 | }, 543 | /** 544 | * 检测剪裁框位置是否在允许的范围内(屏幕内) 545 | */ 546 | _cutDetectionPosition(){ 547 | let _cutDetectionPositionTop = () => { 548 | //检测上边距是否在范围内 549 | if (this.data.cut_top < 0) { 550 | this.setData({ 551 | cut_top: 0 552 | }); 553 | } 554 | if (this.data.cut_top > this.data.info.windowHeight - this.data.height) { 555 | this.setData({ 556 | cut_top: this.data.info.windowHeight - this.data.height 557 | }); 558 | } 559 | }, _cutDetectionPositionLeft = () => { 560 | //检测左边距是否在范围内 561 | if (this.data.cut_left < 0) { 562 | this.setData({ 563 | cut_left: 0 564 | }); 565 | } 566 | if (this.data.cut_left > this.data.info.windowWidth - this.data.width) { 567 | this.setData({ 568 | cut_left: this.data.info.windowWidth - this.data.width 569 | }); 570 | } 571 | }; 572 | //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中) 573 | if (this.data.cut_top == null && this.data.cut_left == null) { 574 | this._setCutCenter(); 575 | } else if (this.data.cut_top != null && this.data.cut_left != null){ 576 | _cutDetectionPositionTop(); 577 | _cutDetectionPositionLeft(); 578 | } else if (this.data.cut_top != null && this.data.cut_left == null) { 579 | _cutDetectionPositionTop(); 580 | this.setData({ 581 | cut_left: (this.data.info.windowWidth - this.data.width) / 2 582 | }); 583 | } else if (this.data.cut_top == null && this.data.cut_left != null) { 584 | _cutDetectionPositionLeft(); 585 | this.setData({ 586 | cut_top: (this.data.info.windowHeight - this.data.height) / 2 587 | }); 588 | } 589 | }, 590 | /** 591 | * 检测canvas位置是否在允许的范围内(屏幕内)如果在屏幕外则不开启实时渲染 592 | * 如果只写一个参数则另一个默认为0,都不写默认超出屏幕外 593 | */ 594 | _canvasDetectionPosition(){ 595 | if(this.data.canvas_top == null && this.data.canvas_left == null) { 596 | this.data._canvas_overflow = false; 597 | this.setData({ 598 | canvas_top: -5000, 599 | canvas_left: -5000 600 | }); 601 | }else if(this.data.canvas_top != null && this.data.canvas_left != null) { 602 | if (this.data.canvas_top < - this.data.height || this.data.canvas_top > this.data.info.windowHeight) { 603 | this.data._canvas_overflow = true; 604 | } else { 605 | this.data._canvas_overflow = false; 606 | } 607 | }else if(this.data.canvas_top != null && this.data.canvas_left == null) { 608 | this.setData({ 609 | canvas_left: 0 610 | }); 611 | } else if (this.data.canvas_top == null && this.data.canvas_left != null) { 612 | this.setData({ 613 | canvas_top: 0 614 | }); 615 | if (this.data.canvas_left < -this.data.width || this.data.canvas_left > this.data.info.windowWidth) { 616 | this.data._canvas_overflow = true; 617 | } else { 618 | this.data._canvas_overflow = false; 619 | } 620 | } 621 | }, 622 | /** 623 | * 图片边缘检测-位置 624 | */ 625 | _imgMarginDetectionPosition(scale) { 626 | if (!this.data.limit_move) return; 627 | let left = this.data._img_left; 628 | let top = this.data._img_top; 629 | var scale = scale || this.data.scale; 630 | let img_width = this.data.img_width; 631 | let img_height = this.data.img_height; 632 | if (this.data.angle / 90 % 2) { 633 | img_width = this.data.img_height; 634 | img_height = this.data.img_width; 635 | } 636 | left = this.data.cut_left + img_width * scale / 2 >= left ? left : this.data.cut_left + img_width * scale / 2; 637 | left = this.data.cut_left + this.data.width - img_width * scale / 2 <= left ? left : this.data.cut_left + this.data.width - img_width * scale / 2; 638 | top = this.data.cut_top + img_height * scale / 2 >= top ? top : this.data.cut_top + img_height * scale / 2; 639 | top = this.data.cut_top + this.data.height - img_height * scale / 2 <= top ? top : this.data.cut_top + this.data.height - img_height * scale / 2; 640 | this.setData({ 641 | _img_left: left, 642 | _img_top: top, 643 | scale: scale 644 | }) 645 | }, 646 | /** 647 | * 图片边缘检测-缩放 648 | */ 649 | _imgMarginDetectionScale(){ 650 | if (!this.data.limit_move)return; 651 | let scale = this.data.scale; 652 | let img_width = this.data.img_width; 653 | let img_height = this.data.img_height; 654 | if (this.data.angle / 90 % 2) { 655 | img_width = this.data.img_height; 656 | img_height = this.data.img_width; 657 | } 658 | if (img_width * scale < this.data.width){ 659 | scale = this.data.width / img_width; 660 | } 661 | if (img_height * scale < this.data.height) { 662 | scale = Math.max(scale,this.data.height / img_height); 663 | } 664 | this._imgMarginDetectionPosition(scale); 665 | }, 666 | _setData(obj) { 667 | let data = {}; 668 | for (var key in obj) { 669 | if (this.data[key] != obj[key]){ 670 | data[key] = obj[key]; 671 | } 672 | } 673 | this.setData(data); 674 | return data; 675 | }, 676 | /** 677 | * 计算图片尺寸 678 | */ 679 | _imgComputeSize() { 680 | let img_width = this.data.img_width, 681 | img_height = this.data.img_height; 682 | if (!this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) { 683 | //默认按图片最小边 = 对应裁剪框尺寸 684 | img_width = this.data.imageObject.width; 685 | img_height = this.data.imageObject.height; 686 | if (img_width / img_height > this.data.width / this.data.height){ 687 | img_height = this.data.height; 688 | img_width = this.data.imageObject.width / this.data.imageObject.height * img_height; 689 | }else{ 690 | img_width = this.data.width; 691 | img_height = this.data.imageObject.height / this.data.imageObject.width * img_width; 692 | } 693 | } else if (this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) { 694 | img_width = this.data.imageObject.width / this.data.imageObject.height * this.data.INIT_IMGHEIGHT; 695 | } else if (!this.data.INIT_IMGHEIGHT && this.data.INIT_IMGWIDTH) { 696 | img_height = this.data.imageObject.height / this.data.imageObject.width * this.data.INIT_IMGWIDTH; 697 | } 698 | this.setData({ 699 | img_width: img_width, 700 | img_height: img_height 701 | }); 702 | }, 703 | //改变截取框大小 704 | _computeCutSize() { 705 | if (this.data.width > this.data.info.windowWidth) { 706 | this.setData({ 707 | width: this.data.info.windowWidth, 708 | }); 709 | } else if (this.data.width + this.data.cut_left > this.data.info.windowWidth){ 710 | this.setData({ 711 | cut_left: this.data.info.windowWidth - this.data.cut_left, 712 | }); 713 | }; 714 | if (this.data.height > this.data.info.windowHeight) { 715 | this.setData({ 716 | height: this.data.info.windowHeight, 717 | }); 718 | } else if (this.data.height + this.data.cut_top > this.data.info.windowHeight){ 719 | this.setData({ 720 | cut_top: this.data.info.windowHeight - this.data.cut_top, 721 | }); 722 | } 723 | !this.data._canvas_overflow && this._draw(); 724 | }, 725 | //开始触摸 726 | _start(event) { 727 | this.data._flag_img_endtouch = false; 728 | if (event.touches.length == 1) { 729 | //单指拖动 730 | this.data._touch_img_relative[0] = { 731 | x: (event.touches[0].clientX - this.data._img_left), 732 | y: (event.touches[0].clientY - this.data._img_top) 733 | } 734 | } else { 735 | //双指放大 736 | let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX); 737 | let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY); 738 | this.data._touch_img_relative = [{ 739 | x: (event.touches[0].clientX - this.data._img_left), 740 | y: (event.touches[0].clientY - this.data._img_top) 741 | }, { 742 | x: (event.touches[1].clientX - this.data._img_left), 743 | y: (event.touches[1].clientY - this.data._img_top) 744 | }]; 745 | this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); 746 | } 747 | !this.data._canvas_overflow && this._draw(); 748 | }, 749 | _move_throttle(){ 750 | //安卓需要节流 751 | if (this.data.info.platform =='android'){ 752 | clearTimeout(this.data.MOVE_THROTTLE); 753 | this.data.MOVE_THROTTLE = setTimeout(() => { 754 | this.data.MOVE_THROTTLE_FLAG = true; 755 | }, 1000 / 40) 756 | return this.data.MOVE_THROTTLE_FLAG; 757 | }else{ 758 | this.data.MOVE_THROTTLE_FLAG = true; 759 | } 760 | }, 761 | _move(event) { 762 | if (this.data._flag_img_endtouch || !this.data.MOVE_THROTTLE_FLAG) return; 763 | this.data.MOVE_THROTTLE_FLAG = false; 764 | this._move_throttle(); 765 | this._moveDuring(); 766 | if (event.touches.length == 1) { 767 | //单指拖动 768 | let left = (event.touches[0].clientX - this.data._touch_img_relative[0].x), 769 | top = (event.touches[0].clientY - this.data._touch_img_relative[0].y); 770 | //图像边缘检测,防止截取到空白 771 | this.data._img_left = left; 772 | this.data._img_top = top; 773 | this._imgMarginDetectionPosition(); 774 | this.setData({ 775 | _img_left: this.data._img_left, 776 | _img_top: this.data._img_top 777 | }); 778 | } else { 779 | //双指放大 780 | let width = (Math.abs(event.touches[0].clientX - event.touches[1].clientX)), 781 | height = (Math.abs(event.touches[0].clientY - event.touches[1].clientY)), 782 | hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)), 783 | scale = this.data.scale * (hypotenuse / this.data._hypotenuse_length), 784 | current_deg = 0; 785 | scale = scale <= this.data.min_scale ? this.data.min_scale : scale; 786 | scale = scale >= this.data.max_scale ? this.data.max_scale : scale; 787 | //图像边缘检测,防止截取到空白 788 | this.data.scale = scale; 789 | this._imgMarginDetectionScale(); 790 | //双指旋转(如果没禁用旋转) 791 | let _touch_img_relative = [{ 792 | x: (event.touches[0].clientX - this.data._img_left), 793 | y: (event.touches[0].clientY - this.data._img_top) 794 | }, { 795 | x: (event.touches[1].clientX - this.data._img_left), 796 | y: (event.touches[1].clientY - this.data._img_top) 797 | }]; 798 | if (!this.data.disable_rotate){ 799 | let first_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x); 800 | let first_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[0].y, this.data._touch_img_relative[0].x); 801 | let second_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x); 802 | let second_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[1].y, this.data._touch_img_relative[1].x); 803 | //当前旋转的角度 804 | let first_deg = first_atan - first_atan_old, 805 | second_deg = second_atan - second_atan_old; 806 | if (first_deg != 0) { 807 | current_deg = first_deg; 808 | } else if (second_deg != 0) { 809 | current_deg = second_deg; 810 | } 811 | } 812 | this.data._touch_img_relative = _touch_img_relative; 813 | this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); 814 | //更新视图 815 | this.setData({ 816 | angle: this.data.angle + current_deg, 817 | scale: this.data.scale 818 | }); 819 | } 820 | !this.data._canvas_overflow && this._draw(); 821 | }, 822 | //结束操作 823 | _end(event) { 824 | this.data._flag_img_endtouch = true; 825 | this._moveStop(); 826 | }, 827 | //点击中间剪裁框处理 828 | _click(event) { 829 | if (!this.data.imgSrc) { 830 | //调起上传 831 | this.upload(); 832 | return; 833 | } 834 | this._draw(()=>{ 835 | let x = event.detail ? event.detail.x : event.touches[0].clientX; 836 | let y = event.detail ? event.detail.y : event.touches[0].clientY; 837 | if ((x >= this.data.cut_left && x <= (this.data.cut_left + this.data.width)) && (y >= this.data.cut_top && y <= (this.data.cut_top + this.data.height))) { 838 | //生成图片并回调 839 | wx.canvasToTempFilePath({ 840 | width: this.data.width * this.data.export_scale, 841 | height: Math.round(this.data.height * this.data.export_scale), 842 | destWidth: this.data.width * this.data.export_scale, 843 | destHeight: Math.round(this.data.height) * this.data.export_scale, 844 | fileType: 'jpg', 845 | quality: this.data.quality, 846 | canvasId: this.data.el, 847 | success: (res) => { 848 | this.triggerEvent('tapcut', { 849 | url: res.tempFilePath, 850 | width: this.data.width * this.data.export_scale, 851 | height: this.data.height * this.data.export_scale 852 | }); 853 | } 854 | }, this) 855 | } 856 | }); 857 | }, 858 | //渲染 859 | _draw(callback) { 860 | if (!this.data.imgSrc) return; 861 | let draw = () => { 862 | //图片实际大小 863 | let img_width = this.data.img_width * this.data.scale * this.data.export_scale; 864 | let img_height = this.data.img_height * this.data.scale * this.data.export_scale; 865 | //canvas和图片的相对距离 866 | var xpos = this.data._img_left - this.data.cut_left; 867 | var ypos = this.data._img_top - this.data.cut_top; 868 | //旋转画布 869 | this.data.ctx.translate(xpos * this.data.export_scale, ypos * this.data.export_scale); 870 | this.data.ctx.rotate(this.data.angle * Math.PI / 180); 871 | this.data.ctx.drawImage(this.data.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height); 872 | this.data.ctx.draw(false, () => { 873 | callback && callback(); 874 | }); 875 | } 876 | if (this.data.ctx.width != this.data.width || this.data.ctx.height != this.data.height){ 877 | //优化拖动裁剪框,所以必须把宽高设置放在离用户触发渲染最近的地方 878 | this.setData({ 879 | _canvas_height: this.data.height, 880 | _canvas_width: this.data.width, 881 | },()=>{ 882 | //延迟40毫秒防止点击过快出现拉伸或裁剪过多 883 | setTimeout(() => { 884 | draw(); 885 | }, 40); 886 | }); 887 | }else{ 888 | draw(); 889 | } 890 | }, 891 | //裁剪框处理 892 | _cutTouchMove(e) { 893 | if (this.data._flag_cut_touch && this.data.MOVE_THROTTLE_FLAG) { 894 | if (this.data.disable_ratio && (this.data.disable_width || this.data.disable_height)) return; 895 | //节流 896 | this.data.MOVE_THROTTLE_FLAG = false; 897 | this._move_throttle(); 898 | let width = this.data.width, 899 | height = this.data.height, 900 | cut_top = this.data.cut_top, 901 | cut_left = this.data.cut_left, 902 | size_correct = () => { 903 | width = width <= this.data.max_width ? width >= this.data.min_width ? width : this.data.min_width : this.data.max_width; 904 | height = height <= this.data.max_height ? height >= this.data.min_height ? height : this.data.min_height : this.data.max_height; 905 | }, 906 | size_inspect = () => { 907 | if ((width > this.data.max_width || width < this.data.min_width || height > this.data.max_height || height < this.data.min_height) && this.data.disable_ratio) { 908 | size_correct(); 909 | return false; 910 | } else { 911 | size_correct(); 912 | return true; 913 | } 914 | }; 915 | height = this.data.CUT_START.height + ((this.data.CUT_START.corner > 1 && this.data.CUT_START.corner < 4 ? 1 : -1) * (this.data.CUT_START.y - e.touches[0].clientY)); 916 | switch (this.data.CUT_START.corner) { 917 | case 1: 918 | width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX; 919 | if (this.data.disable_ratio) { 920 | height = width / (this.data.width / this.data.height) 921 | } 922 | if (!size_inspect()) return; 923 | cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width); 924 | break 925 | case 2: 926 | width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX; 927 | if (this.data.disable_ratio) { 928 | height = width / (this.data.width / this.data.height) 929 | } 930 | if (!size_inspect()) return; 931 | cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height) 932 | cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width) 933 | break 934 | case 3: 935 | width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX; 936 | if (this.data.disable_ratio) { 937 | height = width / (this.data.width / this.data.height) 938 | } 939 | if (!size_inspect()) return; 940 | cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height); 941 | break 942 | case 4: 943 | width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX; 944 | if (this.data.disable_ratio) { 945 | height = width / (this.data.width / this.data.height) 946 | } 947 | if (!size_inspect()) return; 948 | break 949 | } 950 | if (!this.data.disable_width && !this.data.disable_height) { 951 | this.setData({ 952 | width: width, 953 | cut_left: cut_left, 954 | height: height, 955 | cut_top: cut_top, 956 | }) 957 | } else if (!this.data.disable_width) { 958 | this.setData({ 959 | width: width, 960 | cut_left: cut_left 961 | }) 962 | } else if (!this.data.disable_height) { 963 | this.setData({ 964 | height: height, 965 | cut_top: cut_top 966 | }) 967 | } 968 | this._imgMarginDetectionScale(); 969 | } 970 | }, 971 | _cutTouchStart(e) { 972 | let currentX = e.touches[0].clientX; 973 | let currentY = e.touches[0].clientY; 974 | let cutbox_top4 = this.data.cut_top + this.data.height - 30; 975 | let cutbox_bottom4 = this.data.cut_top + this.data.height + 20; 976 | let cutbox_left4 = this.data.cut_left + this.data.width - 30; 977 | let cutbox_right4 = this.data.cut_left + this.data.width + 30; 978 | 979 | let cutbox_top3 = this.data.cut_top - 30; 980 | let cutbox_bottom3 = this.data.cut_top + 30; 981 | let cutbox_left3 = this.data.cut_left + this.data.width - 30; 982 | let cutbox_right3 = this.data.cut_left + this.data.width + 30; 983 | 984 | let cutbox_top2 = this.data.cut_top - 30; 985 | let cutbox_bottom2 = this.data.cut_top + 30; 986 | let cutbox_left2 = this.data.cut_left - 30; 987 | let cutbox_right2 = this.data.cut_left + 30; 988 | 989 | let cutbox_top1 = this.data.cut_top + this.data.height - 30; 990 | let cutbox_bottom1 = this.data.cut_top + this.data.height + 30; 991 | let cutbox_left1 = this.data.cut_left - 30; 992 | let cutbox_right1 = this.data.cut_left + 30; 993 | if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) { 994 | this._moveDuring(); 995 | this.data._flag_cut_touch = true; 996 | this.data._flag_img_endtouch = true; 997 | this.data.CUT_START = { 998 | width: this.data.width, 999 | height: this.data.height, 1000 | x: currentX, 1001 | y: currentY, 1002 | corner: 4 1003 | } 1004 | } else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) { 1005 | this._moveDuring(); 1006 | this.data._flag_cut_touch = true; 1007 | this.data._flag_img_endtouch = true; 1008 | this.data.CUT_START = { 1009 | width: this.data.width, 1010 | height: this.data.height, 1011 | x: currentX, 1012 | y: currentY, 1013 | cut_top: this.data.cut_top, 1014 | cut_left: this.data.cut_left, 1015 | corner: 3 1016 | } 1017 | } else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) { 1018 | this._moveDuring(); 1019 | this.data._flag_cut_touch = true; 1020 | this.data._flag_img_endtouch = true; 1021 | this.data.CUT_START = { 1022 | width: this.data.width, 1023 | height: this.data.height, 1024 | cut_top: this.data.cut_top, 1025 | cut_left: this.data.cut_left, 1026 | x: currentX, 1027 | y: currentY, 1028 | corner: 2 1029 | } 1030 | } else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) { 1031 | this._moveDuring(); 1032 | this.data._flag_cut_touch = true; 1033 | this.data._flag_img_endtouch = true; 1034 | this.data.CUT_START = { 1035 | width: this.data.width, 1036 | height: this.data.height, 1037 | cut_top: this.data.cut_top, 1038 | cut_left: this.data.cut_left, 1039 | x: currentX, 1040 | y: currentY, 1041 | corner: 1 1042 | } 1043 | } 1044 | }, 1045 | _cutTouchEnd(e) { 1046 | this._moveStop(); 1047 | this.data._flag_cut_touch = false; 1048 | }, 1049 | //停止移动时需要做的操作 1050 | _moveStop() { 1051 | //清空之前的自动居中延迟函数并添加最新的 1052 | clearTimeout(this.data.TIME_CUT_CENTER); 1053 | this.data.TIME_CUT_CENTER = setTimeout(() => { 1054 | //动画启动 1055 | if (!this.data._cut_animation) { 1056 | this.setData({ 1057 | _cut_animation: true 1058 | }); 1059 | } 1060 | this.setCutCenter(); 1061 | }, 1000) 1062 | //清空之前的背景变化延迟函数并添加最新的 1063 | clearTimeout(this.data.TIME_BG); 1064 | this.data.TIME_BG = setTimeout(() => { 1065 | if (this.data._flag_bright) { 1066 | this.setData({ 1067 | _flag_bright: false 1068 | }); 1069 | } 1070 | }, 2000) 1071 | }, 1072 | //移动中 1073 | _moveDuring() { 1074 | //清空之前的自动居中延迟函数 1075 | clearTimeout(this.data.TIME_CUT_CENTER); 1076 | //清空之前的背景变化延迟函数 1077 | clearTimeout(this.data.TIME_BG); 1078 | //高亮背景 1079 | if (!this.data._flag_bright) { 1080 | this.setData({ 1081 | _flag_bright: true 1082 | }); 1083 | } 1084 | }, 1085 | //监听器 1086 | _watcher() { 1087 | Object.keys(this.data).forEach(v => { 1088 | this._observe(this.data, v, this.data.watch[v]); 1089 | }) 1090 | }, 1091 | _observe(obj, key, watchFun) { 1092 | var val = obj[key]; 1093 | Object.defineProperty(obj, key, { 1094 | configurable: true, 1095 | enumerable: true, 1096 | set:(value) => { 1097 | val = value; 1098 | watchFun && watchFun(val, this); 1099 | }, 1100 | get() { 1101 | if (val && '_img_top|img_left||width|height|min_width|max_width|min_height|max_height|export_scale|cut_top|cut_left|canvas_top|canvas_left|img_width|img_height|scale|angle|min_scale|max_scale'.indexOf(key)!=-1){ 1102 | let ret = parseFloat(parseFloat(val).toFixed(3)); 1103 | if (typeof val == "string" && val.indexOf("%") != -1){ 1104 | ret+='%'; 1105 | } 1106 | return ret; 1107 | } 1108 | return val; 1109 | } 1110 | }) 1111 | }, 1112 | _preventTouchMove() { 1113 | } 1114 | } 1115 | }) 1116 | -------------------------------------------------------------------------------- /mini-program/frontend/image-cropper/image-cropper.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /mini-program/frontend/image-cropper/image-cropper.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /mini-program/frontend/image-cropper/image-cropper.wxss: -------------------------------------------------------------------------------- 1 | .image-cropper{ 2 | background:rgba(14, 13, 13,.8); 3 | position: fixed; 4 | top:0; 5 | left:0; 6 | width:100vw; 7 | height:100vh; 8 | z-index: 1; 9 | } 10 | .main{ 11 | position: absolute; 12 | width:100vw; 13 | height:100vh; 14 | overflow: hidden; 15 | } 16 | .content{ 17 | z-index: 9; 18 | position: absolute; 19 | width:100vw; 20 | height:100vh; 21 | display: flex; 22 | flex-direction:column; 23 | pointer-events:none; 24 | } 25 | .bg_black{ 26 | background: rgba(0, 0, 0, 0.8)!important; 27 | } 28 | .bg_gray{ 29 | background: rgba(0, 0, 0, 0.45); 30 | transition-duration: .35s; 31 | } 32 | .content>.content_top{ 33 | pointer-events:none; 34 | } 35 | .content>.content_middle{ 36 | display: flex; 37 | height: 200px; 38 | width:100%; 39 | } 40 | .content_middle_middle{ 41 | width:200px; 42 | box-sizing:border-box; 43 | position: relative; 44 | transition-duration: .3s; 45 | } 46 | .content_middle_right{ 47 | flex: auto; 48 | } 49 | .content>.content_bottom{ 50 | flex: auto; 51 | } 52 | .image-cropper .img{ 53 | z-index: 2; 54 | top:0; 55 | left:0; 56 | position: absolute; 57 | border:none; 58 | width:100%; 59 | backface-visibility: hidden; 60 | transform-origin:center; 61 | } 62 | .image-cropper-canvas{ 63 | position: fixed; 64 | background: white; 65 | width:150px; 66 | height:150px; 67 | z-index: 10; 68 | top:-200%; 69 | pointer-events:none; 70 | } 71 | .border{ 72 | background: #3DB29E; 73 | pointer-events:auto; 74 | position:absolute; 75 | } 76 | .border-top-left{ 77 | left:-2.5px; 78 | top:-2.5px; 79 | height:2.5px; 80 | width:33rpx; 81 | } 82 | .border-top-right{ 83 | right:-2.5px; 84 | top:-2.5px; 85 | height:2.5px; 86 | width:33rpx; 87 | } 88 | .border-right-top{ 89 | top:-1px; 90 | width:2.5px; 91 | height:30rpx; 92 | right:-2.5px; 93 | } 94 | .border-right-bottom{ 95 | width:2.5px; 96 | height:30rpx; 97 | right:-2.5px; 98 | bottom:-1px; 99 | } 100 | .border-bottom-left{ 101 | height:2.5px; 102 | width:33rpx; 103 | bottom:-2.5px; 104 | left:-2.5px; 105 | } 106 | .border-bottom-right{ 107 | height:2.5px; 108 | width:33rpx; 109 | bottom:-2.5px; 110 | right:-2.5px; 111 | } 112 | .border-left-top{ 113 | top:-1px; 114 | width:2.5px; 115 | height:30rpx; 116 | left:-2.5px; 117 | } 118 | .border-left-bottom{ 119 | width:2.5px; 120 | height:30rpx; 121 | left:-2.5px; 122 | bottom:-1px; 123 | } -------------------------------------------------------------------------------- /mini-program/frontend/images/ac_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/ac_down.png -------------------------------------------------------------------------------- /mini-program/frontend/images/ac_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/ac_icon.png -------------------------------------------------------------------------------- /mini-program/frontend/images/ac_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/ac_up.png -------------------------------------------------------------------------------- /mini-program/frontend/images/air.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/air.png -------------------------------------------------------------------------------- /mini-program/frontend/images/bg_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/bg_image.png -------------------------------------------------------------------------------- /mini-program/frontend/images/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/camera.png -------------------------------------------------------------------------------- /mini-program/frontend/images/cameraIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/cameraIcon.png -------------------------------------------------------------------------------- /mini-program/frontend/images/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/card.png -------------------------------------------------------------------------------- /mini-program/frontend/images/damp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/damp.png -------------------------------------------------------------------------------- /mini-program/frontend/images/diet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/diet.png -------------------------------------------------------------------------------- /mini-program/frontend/images/drink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/drink.png -------------------------------------------------------------------------------- /mini-program/frontend/images/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/eye.png -------------------------------------------------------------------------------- /mini-program/frontend/images/food-and-restaurant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/food-and-restaurant.png -------------------------------------------------------------------------------- /mini-program/frontend/images/food.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/food.png -------------------------------------------------------------------------------- /mini-program/frontend/images/food_rec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/food_rec.png -------------------------------------------------------------------------------- /mini-program/frontend/images/ganmao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/ganmao.png -------------------------------------------------------------------------------- /mini-program/frontend/images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/help.png -------------------------------------------------------------------------------- /mini-program/frontend/images/icon_component_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/icon_component_1.png -------------------------------------------------------------------------------- /mini-program/frontend/images/icon_component_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/icon_component_2.png -------------------------------------------------------------------------------- /mini-program/frontend/images/icon_component_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/icon_component_3.png -------------------------------------------------------------------------------- /mini-program/frontend/images/icon_component_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/icon_component_4.png -------------------------------------------------------------------------------- /mini-program/frontend/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/info.png -------------------------------------------------------------------------------- /mini-program/frontend/images/info_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/info_card.png -------------------------------------------------------------------------------- /mini-program/frontend/images/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/like.png -------------------------------------------------------------------------------- /mini-program/frontend/images/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/next.png -------------------------------------------------------------------------------- /mini-program/frontend/images/risk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/risk.png -------------------------------------------------------------------------------- /mini-program/frontend/images/scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/scan.png -------------------------------------------------------------------------------- /mini-program/frontend/images/shop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/shop.png -------------------------------------------------------------------------------- /mini-program/frontend/images/shopp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/shopp.png -------------------------------------------------------------------------------- /mini-program/frontend/images/solar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/solar.png -------------------------------------------------------------------------------- /mini-program/frontend/images/solar_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/solar_text.png -------------------------------------------------------------------------------- /mini-program/frontend/images/spit_rec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/spit_rec.png -------------------------------------------------------------------------------- /mini-program/frontend/images/sym.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/sym.png -------------------------------------------------------------------------------- /mini-program/frontend/images/tongue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/tongue.png -------------------------------------------------------------------------------- /mini-program/frontend/images/tongue2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/tongue2.png -------------------------------------------------------------------------------- /mini-program/frontend/images/ziwai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charfole/HeyConstitution/d144bf769a94761712846eb197c9623ead46a8a9/mini-program/frontend/images/ziwai.png -------------------------------------------------------------------------------- /mini-program/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechatprogr", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "dependencies": {}, 7 | "devDependencies": {}, 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC" 14 | } 15 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/crop/crop.js: -------------------------------------------------------------------------------- 1 | // pages/crop/crop.js 2 | const app=getApp() 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | src: '', 10 | width: 250,//宽度 11 | height: 250,//高度 12 | uploadData:[], 13 | tags:null, 14 | name:null 15 | }, 16 | 17 | /** 18 | * 生命周期函数--监听页面加载 19 | */ 20 | onLoad: function (options) { 21 | console.log(options.data) 22 | //获取到image-cropper实例 23 | var that=this; 24 | that.data.uploadData.push(options.data); 25 | that.data.tags=that.data.uploadData.join(","); 26 | that.data.name=options.name 27 | this.cropper = this.selectComponent("#image-cropper"); 28 | //开始裁剪 29 | wx.chooseImage({ 30 | success(res) { 31 | const tempFilePaths = res.tempFilePaths 32 | //console.log(tempFilePaths); 33 | that.cropper.pushImg(tempFilePaths); 34 | app.globalData.imgSrc=tempFilePaths; 35 | 36 | } 37 | }) 38 | 39 | }, 40 | // cropperload(e) { 41 | // console.log("cropper初始化完成"); 42 | // }, 43 | loadimage(e) { 44 | console.log("图片加载完成", e.detail); 45 | 46 | //重置图片角度、缩放、位置 47 | this.cropper.imgReset(); 48 | }, 49 | submit() { 50 | var that=this; 51 | 52 | this.cropper.getImg((obj) => { 53 | console.log(obj) 54 | wx.showLoading({ 55 | title: '识别中,请稍等', 56 | mask: true 57 | }) 58 | console.log(that.data.tags); 59 | console.log(typeof (that.data.tags)); 60 | wx.uploadFile({ 61 | 62 | url: 'http://8.129.131.241:8777/', //仅为示例,非真实的接口地址 63 | filePath: obj.url, 64 | name: 'file', 65 | formData: 66 | { 67 | 'tags': that.data.tags 68 | }, 69 | timeout:12000, 70 | success(res) { 71 | 72 | 73 | console.log(res.data) 74 | //const resor =res; 75 | //const data=res.data; 76 | //console.log(data); 77 | 78 | //console.log(resor); 79 | wx.hideLoading(); 80 | app.globalData.options=res.data 81 | wx.switchTab({ 82 | 83 | //url: "../result/result?val=" + data + "&file=" + app.imgSrc 84 | url: "../result/result" 85 | }) 86 | 87 | 88 | 89 | }, 90 | fail(){ 91 | console.log("超时"); 92 | wx.hideLoading(); 93 | wx.showModal({ 94 | title: '连接错误', 95 | content: '网络超时,请稍后重试!', 96 | showCancel:false, 97 | complete(res) { 98 | wx.navigateBack(); 99 | } 100 | }) 101 | }, 102 | }) 103 | }); 104 | }, 105 | 106 | /** 107 | * 生命周期函数--监听页面初次渲染完成 108 | */ 109 | onReady: function () { 110 | 111 | }, 112 | 113 | /** 114 | * 生命周期函数--监听页面显示 115 | */ 116 | onShow: function () { 117 | 118 | }, 119 | 120 | /** 121 | * 生命周期函数--监听页面隐藏 122 | */ 123 | onHide: function () { 124 | 125 | }, 126 | 127 | /** 128 | * 生命周期函数--监听页面卸载 129 | */ 130 | onUnload: function () { 131 | 132 | }, 133 | 134 | /** 135 | * 页面相关事件处理函数--监听用户下拉动作 136 | */ 137 | onPullDownRefresh: function () { 138 | 139 | }, 140 | 141 | /** 142 | * 页面上拉触底事件的处理函数 143 | */ 144 | onReachBottom: function () { 145 | 146 | }, 147 | 148 | /** 149 | * 用户点击右上角分享 150 | */ 151 | onShareAppMessage: function () { 152 | 153 | } 154 | }) -------------------------------------------------------------------------------- /mini-program/frontend/pages/crop/crop.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "image-cropper": "/image-cropper/image-cropper" 4 | }, 5 | "navigationBarTitleText": "裁剪图片", 6 | "disableScroll": true 7 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/crop/crop.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 请选择舌头区域 4 | 5 | 6 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/crop/crop.wxss: -------------------------------------------------------------------------------- 1 | /* pages/crop/crop.wxss */ 2 | .hint{ 3 | z-index: 10; 4 | width: 100%; 5 | color: #fff; 6 | position: absolute; 7 | top: 200rpx; 8 | text-align: center; 9 | } 10 | .btn{ 11 | position: absolute; 12 | width:100%; 13 | bottom:200rpx; 14 | display: flex; 15 | flex-flow:wrap; 16 | z-index: 10; 17 | justify-content:space-around; 18 | } 19 | .btn-submit{ 20 | background-color:#3DB29E; 21 | color: white; 22 | border-radius: 10px; 23 | 24 | } 25 | .btn-click{ 26 | opacity: 0.5; 27 | transform:scale(0.92); 28 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/detail/detail.js: -------------------------------------------------------------------------------- 1 | // pages/result/result.js 2 | const app = getApp() 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | //图片存储链接 10 | val:0, 11 | resultUrl:null, 12 | display:'none', 13 | image:null, 14 | }, 15 | 16 | /** 17 | * 生命周期函数--监听页面加载 18 | */ 19 | onLoad: function (options) { 20 | options=app.globalData.options 21 | console.log(options) 22 | // const data = JSON.parse(options.data); 23 | const data = JSON.parse(options); 24 | //const data=options 25 | //console.log(options) 26 | this.setData({resultUrl:data.imgUrl, 27 | image:app.globalData.imgSrc 28 | }); 29 | if(data.message!="null") 30 | wx.showModal({ 31 | title: '提示', 32 | content:data.message, 33 | showCancel:false 34 | }) 35 | 36 | // this.setData({resultUrl:data.imgUrl, 37 | // display:'block'//展示蒙版 38 | // }); 39 | var obj={ 40 | body:data.body, 41 | year_month_day:data.year_month_day, 42 | time:data.time 43 | } 44 | const temp = wx.getStorageSync('log') || []; 45 | temp.unshift(obj); 46 | wx.setStorageSync('log', temp); 47 | 48 | 49 | 50 | }, 51 | 52 | /** 53 | * 生命周期函数--监听页面初次渲染完成 54 | */ 55 | onReady: function () { 56 | 57 | }, 58 | 59 | /** 60 | * 生命周期函数--监听页面显示 61 | */ 62 | onShow: function () { 63 | 64 | }, 65 | 66 | /** 67 | * 生命周期函数--监听页面隐藏 68 | */ 69 | onHide: function () { 70 | 71 | 72 | }, 73 | 74 | /** 75 | * 生命周期函数--监听页面卸载 76 | */ 77 | onUnload: function () { 78 | }, 79 | 80 | /** 81 | * 页面相关事件处理函数--监听用户下拉动作 82 | */ 83 | onPullDownRefresh: function () { 84 | 85 | }, 86 | 87 | /** 88 | * 页面上拉触底事件的处理函数 89 | */ 90 | onReachBottom: function () { 91 | 92 | }, 93 | 94 | 95 | /** 96 | * 用户点击右上角分享 97 | */ 98 | onShareAppMessage: function () { 99 | 100 | }, 101 | 102 | 103 | hideview: function() { 104 | this.setData({ 105 | display: "none" 106 | }) 107 | }, 108 | clickDrinks:function(){ 109 | wx.navigateTo({ 110 | url: '/pages/drinks/drinks', 111 | }) 112 | } 113 | }) 114 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/detail/detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/detail/detail.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 用户上传的照片: 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/detail/detail.wxss: -------------------------------------------------------------------------------- 1 | /* pages/result/result.wxss */ 2 | 3 | page{ 4 | background-color: rgb(247, 247, 247) 5 | } 6 | .upload_img{ 7 | position: absolute; 8 | top: 50rpx; 9 | left: 50rpx; 10 | color:rgba(000, 000, 000, 0.8) 11 | } 12 | .bodyimage{ 13 | height: 150rpx; 14 | width: 150rpx; 15 | margin: 0 auto; 16 | margin-bottom: 50rpx; 17 | } 18 | .bodyimage image{ 19 | width: 100%; 20 | height: 100%; 21 | } 22 | .resultImage{ 23 | height: 1430rpx; 24 | width: 750rpx; 25 | text-align: center; 26 | } 27 | .resultImage image{ 28 | height: 95%; 29 | width: 100%; 30 | } 31 | /* .clickDrink{ 32 | opacity: 0.8; 33 | position: absolute; 34 | top: 5rpx; 35 | right: 5rpx; 36 | width:230rpx; 37 | text-align: center; 38 | line-height: 60rpx; 39 | height: 60rpx; 40 | z-index: 5; 41 | border-style: solid; 42 | border: 1px; 43 | border-radius: 15px; 44 | background: #3DB29E; 45 | color: black; 46 | } 47 | 48 | .clickDrink image{ 49 | width: 30rpx; 50 | height: 30rpx; 51 | margin: auto; 52 | } 53 | .click{ 54 | transform:scale(0.92); 55 | opacity: 0.5 56 | } */ 57 | /* .bg { 58 | height: 1430rpx; 59 | width: 750rpx; 60 | display: none; 61 | position: absolute; 62 | top: 0%; 63 | left: 0%; 64 | background-color: black; 65 | z-index: 1001; 66 | -moz-opacity: 0.7; 67 | opacity: 0.70; 68 | filter: alpha(opacity=70); 69 | } 70 | .bg_image{ 71 | padding-top: 20%; 72 | height: 100%; 73 | align-content: center; 74 | text-align: center; 75 | width: 100%; 76 | margin: auto; 77 | z-index: 1002; 78 | 79 | } */ -------------------------------------------------------------------------------- /mini-program/frontend/pages/drinks/drinks.js: -------------------------------------------------------------------------------- 1 | // pages/drinks.js 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | drinks: { 9 | '平和质': [ 10 | { '名字': '百莲耳汤', '功效': '健脾养心安神', '成分': '莲子10克、百合10克、银耳10克', '状态': '热(推荐)', '热量': '500卡路里' }, 11 | { '名字': '红米粥', '功效': '健脾祛湿', '成分': '红豆10克、薏米30克、梗米20克', '状态': '热(推荐)', '热量': '500卡路里' }, 12 | { '名字': '胡萝卜山药汤', '功效': '健护脾胃,益气养阴', '成分': '鲜淮山1斤、猪尾骨1块、胡萝卜1根', '状态': '热(推荐)', '热量': '500卡路里' } 13 | ], 14 | '气虚质': [ 15 | { '名字': '花胶党参鸡汤', '功效': '健脾养胃,益气补血', '成分': '花胶干品20克、党参20克、生姜3片,鸡半只(2人份)', '状态': '热(推荐)', '热量': '500卡路里' }, 16 | { '名字': '参山莲枣汤', '功效': '健脾养胃,养心安神', '成分': '党参10克、山药10克、大枣10克、莲子10克', '状态': '热(推荐)', '热量': '500卡路里'}, 17 | { '名字': '猴头菇鸡汤汤', '功效': '健脾养胃,益气养阴', '成分': '猴头菇1包、鸡半只、红枣5-6颗、枸杞1-2把、人参3片、米酒半杯', '状态': '热(推荐)', '热量': '500卡路里'} 18 | ], 19 | '气郁质':[ 20 | { '名字': '佛手猪肝汤', '功效': '调和脾胃,疏肝解郁', '成分': '佛手片10克、鲜猪肝150克、麦片10克、盐、葱适量', '状态': '热(推荐)', '热量': '500卡路里' }, 21 | { '名字': '陈皮玫瑰汤', '功效': '健脾疏肝解郁', '成分': '玫瑰10克、陈皮10克', '状态': '热(推荐)', '热量': '500卡路里'}, 22 | { '名字': '百芎汤', '功效': '养阴安神,活血疏肝', '成分': '川芎10克、百合10克、龙眼肉10克', '状态': '热(推荐)', '热量': '500卡路里'} 23 | ], 24 | '湿热质': [ 25 | { '名字': '绿豆海带煲排骨汤', '功效': '清热解毒,行气利湿', '成分': '猪排骨400克、绿豆50克、鲜海带100克、生姜3~5片,陈皮1瓣', '状态': '热(推荐)', '热量': '500卡路里' }, 26 | { '名字': '胡萝卜茅根马蹄猪骨汤', '功效': '清热祛湿,生津止渴,利尿', '成分': '猪骨500克、茅根50克、马蹄6个、胡萝卜半个、蜜枣2粒', '状态': '热(推荐)', '热量': '500卡路里'}, 27 | { '名字': '地石汤', '功效': '祛湿化痰、健脾补肺', '成分': '生地10克、石斛10克', '状态': '热(推荐)', '热量': '500卡路里'} 28 | ], 29 | '痰湿质': [ 30 | { '名字': '冬瓜薏米猪骨汤', '功效': '健脾祛湿,利尿消肿', '成分': '猪骨500克、冬瓜700克、薏米100克、甜玉米1根、生姜1块', '状态': '热(推荐)', '热量': '500卡路里' }, 31 | { '名字': '地石汤', '功效': '祛湿化痰、健脾补肺', '成分': '生地10克、石斛10克', '状态': '热(推荐)', '热量': '500卡路里'}, 32 | { '名字': '杏仁薏米汤', '功效': '祛湿化痰、健脾补肺', '成分': '杏仁10克、薏米10克', '状态': '热(推荐)', '热量': '500卡路里'} 33 | ], 34 | '血瘀质': [ 35 | { '名字': '田七排骨鸡脚汤', '功效': '活血化瘀,消肿止痛', '成分': '鸡脚数只、排骨500克、田七20克、姜1片、苹果半只', '状态': '热(推荐)', '热量': '500卡路里' }, 36 | { '名字': '归母汤', '功效': '活血祛瘀,调经止痛', '成分': '当归10克、益母草10克、山楂10克', '状态': '热(推荐)', '热量': '500卡路里'}, 37 | { '名字': '桃红汤', '功效': '活血调经、润肠通便', '成分': '桃仁10克、红花10克、大枣10克', '状态': '热(推荐)', '热量': '500卡路里'} 38 | ], 39 | '阳虚质': [{ '名字': '参归姜枣汤', '功效': '清热解毒,利气行湿', '成分': '党参10克、当归10克、生姜6克、大枣10克', '状态': '热(推荐)', '热量': '500卡路里' }, 40 | { '名字': '巴戟炖猪肚汤', '功效': '强筋骨、安五脏、补中气、温肾阳', '成分': '巴戟50克、猪肚350克、姜10克、胡椒粒5克、调味料适量', '状态': '热(推荐)', '热量': '500卡路里'}, 41 | { '名字': '苁蓉汤', '功效': '温补肾阳、固精缩尿', '成分': '肉苁蓉10克、菟丝子10克、大枣10克', '状态': '热(推荐)', '热量': '500卡路里'} 42 | ], 43 | '阴虚质': [ 44 | { '名字': '杞冬参汤', '功效': '养阴益气,生津止渴', '成分': '枸杞10克、麦冬10克、西洋参10克', '状态': '热(推荐)', '热量': '500卡路里' }, 45 | { '名字': '麦冬淮山玉竹煲鸽汤', '功效': '养阴润肺、健脾和胃', '成分': '鸽子1只、淮山15克、玉竹15克、麦冬15克、姜1片', '状态': '热(推荐)', '热量': '500卡路里'}, 46 | { '名字': '杏仁汤', '功效': '养阴润肺,通肠润便', '成分': '杏仁10克、芝麻5克', '状态': '热(推荐)', '热量': '500卡路里'} 47 | ], 48 | }, 49 | body:null, 50 | name:null, 51 | use:null, 52 | form:null, 53 | tem:null, 54 | energy:null, 55 | showIndex:0, 56 | }, 57 | 58 | /** 59 | * 生命周期函数--监听页面加载 60 | */ 61 | onLoad: function (options) 62 | { 63 | const item=wx.getStorageSync('log') || [] 64 | if(item.length!=0){ 65 | const body = item[0].body 66 | this.setData({ 67 | body:body, 68 | name:this.data.drinks[body][0]['名字'], 69 | use: this.data.drinks[body][0]['功效'], 70 | form: this.data.drinks[body][0]['成分'], 71 | tem: this.data.drinks[body][0]['状态'], 72 | energy: this.data.drinks[body][0]['热量'] 73 | }) 74 | } 75 | else{ 76 | wx.showModal({ 77 | title: '提示', 78 | content: '检测到您还未诊断体质,请现在开始吧!', 79 | complete(res) { 80 | wx.navigateBack(); 81 | } 82 | }) 83 | } 84 | }, 85 | change: function (e) { 86 | if (e.currentTarget.dataset.index != this.data.showIndex) { 87 | this.setData({ 88 | showIndex: e.currentTarget.dataset.index 89 | }) 90 | } 91 | //console.log(this.data.showIndex) 92 | const body=this.data.body 93 | const index=this.data.showIndex 94 | //console.log(body) 95 | this.setData({ 96 | name: this.data.drinks[body][index]['名字'], 97 | use: this.data.drinks[body][index]['功效'], 98 | form: this.data.drinks[body][index]['成分'], 99 | tem: this.data.drinks[body][index]['状态'], 100 | energy: this.data.drinks[body][index]['热量'] 101 | }) 102 | }, 103 | /** 104 | * 生命周期函数--监听页面初次渲染完成 105 | */ 106 | onReady: function () { 107 | 108 | }, 109 | 110 | /** 111 | * 生命周期函数--监听页面显示 112 | */ 113 | onShow: function () { 114 | 115 | }, 116 | 117 | /** 118 | * 生命周期函数--监听页面隐藏 119 | */ 120 | onHide: function () { 121 | 122 | }, 123 | 124 | /** 125 | * 生命周期函数--监听页面卸载 126 | */ 127 | onUnload: function () { 128 | 129 | }, 130 | 131 | /** 132 | * 页面相关事件处理函数--监听用户下拉动作 133 | */ 134 | onPullDownRefresh: function () { 135 | 136 | }, 137 | 138 | /** 139 | * 页面上拉触底事件的处理函数 140 | */ 141 | onReachBottom: function () { 142 | 143 | }, 144 | 145 | /** 146 | * 用户点击右上角分享 147 | */ 148 | onShareAppMessage: function () { 149 | 150 | } 151 | }) -------------------------------------------------------------------------------- /mini-program/frontend/pages/drinks/drinks.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {}, 3 | "navigationBarTitleText": "药膳推荐" 4 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/drinks/drinks.wxml: -------------------------------------------------------------------------------- 1 | 2 | 根据您最近的诊断的体质:{{body}} 推荐 3 | 4 | 5 | 1 6 | 2 7 | 3 8 | 9 | 10 | 11 | {{name}} 12 | 13 | CUSTOMIZED 14 | 15 | HEALTH DRINKS 16 | 17 | 18 | 19 | 20 | |功效| {{use}} 21 | |成分| {{form}} 22 | |状态| {{tem}} 23 | |热量| {{energy}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/drinks/drinks.wxss: -------------------------------------------------------------------------------- 1 | /* pages/drinks.wxss */ 2 | 3 | 4 | .tips{ 5 | color: #b3b3b3; 6 | width: 70%; 7 | margin: auto; 8 | height: 50rpx; 9 | font-size: 30rpx; 10 | padding-top: 10rpx; 11 | } 12 | .drink_image{ 13 | padding-top: 2rpx; 14 | height: 600rpx; 15 | width: 95%; 16 | margin: auto; 17 | 18 | } 19 | .drink_image image{ 20 | width: 100%; 21 | height: 100%; 22 | margin: auto; 23 | } 24 | 25 | .drink_name{ 26 | padding-top: 40rpx; 27 | height: 180rpx; 28 | width: 70%; 29 | margin: auto; 30 | border-bottom: 1px; 31 | border-bottom-style: solid; 32 | border-bottom-color: #f4c57a; 33 | } 34 | 35 | .drink_name .name{ 36 | color: #3b8686; 37 | font-weight: bold; 38 | font-size: 48rpx; 39 | } 40 | 41 | .drink_name .name2{ 42 | color: #bbe8e6; 43 | font-size: 36rpx; 44 | } 45 | 46 | .drink_info{ 47 | padding-top: 50rpx; 48 | height: 700rpx; 49 | width: 70%; 50 | margin: auto; 51 | } 52 | 53 | .drink_info .info{ 54 | font-size: 30rpx; 55 | color: #b3b3b3; 56 | margin-bottom: 70rpx; 57 | height: 60rpx; 58 | align-content: center; 59 | } 60 | 61 | .lable{ 62 | padding-top: 20rpx; 63 | margin: auto; 64 | width: 70% 65 | } 66 | .lable_item{ 67 | line-height: 50rpx; 68 | text-align:center; 69 | display: inline-block; 70 | width: 70rpx; 71 | height: 50rpx; 72 | border: 1px solid #f0f0f0; 73 | color: #b3b3b3; 74 | } 75 | .lable_item_selected{ 76 | background-color: #3b8686; 77 | color:black; 78 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/help/help.js: -------------------------------------------------------------------------------- 1 | // pages/help/help.js 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | showIndex:1, 9 | }, 10 | acTap: function (e) { 11 | if (e.currentTarget.dataset.index != this.data.showIndex) { 12 | this.setData({ 13 | showIndex: e.currentTarget.dataset.index 14 | }) 15 | } else { 16 | this.setData({ 17 | showIndex:0 18 | }) 19 | } 20 | }, 21 | /** 22 | * 生命周期函数--监听页面加载 23 | */ 24 | onLoad: function (options) { 25 | this.setData({showIndex:1}) 26 | }, 27 | 28 | /** 29 | * 生命周期函数--监听页面初次渲染完成 30 | */ 31 | onReady: function () { 32 | 33 | }, 34 | 35 | /** 36 | * 生命周期函数--监听页面显示 37 | */ 38 | onShow: function () { 39 | 40 | }, 41 | 42 | /** 43 | * 生命周期函数--监听页面隐藏 44 | */ 45 | onHide: function () { 46 | 47 | }, 48 | 49 | /** 50 | * 生命周期函数--监听页面卸载 51 | */ 52 | onUnload: function () { 53 | 54 | }, 55 | 56 | /** 57 | * 页面相关事件处理函数--监听用户下拉动作 58 | */ 59 | onPullDownRefresh: function () { 60 | 61 | }, 62 | 63 | /** 64 | * 页面上拉触底事件的处理函数 65 | */ 66 | onReachBottom: function () { 67 | 68 | }, 69 | 70 | /** 71 | * 用户点击右上角分享 72 | */ 73 | onShareAppMessage: function () { 74 | 75 | }, 76 | 77 | 78 | name: "tuiCollapse", 79 | props: { 80 | //collapse背景颜色 81 | bgColor: { 82 | type: String, 83 | default: 'none' 84 | }, 85 | //collapse-head 背景颜色 86 | hdBgColor: { 87 | type: String, 88 | default: '#fff' 89 | }, 90 | //collapse-body 背景颜色 91 | bdBgColor: { 92 | type: String, 93 | default: 'none' 94 | }, 95 | //collapse-body实际高度 open时使用 96 | height: { 97 | type: String, 98 | default: 'auto' 99 | }, 100 | //close时translateY ,当bd高度固定时,建议值为0 101 | translateY: { 102 | type: String, 103 | default: '-50%' 104 | }, 105 | //索引 106 | index: { 107 | type: Number, 108 | default: 0 109 | }, 110 | //当前索引,index==current时展开 111 | current: { 112 | type: Number, 113 | default: -1 114 | }, 115 | // 是否禁用 116 | disabled: { 117 | type: [Boolean, String], 118 | default: false 119 | }, 120 | //是否带箭头 121 | arrow: { 122 | type: [Boolean, String], 123 | default: true 124 | }, 125 | //箭头颜色 126 | arrowColor: { 127 | type: String, 128 | default: "#333" 129 | } 130 | }, 131 | watch: { 132 | current() { 133 | this.updateCurrentChange() 134 | } 135 | }, 136 | created() { 137 | this.updateCurrentChange() 138 | }, 139 | data() { 140 | return { 141 | isOpen: false 142 | }; 143 | }, 144 | methods: { 145 | updateCurrentChange() { 146 | this.isOpen = this.index == this.current 147 | }, 148 | handleClick() { 149 | if (this.disabled) return; 150 | this.$emit("click", { 151 | index: Number(this.index) 152 | }) 153 | } 154 | } 155 | 156 | 157 | }) 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/help/help.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {}, 3 | "navigationBarTitleText": "说明帮助" 4 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/help/help.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 注意事项 7 | 8 | 9 | 请确保光照条件正常。光线的强弱与色调,对颜色的影响极大。应以白天充足而柔和的自然光线为佳,如在夜间或暗处,用日光灯为好。\n\n不宜在饭后进行舌诊。饮食及药物可使舌象发生变化,过冷过热的饮食及刺激性食物可使舌色发生改变。过食肥甘之品及服大量镇静剂,可使舌苔厚腻。\n\n上传图片时尽量裁剪到舌头区域,否则可能会造成无法识别。 10 | 11 | 12 | 13 | 舌诊的来源 14 | 15 | 16 | 舌诊是观察舌头的色泽、形态的变化来辅助诊断及鉴别的一个简单有效的方法。\n\n舌诊主要诊察舌质和舌苔的形态、色泽、润燥等,以此判断疾病的性质、病势的浅深、气血的盛衰、津液的盈亏及脏腑的虚实等。 17 | 18 | 19 | 体质划分 20 | 21 | 22 | 根据传统中医理论,人体大致可以分为九大体质:湿热质、气虚质、血瘀质、特禀质、痰湿质、阴虚质、阳虚质、平和质、气郁质。 23 | 24 | 25 | 舌诊的准确性说明 26 | 27 | 28 | 由于算法对光线、拍摄角度、图片大小等因素较为敏感,因此上述因素可能会对结果产生偏差! 29 | 30 | 31 | 查看拍照上传样例 32 | 33 | 34 | 35 | 36 | 37 | 拍照上传样例: 38 | 39 | 40 | 41 | (图片来自网络,如有侵权请联系删除) 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 关于我们 53 | 54 | 55 | 本小程序是由草木多闻团队设计呈现的,团队致力于高效的诊断方案和药膳汤品推荐。 56 | 57 | 58 | 59 | 60 | 62 | 67 | 68 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/help/help.wxss: -------------------------------------------------------------------------------- 1 | /* pages/help/help.wxss */ 2 | 3 | page{ 4 | margin-top: 80rpx; 5 | } 6 | 7 | .accordion 8 | { 9 | height: 700rpx; 10 | } 11 | .ac_item{ 12 | margin: 15rpx 10rpx; 13 | height: 90rpx; 14 | line-height: 90rpx; 15 | position: relative; 16 | border-bottom-width: 1px; 17 | 18 | border-bottom-color: rgba(61,178,158,0.1); 19 | border-bottom-style: solid; 20 | padding-bottom: 10rpx; 21 | 22 | } 23 | .ac_text{ 24 | padding-left: 5rpx; 25 | height: 90rpx; 26 | float: left; 27 | font-size: 15px; 28 | 29 | } 30 | 31 | .ac_icon{ 32 | padding-right: 5rpx; 33 | 34 | float: right; 35 | height: 60rpx; 36 | width: 60rpx; 37 | } 38 | .ac_icon image{ 39 | width: 30rpx; 40 | height: 30rpx; 41 | margin: 0 auto; 42 | align-content: center; 43 | } 44 | 45 | .ac_detail{ 46 | margin: 0 25rpx; 47 | margin-bottom: 10rpx; 48 | 49 | } 50 | .ac_detail text{ 51 | font-size: 14px; 52 | color:rgba(150,151,153); 53 | } 54 | .left{ 55 | float: left; 56 | margin-left:10rpx; 57 | } 58 | 59 | 60 | 61 | 62 | 63 | 64 | /* .Q{ 65 | margin-top: 25rpx; 66 | margin-left:5%; 67 | font-size: 15px; 68 | margin-bottom: 3px; 69 | width: 85% 70 | } 71 | .A{ 72 | margin-left:5%; 73 | font-size: 13px; 74 | margin-bottom: 10px; 75 | color: rgb(130, 197, 189); 76 | width: 85% 77 | 78 | } 79 | */ 80 | .exp 81 | { 82 | margin-top: 30px; 83 | 84 | display: flex; 85 | flex-direction: row; 86 | margin-left: 20px; 87 | } 88 | .text{ 89 | font-size: 15px; 90 | color:rgba(150,151,153); 91 | width: 300rpx; 92 | } 93 | .text_{ 94 | color:rgba(150,151,153); 95 | font-size: 13px; 96 | width: 300rpx; 97 | margin-top: 10rpx; 98 | } 99 | .image{ 100 | margin-left: 50rpx; 101 | width: 250rpx; 102 | height: 250rpx; 103 | } 104 | .image image{ 105 | width: 100%; 106 | height:100%; 107 | } 108 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/index/index.js: -------------------------------------------------------------------------------- 1 | var app = getApp() 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | diet_tips:"朝朝盐水,晚晚蜜汤。\n菊黄蟹肥秋正浓。\n秋之燥,菊花茶滋阴润燥。", 9 | sprit_tips:"露寒万物,汤暖你心。\n露寒霜重,心中暖意更重。", 10 | list: [{ 11 | "text": "首页", 12 | dot: true 13 | }, 14 | { 15 | "text": "设置", 16 | badge: 'New' 17 | }], 18 | scanitem:['','',''] 19 | }, 20 | clickHelp: function(){ 21 | wx.navigateTo({ 22 | url: '../help/help', 23 | }) 24 | }, 25 | /** 26 | * 生命周期函数--监听页面加载 27 | */ 28 | onLoad: function (options) { 29 | 30 | }, 31 | 32 | /** 33 | * 生命周期函数--监听页面初次渲染完成 34 | */ 35 | onReady: function () { 36 | 37 | }, 38 | 39 | /** 40 | * 生命周期函数--监听页面显示 41 | */ 42 | onShow: function () { 43 | 44 | }, 45 | 46 | /** 47 | * 生命周期函数--监听页面隐藏 48 | */ 49 | onHide: function () { 50 | 51 | }, 52 | 53 | /** 54 | * 生命周期函数--监听页面卸载 55 | */ 56 | onUnload: function () { 57 | 58 | }, 59 | 60 | /** 61 | * 页面相关事件处理函数--监听用户下拉动作 62 | */ 63 | onPullDownRefresh: function () { 64 | 65 | }, 66 | 67 | /** 68 | * 页面上拉触底事件的处理函数 69 | */ 70 | onReachBottom: function () { 71 | 72 | }, 73 | 74 | /** 75 | * 用户点击右上角分享 76 | */ 77 | onShareAppMessage: function () { 78 | 79 | return { 80 | 81 | title: '草木多闻', 82 | desc: '快来体验舌诊识别体质吧!', 83 | path: '/pages/index/index' 84 | 85 | } 86 | 87 | }, 88 | 89 | 90 | clickToTake: function() 91 | { 92 | wx.navigateTo({ 93 | url: '/pages/optional/optional', 94 | }) 95 | }, 96 | clickLogs: function () { 97 | wx.navigateTo({ 98 | url: '/pages/logs/logs', 99 | }) 100 | }, 101 | clickDrinks: function () { 102 | wx.navigateTo({ 103 | url: '/pages/drinks/drinks', 104 | }) 105 | } 106 | }) 107 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | 4 | 5 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 29 | 41 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 临近节气 65 | 66 | 寒露 67 | Cold Dew 68 | 八月廿二 69 | 秋日的凉冷归于寒露,秋日的温暖归于暖汤。 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 今日健康指数 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 90% 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | {{diet_tips}} 98 | 99 | 100 | 101 | {{sprit_tips}} 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/logs/logs.js: -------------------------------------------------------------------------------- 1 | //logs.js 2 | const util = require('../../utils/util.js') 3 | Page({ 4 | data: { 5 | log: [], 6 | hasLog:false, 7 | }, 8 | // onLoad: function () { 9 | // this.setData({ 10 | // logs: (wx.getStorageSync('logs') || []).map(log => { 11 | // return util.formatTime(new Date(log)) 12 | // }) 13 | // }) 14 | // } 15 | onLoad: function () { 16 | console.log(wx.getStorageSync('log')) 17 | this.setData({ 18 | log: wx.getStorageSync('log') || [] 19 | }) 20 | if(this.data.log.length!=0) 21 | { 22 | this.setData({ 23 | hasLog:true 24 | }) 25 | } 26 | 27 | }, 28 | 29 | clearStorage:function() 30 | { 31 | var that=this; 32 | wx.showModal({ 33 | title: '清空所有记录', 34 | content: '您确定要清空所有记录吗?', 35 | success(res){ 36 | if(res.confirm) 37 | wx.clearStorageSync(); 38 | that.setData({ 39 | log: wx.getStorageSync('log') || [] 40 | }) 41 | } 42 | }) 43 | } 44 | }) 45 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/logs/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "体质记录", 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/logs/logs.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{item.year_month_day}} 4 | 5 | 6 | {{item.time}} 诊断为{{item.body}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 清空所有记录 14 | 15 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/logs/logs.wxss: -------------------------------------------------------------------------------- 1 | 2 | page{ 3 | 4 | --black: #333333; 5 | --cyan: #1cbbb4; 6 | --ghostWhite: #f1f1f1; 7 | --white: #ffffff; 8 | 9 | 10 | font-size: 28rpx; 11 | color: var(--black); 12 | font-family: Helvetica Neue, Helvetica, sans-serif; 13 | } 14 | 15 | /* ================== 16 | 时间轴 17 | ==================== */ 18 | 19 | .cu-timeline { 20 | display: block; 21 | background-color: var(--white); 22 | } 23 | 24 | .cu-timeline .cu-time { 25 | width: 180rpx; 26 | text-align: center; 27 | padding: 20rpx 0; 28 | font-size: 26rpx; 29 | color: #888; 30 | display: block; 31 | } 32 | 33 | .cu-timeline>.cu-item { 34 | padding: 30rpx 30rpx 30rpx 120rpx; 35 | position: relative; 36 | display: block; 37 | z-index: 0; 38 | } 39 | 40 | .cu-timeline>.cu-item:not([class*="text-"]) { 41 | color: #ccc; 42 | } 43 | 44 | .cu-timeline>.cu-item::after { 45 | content: ""; 46 | display: block; 47 | position: absolute; 48 | width: 1rpx; 49 | background-color: #ddd; 50 | left: 60rpx; 51 | height: 100%; 52 | top: 0; 53 | z-index: 8; 54 | } 55 | 56 | .cu-timeline>.cu-item::before { 57 | font-family: "cuIcon"; 58 | display: block; 59 | position: absolute; 60 | top: 36rpx; 61 | z-index: 9; 62 | background-color: var(--white); 63 | width: 50rpx; 64 | height: 50rpx; 65 | text-align: center; 66 | border: none; 67 | line-height: 50rpx; 68 | left: 36rpx; 69 | } 70 | 71 | .cu-timeline>.cu-item:not([class*="cuIcon-"])::before { 72 | content: "\e763"; 73 | } 74 | 75 | .cu-timeline>.cu-item[class*="cuIcon-"]::before { 76 | background-color: var(--white); 77 | width: 50rpx; 78 | height: 50rpx; 79 | text-align: center; 80 | border: none; 81 | line-height: 50rpx; 82 | left: 36rpx; 83 | } 84 | 85 | .cu-timeline>.cu-item>.content { 86 | padding: 30rpx; 87 | border-radius: 6rpx; 88 | display: block; 89 | line-height: 1.6; 90 | } 91 | 92 | .cu-timeline>.cu-item>.content:not([class*="bg-"]) { 93 | background-color: var(--ghostWhite); 94 | color: var(--black); 95 | } 96 | 97 | .cu-timeline>.cu-item>.content+.content { 98 | margin-top: 20rpx; 99 | } 100 | 101 | .text-cyan{ 102 | color: var(--cyan); 103 | } 104 | 105 | .clear{ 106 | width: 100%; 107 | bottom: 10px; 108 | border-top-style:solid; 109 | border-top-width: 1px; 110 | border-top-color: rgba(61,178,158,0.2); 111 | margin: 20rpx; 112 | text-align: center 113 | } 114 | .clear_btn{ 115 | width: 40%; 116 | padding-top: 10px; 117 | color:rgba(150,151,153,0.8); 118 | font-size: 28rpx; 119 | margin: auto; 120 | text-align: center 121 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/optional/optional.js: -------------------------------------------------------------------------------- 1 | // pages/optional/optional.js 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | list: [ 9 | { name: '乏力', checked: false }, 10 | { name: '口渴', checked: false }, 11 | { name: '痰多', checked: false }, 12 | { name: '自汗', checked: false }, 13 | { name: '心烦', checked: false }, 14 | { name: '失眠', checked: false }, 15 | { name: '口苦', checked: false }, 16 | { name: '易长痘痘', checked: false }, 17 | { name: '身体困重', checked: false }, 18 | { name: '耐受寒热', checked: false }, 19 | { name: '不易疲劳', checked: false }, 20 | { name: '自觉发热', checked: false }, 21 | { name: '多愁善感', checked: false }, 22 | { name: '口腔溃疡', checked: false }, 23 | { name: '头胀胸闷', checked: false }, 24 | { name: '面色晦暗', checked: false }, 25 | { name: '胸胁疼痛', checked: false }, 26 | { name: '少气懒言', checked: false }, 27 | { name: '容易生气', checked: false }, 28 | { name: '容易感冒', checked: false }, 29 | { name: '畏寒肢冷', checked: false }, 30 | { name: '嗳气叹气', checked: false }, 31 | { name: '大便稀溏', checked: false }, 32 | { name: '消化不良', checked: false }, 33 | { name: '关节疼痛', checked: false }, 34 | { name: '皮肤干燥', checked: false }, 35 | { name: '皮肤粗糙有瘀斑', checked: false }, 36 | { name: '月经血块', checked: false }, 37 | { name: '身体水肿', checked: false }, 38 | 39 | 40 | 41 | ], 42 | max_selected: 4, 43 | cur_selected: 0, 44 | arr_selected: [], 45 | name:null 46 | }, 47 | 48 | 49 | 50 | 51 | lable_click: function (e) { 52 | var that = this; 53 | console.log(e.currentTarget.dataset); 54 | var index = e.currentTarget.dataset.index; 55 | var checked = e.currentTarget.dataset.checked; 56 | var name = e.currentTarget.dataset.name; 57 | //判断是否达到可选上限 58 | console.log(checked) 59 | if (!checked) { 60 | if (that.data.cur_selected >= that.data.max_selected) { 61 | //弹出模态框 62 | wx.showModal({ 63 | content: '为了使结果更准确,最多选择'+that.data.max_selected+'项主要症状', 64 | showCancel: false 65 | }) 66 | return; 67 | } 68 | that.data.cur_selected++; 69 | var temp = "list[" + index + "].checked"; 70 | that.setData({ [temp]: !checked }); 71 | that.data.arr_selected.push(name); 72 | console.log("插入后" + that.data.arr_selected) 73 | } 74 | //取消选中 75 | else { 76 | var temp = "list[" + index + "].checked"; 77 | that.setData({ [temp]: !checked }) 78 | for (var i in that.data.arr_selected) 79 | if (that.data.arr_selected[i] == name) 80 | that.data.arr_selected.splice(i, 1); 81 | that.data.cur_selected--; 82 | console.log("取消后" + that.data.arr_selected); 83 | } 84 | 85 | 86 | }, 87 | 88 | submit:function(){ 89 | var that=this; 90 | wx.redirectTo({ 91 | url: "../crop/crop?data=" + that.data.arr_selected, 92 | }) 93 | }, 94 | 95 | /** 96 | * 生命周期函数--监听页面加载 97 | */ 98 | onLoad: function (options) { 99 | 100 | }, 101 | 102 | checkbox_group_change:function(e){ 103 | console.log(e.detail.value) 104 | 105 | }, 106 | /** 107 | * 生命周期函数--监听页面初次渲染完成 108 | */ 109 | onReady: function () { 110 | 111 | }, 112 | 113 | /** 114 | * 生命周期函数--监听页面显示 115 | */ 116 | onShow: function () { 117 | 118 | }, 119 | 120 | /** 121 | * 生命周期函数--监听页面隐藏 122 | */ 123 | onHide: function () { 124 | 125 | }, 126 | 127 | /** 128 | * 生命周期函数--监听页面卸载 129 | */ 130 | onUnload: function () { 131 | 132 | }, 133 | 134 | /** 135 | * 页面相关事件处理函数--监听用户下拉动作 136 | */ 137 | onPullDownRefresh: function () { 138 | 139 | }, 140 | 141 | /** 142 | * 页面上拉触底事件的处理函数 143 | */ 144 | onReachBottom: function () { 145 | 146 | }, 147 | 148 | /** 149 | * 用户点击右上角分享 150 | */ 151 | onShareAppMessage: function () { 152 | 153 | }, 154 | }) -------------------------------------------------------------------------------- /mini-program/frontend/pages/optional/optional.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/optional/optional.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 主要症状 5 | (请在舌诊前选择您的主要症状,如没有可不选) 6 | 7 | 8 | 9 | {{item.name}} 10 | 11 | 12 | 13 | 14 | 15 | 下一步 16 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/optional/optional.wxss: -------------------------------------------------------------------------------- 1 | /* pages/optional/optional.wxss */ 2 | 3 | page{ 4 | margin: 0; 5 | padding:0; 6 | } 7 | 8 | .lable_header{ width: 100%; background-color: #fff; padding: 50rpx 30rpx 40rpx; box-sizing: border-box; 9 | } 10 | .lable_info{ width: 100%; overflow: hidden; } 11 | .lable_info .title{ font-size: 32rpx;} 12 | .lable_info .tip{ color: #b2b2b2; font-size: 26rpx; margin-top: 25rpx; } 13 | 14 | .lable_list{ 15 | padding: 10rpx 25rpx; 16 | width: 100%; 17 | height: 750rpx; 18 | } 19 | 20 | .lable{ 21 | width: auto; 22 | padding: 0 20rpx; 23 | display: inline-block; 24 | text-align: center; 25 | height: 70rpx; 26 | line-height: 70rpx; 27 | border: 1px solid #f0f0f0; 28 | border-radius: 10rpx; 29 | font-size: 28rpx; color: #808080; 30 | margin: 0 23rpx 23rpx 0; 31 | } 32 | .lable_selected{ 33 | color: #3DB29E; 34 | border-color: #3DB29E; 35 | } 36 | 37 | 38 | .lable_button{ 39 | position:fixed; 40 | bottom:10rpx; 41 | display:flex; 42 | text-align: center; 43 | justify-content:center; 44 | width: 100%; 45 | } 46 | .lable_submit{ 47 | border-radius: 149px; 48 | background-color: rgba(114,155,137,0.5); 49 | box-shadow: 5px 5px 10px #8f8f8f, 50 | -5px -5px 10px #ffffff; 51 | height: 135rpx; 52 | width: 135rpx; 53 | text-align: center; 54 | justify-content:center; 55 | line-height: 135rpx; 56 | font-size: 34rpx; color: white; 57 | } 58 | 59 | .lable_submit:hover{ 60 | transform:scale(0.92); 61 | opacity: 0.5 62 | } 63 | 64 | 65 | 66 | .putname{ 67 | margin-left: 25rpx; 68 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/result/result.js: -------------------------------------------------------------------------------- 1 | // pages/result/result.js 2 | const app = getApp() 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | //图片存储链接 10 | bodyIntroduce:"人体阳气化生不足,温煦作用下降生里寒。", 11 | userInfo: {}, 12 | hasUserInfo: false, 13 | canIUse: wx.canIUse('button.open-type.getUserInfo'), 14 | canIUseGetUserProfile: false, 15 | canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName'), // 如需尝试获取用户信息可改为false 16 | }, 17 | 18 | /** 19 | * 生命周期函数--监听页面加载 20 | */ 21 | onLoad: function (options) { 22 | // const data = JSON.parse(options.data); 23 | // console.log(data); 24 | // //console.log(options) 25 | // //this.setData({image:options.file}); 26 | // if(data.message!="null") 27 | // wx.showModal({ 28 | // title: '提示', 29 | // content:data.message, 30 | // complete(res) { 31 | // wx.navigateBack(); 32 | // } 33 | // }) 34 | 35 | // this.setData({resultUrl:data.imgUrl, 36 | // display:'block'//展示蒙版 37 | // }); 38 | // var obj={ 39 | // body:data.body, 40 | // year_month_day:data.year_month_day, 41 | // time:data.time 42 | // } 43 | // const temp = wx.getStorageSync('log') || []; 44 | // temp.unshift(obj); 45 | // wx.setStorageSync('log', temp); 46 | 47 | 48 | //------------------------------------------------! 49 | if (wx.getUserProfile) { 50 | this.setData({ 51 | canIUseGetUserProfile: true 52 | }) 53 | } 54 | }, 55 | getUserProfile(e) { 56 | // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗 57 | wx.getUserProfile({ 58 | desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写 59 | success: (res) => { 60 | console.log(res) 61 | this.setData({ 62 | userInfo: res.userInfo, 63 | hasUserInfo: true 64 | }) 65 | } 66 | }) 67 | 68 | console.log(this.data.userInfo) 69 | 70 | }, 71 | 72 | /** 73 | * 生命周期函数--监听页面初次渲染完成 74 | */ 75 | onReady: function () { 76 | 77 | }, 78 | 79 | /** 80 | * 生命周期函数--监听页面显示 81 | */ 82 | onShow: function () { 83 | 84 | }, 85 | 86 | /** 87 | * 生命周期函数--监听页面隐藏 88 | */ 89 | onHide: function () { 90 | 91 | 92 | }, 93 | 94 | /** 95 | * 生命周期函数--监听页面卸载 96 | */ 97 | onUnload: function () { 98 | }, 99 | 100 | /** 101 | * 页面相关事件处理函数--监听用户下拉动作 102 | */ 103 | onPullDownRefresh: function () { 104 | 105 | }, 106 | 107 | /** 108 | * 页面上拉触底事件的处理函数 109 | */ 110 | onReachBottom: function () { 111 | 112 | }, 113 | 114 | 115 | /** 116 | * 用户点击右上角分享 117 | */ 118 | onShareAppMessage: function () { 119 | 120 | }, 121 | 122 | 123 | hideview: function() { 124 | this.setData({ 125 | display: "none" 126 | }) 127 | }, 128 | clickDrinks:function(){ 129 | wx.navigateTo({ 130 | url: '/pages/drinks/drinks', 131 | }) 132 | }, 133 | clickDetail:function(){ 134 | wx.navigateTo({ 135 | url: '/pages/detail/detail', 136 | }) 137 | } 138 | }) 139 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/result/result.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {}, 3 | "navigationBarTitleText": "舌诊结果" 4 | } -------------------------------------------------------------------------------- /mini-program/frontend/pages/result/result.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 14 | 17 | 26 | 27 | 28 | 29 | 诊断结果 30 | DIAGNOSTIC ANALYSIS 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 点击获取用户信息 46 | 47 | 48 | 49 | 50 | {{userInfo.nickName}} 51 | 52 | 阳虚质 53 | {{bodyIntroduce}} 54 | 2020/10/03 55 | 56 | 57 | 58 | 更多分析结果 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 70 | -------------------------------------------------------------------------------- /mini-program/frontend/pages/result/result.wxss: -------------------------------------------------------------------------------- 1 | /* pages/result/result.wxss */ 2 | 3 | /* page{ 4 | background-color: rgb(247, 247, 247) 5 | } */ 6 | /* .bodyimage{ 7 | height: 150rpx; 8 | width: 150rpx; 9 | margin: 0 auto; 10 | margin-bottom: 50rpx; 11 | } 12 | .bodyimage image{ 13 | width: 100%; 14 | height: 100%; 15 | } */ 16 | /* .resultImage{ 17 | height: 1430rpx; 18 | width: 750rpx; 19 | text-align: center; 20 | } 21 | .resultImage image{ 22 | height: 95%; 23 | width: 100%; 24 | } 25 | .clickDrink{ 26 | opacity: 0.8; 27 | position: absolute; 28 | top: 5rpx; 29 | right: 5rpx; 30 | width:230rpx; 31 | text-align: center; 32 | line-height: 60rpx; 33 | height: 60rpx; 34 | z-index: 5; 35 | border-style: solid; 36 | border: 1px; 37 | border-radius: 15px; 38 | background: #3DB29E; 39 | color: black; 40 | } 41 | 42 | .clickDrink image{ 43 | width: 30rpx; 44 | height: 30rpx; 45 | margin: auto; 46 | } 47 | .click{ 48 | transform:scale(0.92); 49 | opacity: 0.5 50 | } 51 | .bg { 52 | height: 1430rpx; 53 | width: 750rpx; 54 | display: none; 55 | position: absolute; 56 | top: 0%; 57 | left: 0%; 58 | background-color: black; 59 | z-index: 1001; 60 | -moz-opacity: 0.7; 61 | opacity: 0.70; 62 | filter: alpha(opacity=70); 63 | } 64 | .bg_image{ 65 | padding-top: 20%; 66 | height: 100%; 67 | align-content: center; 68 | text-align: center; 69 | width: 100%; 70 | margin: auto; 71 | z-index: 1002; 72 | 73 | } */ 74 | 75 | .header{ 76 | background-color: #729b89; 77 | height: 300rpx; 78 | } 79 | 80 | .header_textCN{ 81 | text-align: center; 82 | font-size: 38rpx; 83 | padding-top: 80rpx; 84 | padding-bottom: 10rpx; 85 | letter-spacing:8rpx; 86 | } 87 | 88 | .header_textEN{ 89 | color: #e8cc9c; 90 | text-align: center; 91 | font-size: 14rpx; 92 | } 93 | 94 | .card{ 95 | 96 | background-image: url('data:image/png;base64,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'); 97 | background-repeat:no-repeat; 98 | background-size:100% 100%; 99 | -moz-background-size:100% 100%; 100 | margin: auto; 101 | position: relative; 102 | top: -150rpx; 103 | height: 450rpx; 104 | width: 90%; 105 | } 106 | 107 | .card_container{ 108 | height: 260rpx; 109 | } 110 | 111 | .card .avatar{ 112 | position: absolute; 113 | left: 40rpx; 114 | top: 40rpx; 115 | opacity: 0.8; 116 | } 117 | .userinfo-avatar { 118 | overflow: hidden; 119 | width: 128rpx; 120 | height: 128rpx; 121 | margin: 20rpx; 122 | border-radius: 50%; 123 | } 124 | .hasNotUserInfo{ 125 | position: absolute; 126 | left: 80rpx; 127 | top: 100rpx; 128 | width: 300rpx; 129 | height: 100rpx; 130 | background-color:#729b89; 131 | border-radius: 999px; 132 | color: white; 133 | text-align: center; 134 | line-height: 100rpx; 135 | opacity: 0.8; 136 | } 137 | .card .nick{ 138 | position: absolute; 139 | left: 80rpx; 140 | top: 250rpx; 141 | opacity: 0.8; 142 | } 143 | 144 | .card .body{ 145 | position: absolute; 146 | right: 80rpx; 147 | top: 80rpx; 148 | font-weight: bold; 149 | font-size: 40rpx; 150 | letter-spacing: 5rpx; 151 | opacity: 0.8; 152 | } 153 | 154 | .card .body_info{ 155 | position: absolute; 156 | right: 40rpx; 157 | top: 150rpx; 158 | font-size: 24rpx; 159 | letter-spacing: 5rpx; 160 | opacity: 0.8; 161 | width: 200rpx; 162 | text-align: left; 163 | } 164 | 165 | .card .time{ 166 | position: absolute; 167 | left: 80rpx; 168 | bottom:50rpx; 169 | font-size: 30rpx; 170 | color: #e8cc9c; 171 | } 172 | 173 | .more{ 174 | color: #e8cc9c; 175 | font-size: 30rpx; 176 | margin-left: 15%; 177 | height: 50rpx; 178 | line-height: 50rpx; 179 | letter-spacing: 5rpx; 180 | margin-top: 40rpx; 181 | } 182 | 183 | .button_group{ 184 | margin-top: 60rpx; 185 | } 186 | 187 | .button_line{ 188 | height: 325rpx; 189 | text-align: center; 190 | } 191 | 192 | .button{ 193 | width:325rpx; 194 | height: 325rpx; 195 | display: inline-block; 196 | } 197 | 198 | .button image{ 199 | width:325rpx; 200 | height: 325rpx; 201 | } 202 | 203 | .click 204 | { 205 | transform:scale(0.92); 206 | opacity: 0.5 207 | } -------------------------------------------------------------------------------- /mini-program/frontend/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": false, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "coverView": true, 13 | "autoAudits": false, 14 | "showShadowRootInWxmlPanel": true, 15 | "scopeDataCheck": false, 16 | "checkInvalidKey": true, 17 | "checkSiteMap": true, 18 | "uploadWithSourceMap": true, 19 | "useMultiFrameRuntime": false, 20 | "useApiHook": true, 21 | "babelSetting": { 22 | "ignore": [], 23 | "disablePlugins": [], 24 | "outputPath": "" 25 | }, 26 | "useIsolateContext": true, 27 | "useCompilerModule": true, 28 | "userConfirmedUseCompilerModuleSwitch": false, 29 | "packNpmManually": false, 30 | "packNpmRelationList": [] 31 | }, 32 | "compileType": "miniprogram", 33 | "libVersion": "2.16.0", 34 | "appid": "wx99d6524a9f5ce5d5", 35 | "projectname": "%E8%8D%89%E6%9C%A8%E5%A4%9A%E9%97%BB", 36 | "debugOptions": { 37 | "hidedInDevtools": [] 38 | }, 39 | "isGameTourist": false, 40 | "simulatorType": "wechat", 41 | "simulatorPluginLibVersion": {}, 42 | "condition": { 43 | "search": { 44 | "current": -1, 45 | "list": [] 46 | }, 47 | "conversation": { 48 | "current": -1, 49 | "list": [] 50 | }, 51 | "game": { 52 | "currentL": -1, 53 | "list": [] 54 | }, 55 | "miniprogram": { 56 | "current": -1, 57 | "list": [] 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /mini-program/frontend/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /mini-program/frontend/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | --------------------------------------------------------------------------------