rabin 5 роки тому
батько
коміт
5ce25a0979
100 змінених файлів з 4853 додано та 0 видалено
  1. 72 0
      LICENSE
  2. 9 0
      README.md
  3. 10 0
      admin.py
  4. 1 0
      admin/__init__.py
  5. 5 0
      admin/main.py
  6. 1 0
      admin/page/__init__.py
  7. 4 0
      admin/page/__load__.py
  8. 461 0
      admin/page/device.py
  9. 209 0
      admin/page/farm.py
  10. 135 0
      admin/page/hardware.py
  11. 109 0
      admin/page/msg.py
  12. 53 0
      admin/page/origin.py
  13. 87 0
      admin/page/package.py
  14. 174 0
      admin/page/setting.py
  15. 221 0
      admin/page/web.py
  16. 184 0
      admin/page/work.py
  17. 94 0
      conf/dev.conf
  18. 69 0
      conf/env.conf
  19. 24 0
      conf/temp.conf
  20. 19 0
      cron.py
  21. 10 0
      front.py
  22. 5 0
      front/__init__.py
  23. 4 0
      front/main.py
  24. 1 0
      front/page/__init__.py
  25. 463 0
      front/page/__load__.py
  26. 764 0
      front/page/device.py
  27. 244 0
      front/page/main.py
  28. 23 0
      front/page/msg.py
  29. 210 0
      front/page/origin.py
  30. 29 0
      front/page/upload.py
  31. 34 0
      front/page/user.py
  32. 221 0
      front/page/work.py
  33. 52 0
      front/static/mobile/analytics.html
  34. 0 0
      front/static/mobile/css/farm.css
  35. 0 0
      front/static/mobile/css/global.css
  36. 1 0
      front/static/mobile/css/imgs.css
  37. 1 0
      front/static/mobile/css/index.css
  38. 1 0
      front/static/mobile/css/login.css
  39. 1 0
      front/static/mobile/css/logs.css
  40. 0 0
      front/static/mobile/css/msgs.css
  41. 0 0
      front/static/mobile/css/origins.css
  42. 1 0
      front/static/mobile/css/station.css
  43. 105 0
      front/static/mobile/farm.html
  44. 83 0
      front/static/mobile/greenhouse.html
  45. BIN
      front/static/mobile/images/1fef2694.tmp2.jpg
  46. BIN
      front/static/mobile/images/35441c2e.ico.png
  47. BIN
      front/static/mobile/images/3fd94561.charts1.jpg
  48. BIN
      front/static/mobile/images/4fe4e197.ico.png
  49. BIN
      front/static/mobile/images/649cd7ee.tmp4.jpg
  50. BIN
      front/static/mobile/images/6f5ddf93.tmp5.jpg
  51. BIN
      front/static/mobile/images/786c7f25.farmicon.png
  52. BIN
      front/static/mobile/images/888db1cc.tmp1.jpg
  53. BIN
      front/static/mobile/images/8909d634.map.jpg
  54. BIN
      front/static/mobile/images/a1e19d4f.tmp.jpg
  55. BIN
      front/static/mobile/images/b667b90e.charts.jpg
  56. BIN
      front/static/mobile/images/bdc1f518.logo.jpg
  57. BIN
      front/static/mobile/images/f7a3ef62.banner.jpg
  58. 58 0
      front/static/mobile/imgs.html
  59. 72 0
      front/static/mobile/index.html
  60. 1 0
      front/static/mobile/js/analytics.js
  61. 1 0
      front/static/mobile/js/farm.js
  62. 0 0
      front/static/mobile/js/global.js
  63. 1 0
      front/static/mobile/js/greenhouse.js
  64. 13 0
      front/static/mobile/js/imgs.js
  65. 1 0
      front/static/mobile/js/index.js
  66. 1 0
      front/static/mobile/js/login.js
  67. 1 0
      front/static/mobile/js/logs.js
  68. 1 0
      front/static/mobile/js/msgs.js
  69. 13 0
      front/static/mobile/js/origins.js
  70. 1 0
      front/static/mobile/js/set.js
  71. 1 0
      front/static/mobile/js/soil.js
  72. 1 0
      front/static/mobile/js/station.js
  73. 48 0
      front/static/mobile/login.html
  74. 74 0
      front/static/mobile/logs.html
  75. 45 0
      front/static/mobile/msgs.html
  76. 89 0
      front/static/mobile/origins.html
  77. 46 0
      front/static/mobile/set.html
  78. 59 0
      front/static/mobile/soil.html
  79. 69 0
      front/static/mobile/station.html
  80. 0 0
      front/static/pc/css/global.css
  81. 1 0
      front/static/pc/css/login.css
  82. 1 0
      front/static/pc/css/logs.css
  83. 1 0
      front/static/pc/css/pmjk.css
  84. 1 0
      front/static/pc/css/sy_cplb.css
  85. 19 0
      front/static/pc/dsml.html
  86. 19 0
      front/static/pc/fmgg.html
  87. BIN
      front/static/pc/images/0ca089fc.icons.png
  88. BIN
      front/static/pc/images/20255880.tmp.jpg
  89. BIN
      front/static/pc/images/376a00e6.tmp2.jpg
  90. BIN
      front/static/pc/images/4c9b8ed6.tmp4.jpg
  91. BIN
      front/static/pc/images/4e9ffe8f.charts1.jpg
  92. BIN
      front/static/pc/images/51b4c576.icons.png
  93. BIN
      front/static/pc/images/8f932958.tmp1.jpg
  94. BIN
      front/static/pc/images/ac6b66f2.icons.png
  95. BIN
      front/static/pc/images/cd8fcfa0.icons.png
  96. BIN
      front/static/pc/images/e645d80a.tmp3.jpg
  97. 19 0
      front/static/pc/index.html
  98. 1 0
      front/static/pc/js/dsml.js
  99. 0 0
      front/static/pc/js/echarts.common.min.js
  100. 1 0
      front/static/pc/js/fmgg.js

+ 72 - 0
LICENSE

@@ -0,0 +1,72 @@
+Apache License 
+Version 2.0, January 2004 
+http://www.apache.org/licenses/
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License"); 
+you may not use this file except in compliance with the License. 
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software 
+distributed under the License is distributed on an "AS IS" BASIS, 
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+See the License for the specific language governing permissions and 
+limitations under the License.

+ 9 - 0
README.md

@@ -0,0 +1,9 @@
+# zeus
+
+云端服务器
+
+开发语言:python
+框架:tornado+demeter类库
+
+通信协议:mqtt/modbus
+

+ 10 - 0
admin.py

@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web
+    name:admin.py
+    author:rabin
+"""
+from demeter.core import *
+
+if __name__ == "__main__":
+	Demeter.webInit('admin')

+ 1 - 0
admin/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 5 - 0
admin/main.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+from demeter.web import *
+import demeter.admin.page as admin_page
+import admin.page
+Web.start(application=[admin.page,admin_page])

+ 1 - 0
admin/page/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 4 - 0
admin/page/__load__.py

@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+from demeter.admin.page.__load__ import *
+
+Demeter.config['setting']['farmList'] = Demeter.service('common').list('farm')

+ 461 - 0
admin/page/device.py

@@ -0,0 +1,461 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:device.py 设备相关页面
+    author:rabin
+"""
+from .__load__ import *
+
+class gateway_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'网关'
+			,path = 'gateway'
+			,width = '600'
+			,height = '500'
+			#,add = False
+			#,edit = False
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'网关名称'))
+			,thead = (u'网关名称', u'网关ID', u'所属产品', u'关联服务', u'网关连接状态', u'更新时间')
+			,tbody = ('name', 'hardware_id', 'product', 'server', 'status', 'cdate')
+			,state = False
+		)
+		self.list('device_gateway')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				device = self.service('common').list('device_info', search={'hardware_id':value['hardware_id']})
+				self.data['list'][key]['status'] = '断开'
+				self.data['list'][key]['product'] = '无'
+				self.data['list'][key]['server'] = '无'
+
+				if value['product_id']:
+					product = self.service('common').one('setting_product', id=value['product_id'])
+					self.data['list'][key]['product'] = product['name']
+				if value['server_id']:
+					server = self.service('common').one('setting_server', id=value['server_id'])
+					self.data['list'][key]['server'] = server['name']
+				if device:
+					for v in device:
+						if v['value']:
+							v['value'] = float(v['value'])
+							if v['hardware_type'] == 5 and v['value'] == 1:
+								self.data['list'][key]['status'] = '连接'
+							elif v['hardware_type'] == 4 and v['value']:
+								self.data['list'][key]['power_status'] = '连接'
+								self.data['list'][key]['power_num'] = v['value']
+		self.show('list')
+
+class gateway_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		if id:
+			#hardware_id = 'hardware_id-show-required'
+			hardware_id = 'hardware_id-input-required'
+		else:
+			hardware_id = 'hardware_id-input-required'
+		self.set(
+			path = 'gateway'
+			,label = (u'网关名称', u'网关ID', u'所属产品', u'关联服务', u'设备分布图纸')
+			,update = ('name-input-required',hardware_id,'product_id-select-','server_id-select-', 'pic-pic-')
+			,update_product_id = self.service('common').list('setting_product')
+			,update_server_id = self.service('common').list('setting_server')
+		)
+		self.one('device_gateway')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.update('device_gateway')
+		self.device(id)
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('device_gateway')
+
+	@Web.auth
+	@Web.setting
+	def device(self, id):
+		info = self.service('common').one('device_gateway', id=id)
+		self.service('device').addDeviceByGateway(info)
+		
+class info_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'设备'
+			,path = 'info'
+			,width = '600'
+			,height = '400'
+			,button = ({'name':'添加摄像机','link':'/device/camera_update'},{'name':'添加摄像头','link':'/device/camera_pic_update'})
+			,add = False
+			#,edit = False
+			,search = (('hardware_type-select-','type_id-select-','name-input-mlike', 'status-hidden-'), (u'硬件类型',u'设备类型',u'设备名称', '设备状态'))
+			,thead = (u'设备名称', u'设备id', u'当前值', u'设备类型', u'网关',u'硬件类型')
+			,tbody = ('name', 'hardware_id', 'value', 'type', 'gateway', 'hardware_type')
+			,state = True
+		)
+		self.data['common']['search_type_id-select-'] = self.service('common').list('setting_device_type')
+		self.data['common']['search_gateway_id-select---farm_id'] = self.service('common').list('device_gateway')
+		self.data['common']['search_hardware_type-select-'] = self.service('common').list('hardware_type')
+		"""
+		if self.data['common']['search_hardware_type-select-']:
+			del self.data['common']['search_hardware_type-select-'][0]
+		"""
+		status = self.input('search_status-hidden-', False)
+		if status:
+			self.data['search']['status'] = False
+
+		self.list('device_info', order='inorder asc, type_id asc,udate asc,hardware_id asc')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				farm = self.service('common').one('farm', id=value['farm_id'])
+				self.data['list'][key]['farm'] = farm['name']
+				self.data['list'][key]['type'] = '无'
+				if value['type_id']:
+					type_info = self.service('common').one('setting_device_type', id=value['type_id'])
+					if type_info:
+						self.data['list'][key]['type'] = type_info['name']
+				info = self.service('common').one('device_gateway', id=value['gateway_id'])
+				self.data['list'][key]['gateway'] = info['name']
+				if value['status']:
+					self.data['list'][key]['status'] = '已连接'
+				else:
+					self.data['list'][key]['status'] = '已断开'
+
+				if not value['value']:
+					value['value'] = ''
+					self.data['list'][key]['value'] = '无'
+				elif value['hardware_type'] == 2 or value['hardware_type'] == 4:
+					if value['type_id'] and type_info:
+						value['value'] = value['value'] + ' ' + type_info['unit']
+					self.data['list'][key]['value'] = '<a href="/device/stat?id='+value['id']+'&search_date-select-=1&method=list">'+value['value'] + '</a><br />更新时间:' + Demeter.date(value['cdate']) + '<br /><a href="/device/stat?id='+value['id']+'&search_date-select-=1&method=avg">[平均值统计]</a> <a href="/device/stat?id='+value['id']+'&search_date-select-=1&method=maxmin">[高低值统计]</a>'
+				elif value['hardware_type'] == 6:
+					self.data['list'][key]['value'] = '<a href="/device/pic?id='+value['id']+'"><img src="'+value['value']+'" width="200px"/></a><br />更新时间:' + Demeter.date(value['cdate'])
+				elif value['hardware_type'] == 3:
+					if value['status']:
+						status = ''
+					else:
+						status = 'disabled'
+					url = '/device/info'
+					import math
+					value['value'] = math.ceil(float(value['value']))
+					if value['value'] == 1:
+						value['value'] = '开'
+					else:
+						value['value'] = '关'
+
+					'''
+					if value['value'] == 1:
+						#disabled
+						self.data['list'][key]['value'] = '<input type="checkbox" name="switch" lay-filter="switch" lay-skin="switch" checked '+status+' value="1" data-value="0" data-id="'+value['id']+'" data-url="'+url+'">'
+					else:
+						self.data['list'][key]['value'] = '<input type="checkbox" lay-filter="switch" name="switch" lay-skin="switch" '+status+' value="0" data-value="1" data-id="'+value['id']+'" data-url="'+url+'">'
+					'''
+					self.data['list'][key]['value'] = value['value']
+				elif value['hardware_type'] == 5:
+					if value['value'] == '1':
+						self.data['list'][key]['value'] = '已连接'
+					else:
+						self.data['list'][key]['value'] = '已断开'
+
+				hardware_type = self.service('common').one('hardware_type', id=value['hardware_type'])
+				self.data['list'][key]['hardware_type'] = hardware_type['name']
+
+
+		self.show('list')
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		value = self.input('value')
+		if id:
+			Demeter.service('device').switch(id, value)
+			self.out('yes', {'state':id})
+		else:
+			self.out('no')
+
+class info_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.one('device_info')
+		if self.data['info']['hardware_type'] == 7:
+			self.set(
+				path = 'camera'
+				#,label = (u'摄像机名称', u'摄像机id', u'所属农场', u'选择网关', u'选择硬件类型', u'摄像机地址')
+				#,update = ('name-input-required','hardware_id-show-','farm_id-select-required','gateway_id-select-required','hardware_type-select-required','value-text-required')
+				,label = (u'摄像机名称', u'摄像机id', u'所属农场', u'选择网关', u'摄像机地址', u'排序')
+				,update = ('name-input-required','hardware_id-show-','farm_id-select-required-gateway_id','gateway_id-select-required--farm_id','value-text-required','inorder-input-')
+				,update_farm_id = Demeter.config['setting']['farmList']
+				,update_gateway_id = self.service('common').list('device_gateway')
+				#,update_hardware_type = self.service('common').list('hardware_type')
+			)
+		elif self.data['info']['hardware_type'] == 6:
+			self.set(
+				path = 'camera_pic'
+				,label = (u'摄像头名称', u'摄像头id', u'所属农场', u'选择网关', u'摄像头地址', u'排序')
+				,update = ('name-input-required','hardware_id-show-','farm_id-select-required-gateway_id','gateway_id-select-required--farm_id','value-text-required','inorder-input-')
+				,update_farm_id = Demeter.config['setting']['farmList']
+				,update_gateway_id = self.service('common').list('device_gateway')
+			)
+		elif self.data['info']['hardware_type'] in (2,4):
+			self.set(
+				path = 'info'
+				#,label = (u'设备名称', u'设备id', u'计算公式', u'实时计算公式')
+				#,update = ('name-input-required','hardware_id-show-',u'exp-text--{n}为当前数据,只处理最新数据',u'out_exp-text--处理所有数据,比较消耗服务器资源')
+				,label = (u'设备名称', u'设备id', u'计算公式', u'排序')
+				,update = ('name-input-required','hardware_id-show-',u'exp-input--{n}为当前数据,只处理最新数据','inorder-text-')
+			)
+		else:
+			self.set(
+				path = 'info'
+				,label = (u'设备名称', u'设备id', u'排序')
+				,update = ('name-input-required','hardware_id-show-','inorder-input-')
+			)
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('device_info')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('device_info')
+		"""
+		self.one('device_info')
+		if self.input('state') == 'True' or (self.data['info'] and 'hardware_type' in self.data['info'] and self.data['info']['hardware_type'] == 7):
+			self.drop('device_info')
+		else:
+			#除摄像机之外,其余设备不允许删除
+			self.out('no')
+		"""
+
+class camera_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.redirect('/device/info?search_hardware_type=7')
+
+class camera_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = 'camera'
+			,label = (u'摄像机名称', u'摄像机id', u'所属农场', u'选择网关', u'摄像机地址',u'排序')
+			,update = ('name-input-required','hardware_id-input-required','farm_id-select-required-gateway_id','gateway_id-select-required--farm_id','value-text-required','inorder-text-')
+			,update_farm_id = Demeter.config['setting']['farmList']
+			,update_gateway_id = self.service('common').list('device_gateway')
+		)
+		self.one('device_info')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.data['update']['hardware_type'] = 7
+		self.data['update']['type_id'] = 0
+		self.update('device_info')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('device_info')
+
+class camera_pic_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.redirect('/device/info?search_hardware_type=6')
+
+class camera_pic_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = 'camera_pic'
+			,label = (u'摄像头名称', u'摄像头id', u'所属农场', u'选择网关', u'摄像头地址',u'排序')
+			,update = ('name-input-required','hardware_id-input-required','farm_id-select-required-gateway_id','gateway_id-select-required--farm_id','value-text-required','inorder-text-')
+			,update_farm_id = Demeter.config['setting']['farmList']
+			,update_gateway_id = self.service('common').list('device_gateway')
+		)
+		self.one('device_info')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.data['update']['hardware_type'] = 6
+		self.data['update']['type_id'] = 0
+		self.update('device_info')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('device_info')
+
+class pic_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'摄像头图片'
+			,path = 'pic'
+			,width = '600'
+			,height = '300'
+			,add = False
+			,edit = False
+			,search = (('label-1','sdate-time-start','sdate-time-end'), (u'日期范围',u'开始时间',u'截止时间'))
+			,thead = (u'图片地址', u'更新时间')
+			,tbody = ('pic', 'sdate')
+			,state = False
+		)
+
+		self.list('device_pic', order='sdate desc')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['pic'] = '<img src="'+value['pic']+'" width="200px" />'
+		self.show('list')
+
+class stat_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		method = self.input('method', 'avg')
+		id = self.input('id')
+		self.set(
+			name = u'设备统计'
+			,path = 'stat'
+			,search = (('label-1','cdate-time-start','cdate-time-end', 'date-select-'), (u'日期范围',u'开始时间',u'截止时间',u'周期选择'))
+		)
+		data = self.service('common').one('device_info', id=id)
+		typeInfo = self.service('common').one('setting_device_type', id=data['type_id'])
+		farm = self.service('common').one('farm', id=data['farm_id'])
+		self.data['info'] = data
+		self.data['type'] = typeInfo
+		self.data['farm'] = farm
+		self.data['method'] = method
+
+		model = Demeter.model('data', 'tsdb')
+		self.data['common']['search_date-select-'] = model.dateConfig()
+		search = {}
+		if 'cdate-time-start' in self.data['search']:
+			search['start'] = self.data['search']['cdate-time-start']
+		if 'cdate-time-end' in self.data['search']:
+			search['end'] = self.data['search']['cdate-time-end']
+		if 'date-select-' in self.data['search']:
+			search['group'] = self.data['search']['date-select-']
+		self.data['list'] = model.getData(method, search, data)
+
+		self.show('stat')
+
+
+class printer_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'打印机'
+			,path = 'printer'
+			,width = '600'
+			,height = '400'
+			,search = (('farm_id-select-','name-input-mlike'), (u'选择农场',u'打印机名称'))
+			,thead = (u'所属农场', u'打印机名称', u'打印机地址', u'更新时间')
+			,tbody = ('farm','name', 'host', 'cdate')
+			,state = True
+		)
+		self.data['common']['search_farm_id-select-'] = Demeter.config['setting']['farmList']
+		self.list('device_printer')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				farm = self.service('common').one('farm', id=value['farm_id'])
+				self.data['list'][key]['farm'] = farm['name']
+		self.show('list')
+
+class printer_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = 'printer'
+			,label = (u'所属农场', u'打印机名称', u'打印机地址')
+			,update = ('farm_id-select-required', 'name-input-required','host-input-required')
+			,update_farm_id = Demeter.config['setting']['farmList']
+		)
+		self.one('device_printer')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('device_printer')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('device_printer')
+
+
+class notice_type_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'错误码设置'
+			,path = '/device/notice_type'
+			,width = '600'
+			,height = '300'
+			,search = (('name-input-mlike','key-input-mlike'), (u'错误码描述',u'错误码key'))
+			,thead = (u'ID', u'错误码描述',u'错误码key', u'更新时间')
+			,tbody = ('id', 'name', 'key', 'cdate')
+			,state = False
+		)
+		self.list('notice_type')
+		self.show('list')
+
+class notice_type_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/device/notice_type'
+			,label = (u'错误码描述', u'错误码key')
+			,update = ('name-input-required', 'key-input-required')
+		)
+		self.one('notice_type')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('notice_type')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('notice_type')
+
+class log_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'网关日志'
+			,path = '/device/log'
+			,width = '600'
+			,height = '600'
+			,add = False
+			,edit = False
+			,search = (('farm_id-select-','content-input-mlike'), (u'选择农场', u'内容'))
+			,thead = (u'所属农场', u'所属网关', u'日志内容',u'发送时间')
+			,tbody = ('farm','gateway', 'content', 'cdate')
+			,state = False
+		)
+		self.data['common']['search_farm_id-select-'] = Demeter.config['setting']['farmList']
+		self.list('log')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				farm = self.service('common').one('farm', id=value['farm_id'])
+				self.data['list'][key]['farm'] = farm['name']
+				gateway = self.service('common').one('device_gateway', id=value['gateway_id'])
+				self.data['list'][key]['gateway'] = gateway['name']
+		self.show('list')

+ 209 - 0
admin/page/farm.py

@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:farm.py 农场相关页面
+    author:rabin
+"""
+from .__load__ import *
+
+farm = {
+	'id' : int(Demeter.config['setting']['farm'])
+}
+
+class farm_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'农场' #中文名
+			,path = '/farm/farm' #路径
+			,width = '600' # 新增页面的宽度
+			,height = '600' # 新增页面的高度
+			,edit = False
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'农场名称')) #搜索
+			,thead = (u'ID', u'农场名称', u'功能列表') #表头
+			,tbody = ('id','name', 'func') #表内容
+			,state = False #启用回收站
+		)
+		menu = (
+			{'name':'基础资料', 'url':'/farm/info'}
+			,{'name':'用户管理', 'url':'/farm/user'}
+			,{'name':'产品管理', 'url':'/farm/product'}
+			,{'name':'地块管理', 'url':'/work/land'}
+			,{'name':'农事管理', 'url':'/work/work'}
+			,{'name':'批次管理', 'url':'/origin/batch'}
+
+			,{'name':'网关管理', 'url':'/device/gateway'}
+			,{'name':'设备管理', 'url':'/device/info'}
+
+			,{'name':'打包下载', 'url':'/package/download'}
+			,{'name':'本地控制', 'url':'/package/download'}
+			
+			#,{'name':'打印机管理', 'url':'/device/printer'}
+			#,{'name':'消息提醒', 'url':'/msg/msg'}
+			#,{'name':'网关日志', 'url':'/device/log'}
+			)
+		self.list('farm')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				id = str(value['id'])
+				param = '?farm=' + id + '&search_farm_id-select-=' + id
+				self.data['list'][key]['func'] = ''
+				for i in menu:
+					self.data['list'][key]['func'] = self.data['list'][key]['func'] + '<a href="'+i['url']+''+param+'">'+i['name']+'</a>&nbsp;&nbsp;&nbsp;&nbsp;'
+		self.show('list')
+
+class farm_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/farm/farm'
+			,label = (u'农场名称',)
+			,update = ('name-input-required',)
+		)
+		self.one('farm')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.update('farm')
+		Demeter.config['setting']['farmList'] = self.service('common').list('farm')
+		#self.gateway(id)
+
+	def gateway(self, farm):
+		gateway = self.data['update']['gateway']
+		if gateway:
+			#换行隔开,逗号隔开,插入到网关表里
+			data = gateway.split("\r\n")
+			for value in data:
+				if ',' in value:
+					value = value.split(',')
+				else:
+					value[0] = value
+					value[1] = '网关' + value
+				info = self.service('common').one('device_gateway', hardware_id=value[0])
+				if not info:
+					insert = {}
+					insert['farm_id'] = farm
+					insert['name'] = value[1]
+					insert['hardware_id'] = value[0]
+					self.service('common').update('device_gateway', None, insert)
+				else:
+					update = {}
+					update['name'] = value[1]
+					self.service('common').update('device_gateway', info['id'], update)
+
+class info_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = str(farm['id'])
+		param = '?farm=' + id
+		self.set(
+			path = '/farm/info' + param
+			,label = (u'农场名称',u'农场图片',u'农场位置',u'联系电话',u'联系地址',u'农场主姓名',u'农场主照片',u'欢迎语',u'农场介绍',u'本地控制器')
+			,update = ('name-input-required','pic-pic-required-1000px*300~450px','location-input-required','tel-input-required','address-input-required','master_name-input-required','master_pic-pic-required-300px*450px','welcome-input-',u'info-text-required-请输入农场介绍','eros_status-select-required')
+			,update_eros_status = Demeter.service('core', 'setting').eros_status()
+		)
+		self.one('farm', id=farm['id'])
+		self.show('set')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('farm', id=farm['id'])
+
+class product_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'产品'
+			,path = '/farm/product'
+			,width = '600'
+			,height = '500'
+			,search = (('label-1','cdate-time-start','cdate-time-end','farm_id-select-','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间','选择农场',u'产品名称'))
+			,thead = (u'所属农场', u'产品名称', u'图片', u'种植面积', u'平均亩产', u'更新时间')
+			,tbody = ('farm','name', 'pic', 'area', 'yields', 'cdate')
+			,state = True
+		)
+		self.data['common']['search_farm_id-select-'] = Demeter.config['setting']['farmList']
+		self.list('farm_product')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				farm = self.service('common').one('farm', id=value['farm_id'])
+				self.data['list'][key]['farm'] = farm['name']
+				if self.data['list'][key]['pic']:
+					self.data['list'][key]['pic'] = '<img src="'+self.data['list'][key]['pic']+'" width="200"/>'
+				else:
+					self.data['list'][key]['pic'] = '暂无图片'
+		self.show('list')
+
+class product_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/farm/product'
+			,label = (u'所属农场',u'产品名称', u'种植面积', u'平均亩产', u'特点', u'使用须知', u'图片')
+			,update = ('farm_id-select-required', 'name-input-required','area-input-required','yields-input-required','charact-input-required','notice-input-required','pic-pic-required')
+			,update_farm_id = Demeter.config['setting']['farmList']
+		)
+		self.one('farm_product')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		#self.data['update']['farm_id'] = farm['id']
+		self.update('farm_product')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('farm_product')
+
+
+class user_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'用户'
+			,path = '/farm/user'
+			,width = '600'
+			,height = '400'
+			,search = (('label-1','cdate-time-start','cdate-time-end','farm_id-select-','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间','选择农场',u'用户名称'))
+			,thead = (u'所属农场', u'UID', u'用户名称', u'用户手机号', u'更新时间')
+			,tbody = ('farm','id', 'username', 'mobile', 'cdate')
+			,state = True
+		)
+
+		self.data['common']['search_farm_id-select-'] = Demeter.config['setting']['farmList']
+
+		self.list('farm_user')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				farm = self.service('common').one('farm', id=value['farm_id'])
+				self.data['list'][key]['farm'] = farm['name']
+		self.show('list')
+
+class user_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/farm/user'
+			,label = (u'所属农场',u'账号姓名',u'手机号',u'安全码')
+			,update = ('farm_id-select-required','username-input-required','mobile-input-phone','password-password-')
+			,update_farm_id = Demeter.config['setting']['farmList']
+		)
+		self.one('farm_user')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		#self.data['update']['farm_id'] = farm['id']
+		self.update('farm_user', '手机号已经被注册', mobile=self.data['update']['mobile'])
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('farm_user')

+ 135 - 0
admin/page/hardware.py

@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:hardware.py 硬件相关页面
+    author:rabin
+"""
+from .__load__ import *
+
+class hardware_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'硬件设备'
+			,path = '/hardware/hardware'
+			,width = '600'
+			,height = '600'
+			,add = False
+			,edit = False
+			,search = (('farm_id-select-','hardware_type-select-','hardware_id-input-mlike'), (u'选择农场',u'硬件类型', u'硬件id'))
+			,thead = (u'所属农场', u'硬件类型', u'硬件id',u'网关名',u'设备名', u'接入时间')
+			,tbody = ('farm','type', 'hardware_id', 'gateway', 'device', 'cdate')
+			,state = False
+		)
+		self.data['common']['search_farm_id-select-'] = Demeter.config['setting']['farmList']
+		self.data['common']['search_hardware_type-select-'] = self.service('common').list('hardware_type')
+		self.list('hardware')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				farm = self.service('common').one('farm', id=value['farm_id'])
+				self.data['list'][key]['farm'] = farm['name']
+				htype = self.service('common').one('hardware_type', id=value['hardware_type'])
+				self.data['list'][key]['type'] = htype['name']
+
+				gateway = self.service('common').one('device_gateway', id=value['gateway_id'])
+				self.data['list'][key]['gateway'] = '无效'
+				if gateway:
+					self.data['list'][key]['gateway'] = gateway['name']
+				self.data['list'][key]['device'] = '无效'
+				if value['device_id']:
+					device = self.service('common').one('device_info', id=value['device_id'])
+					if device:
+						self.data['list'][key]['device'] = device['name']
+					
+		self.show('list')
+
+class hardware_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/hardware/hardware'
+			,label = (u'硬件类型',u'硬件id')
+			,update = ('hardware_type-select-required','hardware_id-input-required')
+			,update_hardware_type = self.service('common').list('hardware_type')
+		)
+		self.one('hardware')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('hardware')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('hardware')
+
+class type_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'硬件类型'
+			,path = '/hardware/type'
+			,button = ({'name':'重启守护进程','link':'/hardware/restart_cron','ajax':True,'icon':'&#xe631;'},{'name':'重启mqtt订阅服务','link':'/hardware/restart_sub','ajax':True,'icon':'&#xe631;'},{'name':'重启园区服务','link':'/hardware/restart_front','ajax':True,'icon':'&#xe631;'},{'name':'重启后台服务','link':'/hardware/restart_admin','ajax':True,'icon':'&#xe631;'},{'name':'重启网站服务','link':'/hardware/restart_web','ajax':True,'icon':'&#xe631;'})
+			,width = '600'
+			,height = '300'
+			,search = (('name-input-mlike',), (u'类型名称',))
+			,thead = (u'类型ID',u'类型名称',u'类型key', u'更新时间')
+			,tbody = ('id', 'name', 'key', 'cdate')
+			,state = False
+		)
+		self.list('hardware_type')
+		self.show('list')
+
+class type_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/hardware/type'
+			,label = (u'类型名称', u'类型key')
+			,update = ('name-input-required', 'key-input-required')
+		)
+		self.one('hardware_type')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('hardware_type')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('hardware_type')
+
+class restart_cron_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self):
+		Shell.popen("ps -ef | grep cron.py | grep -v grep |awk '{print $1}'|xargs kill -9")
+		Shell.popen('/usr/local/demeter/cron.py >/dev/null &')
+
+class restart_sub_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self):
+		Shell.popen("ps -ef | grep sub.py | grep -v grep |awk '{print $1}'|xargs kill -9")
+
+class restart_admin_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self):
+		Shell.popen("ps -ef | grep admin.py | grep -v grep |awk '{print $1}'|xargs kill -9")
+
+class restart_front_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self):
+		Shell.popen("ps -ef | grep front.py | grep -v grep |awk '{print $1}'|xargs kill -9")
+
+class restart_web_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self):
+		Shell.popen("ps -ef | grep web.py | grep -v grep |awk '{print $1}'|xargs kill -9")

+ 109 - 0
admin/page/msg.py

@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:msg.py 消息相关
+    author:rabin
+"""
+from .__load__ import *
+
+push = ({'id':'sms', 'name':'短信'}, {'id':'weixin', 'name':'微信'})
+
+class msg_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'消息'
+			,path = '/msg/msg'
+			,width = '600'
+			,height = '600'
+			,add = False
+			,edit = False
+			,full = True
+			,search = (('type_id-select-','content-input-mlike'), (u'硬件类型', u'消息内容'))
+			,thead = ( u'消息类型', u'消息内容', u'是否已读',u'发送时间')
+			,tbody = ('type', 'content', 'status', 'cdate')
+			,state = False
+		)
+		self.data['common']['search_type_id-select-'] = self.service('common').list('msg_type')
+		self.list('msg')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				htype = self.service('common').one('msg_type', id=value['type_id'])
+				self.data['list'][key]['type'] = htype['name']
+
+				if value['uid']:
+					user = self.service('common').one('farm_user', id=value['uid'])
+					self.data['list'][key]['user'] = user['username']
+				else:
+					self.data['list'][key]['user'] = '无'
+
+				if value['status'] == True:
+					self.data['list'][key]['status'] = '已读'
+				else:
+					self.data['list'][key]['status'] = '未读'
+		self.show('list')
+
+class msg_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/msg/msg'
+			,label = (u'发送用户',u'消息类型',u'消息内容',u'消息链接',u'推送')
+			,update = ('uid-checkbox--farm_id','msg_type-select-required','content-editor-required','link-input-','push-checkbox-')
+			,update_msg_type = self.service('common').list('msg_type')
+			,update_uid = self.service('common').list('farm_user')
+			,update_push = push
+		)
+		self.one('msg')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		# 发消息
+		self.update('msg')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('msg')
+
+class type_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'消息类型'
+			,path = '/msg/type'
+			,width = '600'
+			,height = '300'
+			,search = (('name-input-mlike',), (u'类型名称',))
+			,thead = (u'类型ID', u'类型名称',u'类型key', u'更新时间')
+			,tbody = ('id', 'name', 'key', 'cdate')
+			,state = False
+		)
+		self.list('msg_type')
+		self.show('list')
+
+class type_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/msg/type'
+			#,label = (u'类型名称', u'类型key',u'推送')
+			#,update = ('name-input-required', 'key-input-required','push-checkbox-')
+			,label = (u'类型名称', u'类型key')
+			,update = ('name-input-required', 'key-input-required')
+			,update_push = push
+		)
+		self.one('msg_type')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('msg_type')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('msg_type')

+ 53 - 0
admin/page/origin.py

@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:origin.py 溯源相关页面
+    author:rabin
+"""
+from .__load__ import *
+
+class batch_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'溯源批次'
+			,path = '/origin/batch'
+			,width = '600'
+			,height = '600'
+			,add = False
+			,edit = False
+			,search = (('land_id-select-',), (u'地块',))
+			,thead = (u'产品名称', u'种植时间', u'采收时间', u'地块')
+			,tbody = ('name', 'zzdate', 'csdate', 'land')
+			,state = False
+		)
+		self.data['common']['search_land_id-select-'] = self.service('common').list('farm_work_land')
+		self.list('origin_batch')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				land = self.service('common').one('farm_work_land', id=value['land_id'])
+				self.data['list'][key]['land'] = land['name']
+		self.show('list')
+
+class batch_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/origin/batch'
+			,label = (u'产品名称', u'种植时间',u'采收时间',u'设备网关',u'地块',u'图像记录')
+			,update = ('name-input-required', 'zzdate-date-required', 'csdate-date-required','gateway_id-select-required','land_id-select-required','pic-pic-required')
+			,update_gateway_id = self.service('common').list('device_gateway')
+			,update_land_id = self.service('common').list('farm_work_land')
+		)
+		self.one('origin_batch')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('origin_batch')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('origin_batch')

+ 87 - 0
admin/page/package.py

@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:package.py 版本相关
+    author:rabin
+"""
+from .__load__ import *
+
+class version_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'版本'
+			,path = '/package/version'
+			,width = '600'
+			,height = '600'
+			,search = (('package_id-select-','name-input-mlike','version-input-mlike'), (u'选择Package', u'版本名称', u'版本号'))
+			,thead = (u'所属Package', u'版本名称', u'版本号', u'创建时间')
+			,tbody = ('package','name', 'version', 'cdate')
+			,state = False
+		)
+		self.data['common']['search_package-select-'] = self.service('common').list('package')
+		self.list('package_version')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				package = self.service('common').one('package', id=value['package_id'])
+				self.data['list'][key]['package'] = package['name']
+		self.show('list')
+
+class version_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/package/version'
+			,label = (u'所属Package',u'版本名称',u'版本号')
+			,update = ('package_id-select','name-input-required','name-input-required')
+			,update_package_id = self.service('common').list('package')
+		)
+		self.one('package_version')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('package_version')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('package_version')
+
+class package_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'Package'
+			,path = '/package/package'
+			,width = '600'
+			,height = '300'
+			,search = (('name-input-mlike','url-input-mlike'), (u'名称',u'地址'))
+			,thead = (u'ID', u'名称',u'地址', u'更新时间')
+			,tbody = ('id', 'name', 'url', 'cdate')
+			,state = False
+		)
+		self.list('package')
+		self.show('list')
+
+class package_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/package/package'
+			,label = (u'名称', u'地址')
+			,update = ('name-input-required', 'url-input-required')
+		)
+		self.one('package')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('package')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('package')

+ 174 - 0
admin/page/setting.py

@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter setting page
+    name:setting.py 服务协议管理
+    author:rabin
+"""
+from .__load__ import *
+
+class server_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'服务管理'
+			,path = '/setting/server'
+			,width = '600'
+			,height = '600'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'服务名称'))
+			,thead = (u'服务名称', u'服务类型', u'服务地址', u'服务端口', u'更新时间')
+			,tbody = ('name', 'server_type', 'server_host', 'server_port', 'cdate')
+			,state = True
+		)
+		self.list('setting_server')
+		if self.data['list']:
+			server_type = Demeter.service('core', 'setting').server_type()
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['server_type'] = server_type[value['server_type']-1]['name']
+		self.show('list')
+
+class server_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/setting/server'
+			,label = (u'服务名称',u'服务类型',u'服务地址',u'服务端口',u'请求间隔')
+			,update = ('name-input-required','server_type-select-required','server_host-input-required','server_port-input-required','server_time-input-required')
+			,update_server_type = Demeter.service('core', 'setting').server_type()
+		)
+		self.one('setting_server')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('setting_server')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('setting_server')
+
+
+class product_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'产品管理'
+			,path = '/setting/product'
+			,width = '600'
+			,height = '600'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'产品名称'))
+			,thead = (u'产品名称',u'产品标识', u'更新时间')
+			,tbody = ('name', 'key','cdate')
+			,state = True
+		)
+		self.list('setting_product')
+		self.show('list')
+
+class product_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/setting/product'
+			,label = (u'产品名称',u'产品标识')
+			,update = ('name-input-required','key-input-required')
+		)
+		self.one('setting_product')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('setting_product')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('setting_product')
+
+class device_type_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'设备类型'
+			,path = '/setting/device_type'
+			,width = '600'
+			,height = '400'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'类型名称'))
+			,thead = (u'类型ID', u'类型名称', u'类型标识', u'类型单位', u'更新时间')
+			,tbody = ('id', 'name', 'key', 'unit', 'cdate')
+			,state = True
+		)
+		self.list('setting_device_type')
+		self.show('list')
+
+class device_type_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/setting/device_type'
+			#,label = (u'类型名称', u'类型标识',u'类型单位',u'表达式')
+			#,update = ('name-input-required','key-input-required','unit-input-',u'exp-text--请输入表达式,{n}代表当前数据')
+			,label = (u'类型名称', u'类型标识',u'类型单位',u'操作类型',u'可选项')
+			,update = ('name-input-required','key-input-required','unit-input-','data_type-select-','data_option-text--多个换行隔开')
+			,update_data_type = Demeter.service('core', 'setting').data_type()
+		)
+		self.one('setting_device_type')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('setting_device_type')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('setting_device_type')
+
+class modbus_code_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'设备命令码'
+			,path = '/setting/modbus_code'
+			,width = '600'
+			,height = '600'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike','product_id-select-'), (u'日期范围',u'开始时间',u'截止时间',u'设备名称',u'选择产品'))
+			,thead = (u'命令码名称', u'所属产品',u'关联设备类型', u'表达式', u'更新时间')
+			,tbody = ('name', 'product','device_type_key', 'exp', 'cdate')
+			,state = True
+		)
+		self.data['common']['search_product_id-select-'] = self.service('common').list('setting_product')
+		self.list('setting_modbus_code')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				product = self.service('common').one('setting_product', id=value['product_id'])
+				self.data['list'][key]['product'] = product['name']
+		self.show('list')
+
+class modbus_code_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/setting/modbus_code'
+			,label = (u'命令码名称',u'所属产品',u'设备类型',u'表达式',u'硬件类型',u'从机id',u'寄存器读取地址',u'寄存器写入地址')
+			,update = ('name-input-required','product_id-select-required','device_type_key-text-required-直接输入设备类型的key,多个用换行隔开','exp-text--{n}为当前数据,多个用换行隔开','hardware_type-select-required','slave_id-input-required','register_read_address-text-required-多个用换行隔开,寄存器类型,地址,长度','register_write_address-text--多个用换行隔开,寄存器类型,地址,长度(可为空)')
+			,update_product_id = self.service('common').list('setting_product')
+			,update_device_type = self.service('common').list('setting_device_type')
+			#,update_oper_type = Demeter.service('core', 'setting').oper_type()
+			#,update_register_type = Demeter.service('core', 'setting').register_type()
+			,update_hardware_type = self.service('common').list('hardware_type')
+		)
+		self.one('setting_modbus_code')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('setting_modbus_code')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('setting_modbus_code')

+ 221 - 0
admin/page/web.py

@@ -0,0 +1,221 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:content.py 内容相关页面
+    author:rabin
+"""
+from .__load__ import *
+
+class set_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/web/set'
+			,label = (u'标题',u'关键词',u'描述',u'icp备案号',u'联系电话',u'忘记密码联系电话',u'手机端管理',u'购买方式')
+			,update = ('name-input-required','keywords-input-required','description-input-required','icp-input-required','tel-input-required','passtel-input-required',u'mobile-pic--',u'buy-pic--')
+		)
+		self.one('web_set', id=1)
+		self.show('set')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('web_set',id=1)
+
+class article_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'文章'
+			,path = '/web/article'
+			,width = '800'
+			,height = '700'
+			,search = (('label-1','cdate-time-start','cdate-time-end','category_id-select-','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'文章分类',u'文章标题'))
+			,thead = (u'文章标题', u'文章分类', u'更新时间')
+			,tbody = ('name', 'category', 'cdate')
+			,state = True
+		)
+		self.data['common']['search_category_id-select-'] = self.service('common').list('web_article_category')
+		self.list('web_article')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				category = self.service('common').one('web_article_category', id=value['category_id'])
+				self.data['list'][key]['category'] = category['name']
+		self.show('list')
+
+class article_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/web/article'
+			,label = (u'文章标题',u'文章分类',u'文章链接',u'文章图片',u'文章内容')
+			,update = ('name-input-required','category_id-select-required','link-input-','pic-pic-',u'content-editor--请输入内容')
+			,update_category_id = self.service('common').list('web_article_category')
+		)
+		self.one('web_article')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('web_article')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('web_article')
+
+
+class category_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'分类'
+			,path = '/web/category'
+			,width = '600'
+			,height = '300'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'分类名称'))
+			,thead = (u'分类名称', u'更新时间')
+			,tbody = ('name', 'cdate')
+			,state = True
+		)
+		self.list('web_article_category')
+		self.show('list')
+
+class category_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/web/category'
+			,label = (u'分类名称',)
+			,update = ('name-input-required',)
+		)
+		self.one('web_article_category')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('web_article_category')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('web_article_category')
+
+class help_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'帮助'
+			,path = '/web/help'
+			,width = '800'
+			,height = '600'
+			,search = (('label-1','cdate-time-start','cdate-time-end','category_id-select-','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'帮助分类',u'帮助标题'))
+			,thead = (u'帮助标题', u'帮助分类', u'更新时间')
+			,tbody = ('name', 'category', 'cdate')
+			,state = True
+		)
+		self.data['common']['search_category_id-select-'] = self.service('common').list('web_help_category')
+		self.list('web_help')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				category = self.service('common').one('web_help_category', id=value['category_id'])
+				self.data['list'][key]['category'] = category['name']
+		self.show('list')
+
+class help_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/web/help'
+			,label = (u'帮助标题',u'帮助分类',u'帮助内容')
+			,update = ('name-input-required','category_id-select-required',u'content-editor--请输入内容')
+			,update_category_id = self.service('common').list('web_help_category')
+		)
+		self.one('web_help')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('web_help')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('web_help')
+
+class help_category_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'分类'
+			,path = '/web/help_category'
+			,width = '600'
+			,height = '300'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'分类名称'))
+			,thead = (u'帮助分类名称', u'更新时间')
+			,tbody = ('name', 'cdate')
+			,state = True
+		)
+		self.list('web_help_category')
+		self.show('list')
+
+class help_category_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/web/help_category'
+			,label = (u'帮助分类名称',)
+			,update = ('name-input-required',)
+		)
+		self.one('web_help_category')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('web_help_category')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('web_help_category')
+
+class menu_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'菜单'
+			,path = '/web/menu'
+			,width = '600'
+			,height = '300'
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'菜单名称'))
+			,thead = (u'菜单名称',u'菜单链接', u'更新时间')
+			,tbody = ('name', 'link', 'cdate')
+			,state = True
+		)
+		self.list('web_menu')
+		self.show('list')
+
+class menu_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/web/menu'
+			,label = (u'菜单名称',u'菜单链接')
+			,update = ('name-input-required','link-input-required')
+		)
+		self.one('web_menu')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('web_menu')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('web_menu')

+ 184 - 0
admin/page/work.py

@@ -0,0 +1,184 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:work.py 农事相关页面
+    author:rabin
+"""
+from .__load__ import *
+
+class work_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'农事'
+			,path = '/work/work'
+			,width = '600'
+			,height = '600'
+			,add = False
+			,edit = False
+			,search = (('label-1','workdate-time-start','workdate-time-end','category_id-select-'), (u'日期范围',u'开始时间',u'截止时间',u'劳作分类'))
+			,thead = (u'劳作时间', u'劳作分类', u'劳作方式', u'劳作地块', u'劳作用量', u'更新时间')
+			,tbody = ('workdate', 'category', 'method', 'land', 'amount', 'cdate')
+			,state = False
+		)
+		self.list('device_gateway')
+
+		self.data['common']['search_category_id-select-'] = self.service('common').list('farm_work_category')
+		self.list('farm_work')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				category = self.service('common').one('farm_work_category', id=value['category_id'])
+				self.data['list'][key]['category'] = category['name']
+				method = self.service('common').one('farm_work_method', id=value['method_id'])
+				self.data['list'][key]['method'] = method['name']
+				land = self.service('common').one('farm_work_land', id=value['land_id'])
+				self.data['list'][key]['land'] = land['name']
+		self.show('list')
+
+class work_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/work/work'
+			,label = (u'劳作时间',u'劳作类别',u'劳作方式',u'劳作用量',u'劳作地块',u'图像记录')
+			,update = ('workdate-date-required','category_id-select-required-method_id','method_id-select-required--category_id','amount-input-required','land_id-select-required','pic-pic-required')
+			,update_category_id = self.service('common').list('farm_work_category')
+			,update_method_id = self.service('common').list('farm_work_method')
+			,update_land_id = self.service('common').list('farm_work_land')
+		)
+		self.one('farm_work')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('farm_work')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('farm_work')
+
+class method_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'劳作方法'
+			,path = '/work/method'
+			,width = '800'
+			,height = '300'
+			,add = False
+			,edit = False
+			,search = (('label-1','cdate-time-start','cdate-time-end','category_id-select-','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'劳作分类',u'劳作内容'))
+			,thead = (u'劳作内容', u'劳作分类', u'更新时间')
+			,tbody = ('name', 'category', 'cdate')
+			,state = False
+		)
+		self.data['common']['search_category_id-select-'] = self.service('common').list('farm_work_category')
+		self.list('farm_work_method')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				category = self.service('common').one('farm_work_category', id=value['category_id'])
+				self.data['list'][key]['category'] = category['name']
+		self.show('list')
+
+class method_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/work/method'
+			,label = (u'劳作内容',u'劳作分类')
+			,update = ('name-input-required','category_id-select-required')
+			,update_category_id = self.service('common').list('farm_work_category')
+		)
+		self.one('farm_work_method')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('farm_work_method')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('farm_work_method')
+
+class category_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'劳作分类'
+			,path = '/work/category'
+			,width = '600'
+			,height = '300'
+			,add = False
+			,edit = False
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'选择农场',u'分类名称'))
+			,thead = (u'分类名称', u'更新时间')
+			,tbody = ('name', 'cdate')
+			,state = False
+		)
+		self.list('farm_work_category')
+		self.show('list')
+
+class category_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/work/category'
+			,label = (u'分类名称')
+			,update = ('name-input-required')
+		)
+		self.one('farm_work_category')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('farm_work_category')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('farm_work_category')
+
+
+class land_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			name = u'地块'
+			,path = '/work/land'
+			,width = '600'
+			,height = '300'
+			,add = False
+			,edit = False
+			,search = (('label-1','cdate-time-start','cdate-time-end','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'地块名称'))
+			,thead = (u'地块名称', u'更新时间')
+			,tbody = ('name', 'cdate')
+			,state = False
+		)
+		self.list('farm_work_land')
+		self.show('list')
+
+class land_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.set(
+			path = '/work/land'
+			,label = (u'地块名称',)
+			,update = ('name-input-required',)
+		)
+		self.one('farm_work_land')
+		self.show('update')
+	@Web.auth
+	@Web.setting
+	def post(self):
+		self.update('farm_work_land')
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		self.drop('farm_work_land')

+ 94 - 0
conf/dev.conf

@@ -0,0 +1,94 @@
+[base]
+
+[setting]
+;农场名称
+name				= 新农宝盒云端服务
+;农场id
+farm				= 1
+;农场站点
+site				= http://www.xinnongbaohe.com/
+copyright			= 2017 xingnongbaohe.com v1.0.0
+
+[db]
+rdb					= postgresql
+tsdb				= influxdb
+
+[postgresql]
+;createdb -h localhost -p 5432 -U postgres xinnongbaohe_zeus
+;CREATE DATABASE xinnongbaohe_zeus WITH OWNER = postgres ENCODING = "UTF8"
+host				= 0.0.0.0
+port				= 5432
+username			= postgres
+password			= 123456
+dbname				= xinnongbaohe_zeus
+prefix				= demeter
+;允许自动建表
+create				= True
+
+[influxdb]
+host                = 0.0.0.0
+port                = 8086
+username            = root
+password            = root
+dbname              = xinnongbaohe
+prefix              = demeter
+
+[redis]
+host				= 0.0.0.0
+password			= dm_redis_123
+port				= 6379
+name				= eros
+prefix				= eros_
+
+[modbus]
+host				= 192.168.33.10
+port				= 1152
+
+[mqtt]
+host				= 0.0.0.0
+port				= 1883
+username			= admin
+password			= public
+timeout				= 60
+;topic定义
+topic				= method/type/gateway/device
+sub					= pic,sensor,control,power
+
+;后台配置
+[admin]
+port				= 8087
+debug				= True
+;请求的buffersize
+max_buffer_size		= 210763776
+;子进程
+process				= 0
+;定义后台父级菜单
+menu_parent			= 农场管理:&#xe62e;,设备管理:&#xe62c;,配置管理:&#xe614;,网站管理:&#xe64a;
+;定义后台子级菜单
+menu_child			= 农场管理:/farm/farm,用户管理:/farm/user,产品管理:/farm/product,地块管理:/work/land,农事管理:/work/work,溯源批次:/origin/batch,消息提醒:/msg/msg;网关列表:/device/gateway,设备列表:/device/info;产品配置:/setting/product,服务配置:/setting/server,设备类型:/setting/device_type,硬件类型:/hardware/type,MODBUS命令码:/setting/modbus_code;网站资料设置:/web/set,帮助分类:/web/help_category,发布帮助内容:/web/help,文章分类:/web/category,发布内容文章:/web/article,菜单管理:/web/menu
+
+;cookie
+cookie_secret       = 61oETzKXQAGaYekL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=
+login_url           = /user/login
+;是否使用安全cookie
+xsrf_cookies        = True
+
+;前台配置
+[front]
+port				= 8088
+debug				= True
+max_buffer_size		= 210763776
+process				= 0
+url					= http://192.168.33.10:8088/device
+qrcode				= http://pan.baidu.com/share/qrcode?w=300&h=300&url=
+mobile				= True
+
+;网站前台配置
+[web]
+port                = 8089
+debug               = True
+max_buffer_size     = 210763776
+process             = 0
+url                 = http://www.xinnongbaohe.com/
+farmurl             = http://farm.xinnongbaohe.com/?id=
+originurl           = http://s.xinnongbaohe.com/?id=

+ 69 - 0
conf/env.conf

@@ -0,0 +1,69 @@
+[base]
+
+[setting]
+name				= 新农宝盒
+;园区默认id,如有cookie,此处的值会自动变成cookie的值
+farm				= 1
+site				= http://www.xinnongbaohe.com/
+copyright			= 2017 xingnongbaohe.com v1.0.0
+
+[db]
+rdb                 = postgresql
+tsdb                = influxdb
+
+[postgresql]
+host				= iot-pgsql
+port				= 5432
+username			= postgres
+password			= 123456
+dbname				= xinnongbaohe
+prefix				= demeter
+;允许自动建表
+create				= True
+
+[influxdb]
+host                = iot-influx
+port                = 8086
+username            = root
+password            = root
+dbname              = xinnongbaohe
+prefix              = demeter
+
+[redis]
+host				= iot-redis
+password			= dm_redis_123
+port				= 6379
+name				= eros
+prefix				= eros_
+
+[mqtt]
+host				= iot-emq
+port				= 1883
+username			= admin
+password			= public
+timeout				= 60
+;topic定义
+topic				= method/type/gateway/device
+sub					= pic,sensor,control,power,status,log
+
+;后台配置
+[admin]
+port				= 8087
+debug				= True
+;请求的buffersize
+max_buffer_size		= 210763776
+;子进程
+process				= 0
+;top菜单的数据来源
+top 				= farm
+
+;前台配置
+[front]
+port				= 8088
+debug				= True
+max_buffer_size		= 210763776
+process				= 0
+;url					= http://www.xinnongbaohe.com:8088/device
+url					= http://v3.xinnongbaohe.com/device
+qrcode				= http://pan.baidu.com/share/qrcode?w=300&h=300&url=
+mobile				= True

+ 24 - 0
conf/temp.conf

@@ -0,0 +1,24 @@
+[valve]
+100100 = 0
+100101 = 1
+100102 = 1
+100103 = 0
+100104 = 0
+100105 = 1
+100106 = 0
+100107 = 0
+100108 = 0
+100109 = 0
+
+[blower]
+100110 = 0
+100111 = 0
+100112 = 0
+100113 = 0
+100114 = 1
+100115 = 0
+100116 = 0
+100117 = 0
+100118 = 0
+100119 = 1
+

+ 19 - 0
cron.py

@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web
+    name:admin.py
+    author:rabin
+"""
+from demeter.core import *
+
+param = {}
+param['method'] = 'm'
+Demeter.getopt(param)
+
+Demeter.echo(Demeter.option['method'])
+
+method = Demeter.option['method']
+
+cron = Demeter.service(method, 'cron')
+while(True):
+	cron.handle()

+ 10 - 0
front.py

@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web
+    name:admin.py
+    author:rabin
+"""
+from demeter.core import *
+
+if __name__ == "__main__":
+	Demeter.webInit('front')

+ 5 - 0
front/__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter init
+    author:rabin
+"""

+ 4 - 0
front/main.py

@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+from demeter.web import *
+import front.page
+Web.start(application=[front.page,])

+ 1 - 0
front/page/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 463 - 0
front/page/__load__.py

@@ -0,0 +1,463 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter load
+    author:rabin
+"""
+from demeter.web import *
+from datetime import *
+
+class Load(Base):
+	KEYS = ('user', 'farm')
+
+	def setting(self):
+		self.user()
+
+	def user(self):
+		ajax = self.input('ajax')
+		if ajax:
+			self.data['ajax'] = True
+		else:
+			self.data['ajax'] = False
+		self.data['auth'] = True
+		if 'user' in self.data['setting'] and self.data['setting']['user']:
+			self.data['setting']['userInfo'] = self.service('common').one('farm_user', id=self.data['setting']['user'].decode())
+			self.data['setting']['farm'] = self.data['setting']['userInfo']['farm_id']
+		else:
+			return
+
+		if 'farm' in self.data['setting'] and self.data['setting']['farm']:
+			self.data['setting']['farmInfo'] = self.service('common').one('farm', id=self.data['setting']['farm'])
+			self.data['setting']['farmInfo']['gateways'] = ''
+			if self.data['setting']['farmInfo']['gateway']:
+				self.data['setting']['farmInfo']['gateways'] = tuple(eval(self.data['setting']['farmInfo']['gateway']))
+		self.data['setting']['msgNum'] = len(self.service('common').list('msg', search={'status':False, "farm_id":self.data['setting']['farm']}, limit='0,100'))
+		if self.data['setting']['msgNum'] > 99:
+			self.data['setting']['msgNum'] = str(99) + '+'
+
+		#self.data['setting']['msg'] = self.service('common').one('msg', type_id=3)
+		self.data['setting']['web'] = Demeter.config['web']['url']
+		self.data['setting']['farmurl'] = Demeter.config['web']['farmurl']
+		cur = 'main'
+		if '/' in self.request.uri:
+			temp = self.request.uri.split('/')
+			slen = len(temp)
+			if slen > 1 and temp[1]:
+				cur = temp[1]
+		self.data['setting']['cur'] = cur
+
+
+class Device(object):
+	@staticmethod
+	def init(self, search={}):
+		type = self.input('type')
+		id = self.input('id')
+		if not id:
+			self.view('404.html')
+			return (None, type)
+		if 'stat' in self.request.uri:
+			self.data['device_cur'] = 'stat'
+		elif 'log' in self.request.uri:
+			self.data['device_cur'] = 'log'
+		elif 'pic' in self.request.uri:
+			self.data['device_cur'] = 'pic'
+		else:
+			self.data['device_cur'] = 'data'
+		self.data['show'] = True
+		self.data['url'] = Device.url('type='+type+'&id=' + id)
+		if not search:
+			search = {}
+		self.data['info'] = {}
+		self.data['device'] = []
+
+		if type == 'gateway':
+			self.data['info'] = self.service('common').one('device_gateway', id=id)
+			if not self.data['info']:
+				self.view('404.html')
+				return (None, type)
+			search['gateway_id'] = id
+			self.data['device'] = Device.get(self, search=search)
+			if self.data['device_cur'] in ('stat', 'log'):
+				self.data['pic'] = Device.get(self, search={'gateway_id':id, 'hardware_type':6})
+
+		elif type == 'page':
+			self.data['info'] = self.service('common').one('device_page', id=id)
+			if not self.data['info']:
+				self.view('404.html')
+				return (None, type)
+			search['page_id'] = id
+			self.data['group'] = self.service('common').list('device_group', search={'page_id':id}, order='inorder asc,cdate desc')
+			if self.data['group']:
+				Device.group(self, search)
+		else:
+			self.data['info'] = self.data['setting']['farmInfo']
+			if not self.data['info']:
+				self.view('404.html')
+				return (None, type)
+			self.data['device'] = Device.get(self, search=search)
+
+		if not self.data['device'] or not self.data['info']:
+			self.view('404.html')
+			return (None, type)
+		self.data['input'] = {}
+		self.data['input']['type'] = type
+		self.data['input']['id'] = id
+		return (id, type)
+	@staticmethod
+	def set(self):
+		if 'condition' in self.request.uri:
+			self.data['set_cur'] = 'condition'
+		elif 'timing' in self.request.uri:
+			self.data['set_cur'] = 'timing'
+		elif 'loop' in self.request.uri:
+			self.data['set_cur'] = 'loop'
+		else:
+			self.data['set_cur'] = 'mul'
+		self.data['url'] = Device.setUrl()
+	@staticmethod
+	def setCronOper(self):
+		self.data['oper'] = ({'id':1, 'name':'打开'},{'id':2, 'name':'关闭'})
+		self.data['looptype'] = ({'id':1, 'name':'按日周期', 'list':'每天'},{'id':2, 'name':'按周周期', 'list':'每周'}, {'id': 3, 'name': '按月周期', 'list':'每月'})
+		self.data['opers'] = ({'id':1, 'name':'无操作'}, {'id':2, 'name':'打开'},{'id':3, 'name':'关闭'})
+
+		self.data['week'] = ({'id':1, 'name':'周一'},{'id':2, 'name':'周二'}, {'id': 3, 'name': '周三'}, {'id': 4, 'name': '周四'}, {'id': 5, 'name': '周五'}, {'id': 6, 'name': '周六'}, {'id': 7, 'name': '周日'})
+
+		self.data['condition'] = ({'id':1, 'name':'大于', 'exp':'>'}, {'id':2, 'name':'小于', 'exp':'<'},{'id':3, 'name':'等于','exp':'='})
+
+		self.data['day'] = []
+		for i in range(31):
+			i = i + 1
+			self.data['day'].append({'id':i, 'name':i})
+
+		self.data['hour'] = []
+		for i in range(24):
+			i = i + 1
+			self.data['hour'].append({'id':i, 'name':Demeter.hour(i)})
+
+		self.data['minute'] = []
+		for i in range(60):
+			self.data['minute'].append({'id':i, 'name':Demeter.hour(i)})
+
+	@staticmethod
+	def get(self, search):
+		if 'id--ins' in search and search['id--ins']:
+			search['id--ins'] = tuple(eval(search['id--ins']))
+			#order='inorder asc, type_id asc,udate asc,id asc'
+		return self.service('common').list('device_info', state=True, search=search, order='inorder asc, type_id asc,udate asc,hardware_id asc', limit='0,10000')
+
+	@staticmethod
+	def getByGateway(self, search={}):
+		device = Device.get(self, search=search)
+		result = {}
+		if device:
+			for value in device:
+				if value['gateway_id'] not in result:
+					result[value['gateway_id']] = []
+				result[value['gateway_id']].append(value)
+		return result
+
+	@staticmethod
+	def data(self):
+		id, type = Device.init(self)
+		if not id:
+			return
+		method = type + '_data'
+		if hasattr(Device, method):
+			func = getattr(Device, method)
+			data = func(self, id)
+		else:
+			self.view('404.html')
+			return
+		#self.data = dict(self.data, **data)
+
+	@staticmethod
+	def gateway_data(self, id):
+		power = []
+		sensor = []
+		control = []
+		self.data['stat'] = {}
+		self.data['pic'] = []
+		self.data['camera'] = []
+		if self.data['device']:
+			for value in self.data['device']:
+				if value['type_id']:
+					type_info = self.service('common').one('setting_device_type', id=value['type_id'])
+					value['unit'] = type_info['unit']
+					value['typeName'] = type_info['name']
+				# 获取网关状态
+				if value['hardware_type'] == 5:
+					power.append(value)
+				# 获取电源设备
+				if value['hardware_type'] == 4:
+					#value['value'] = Demeter.exp(value['out_exp'], value['value'])
+					power.append(value)
+					"""
+					if not self.data['stat']:
+						self.data['stat'] = value
+					"""
+				# 获取采集设备
+				if value['hardware_type'] == 2:
+					#value['value'] = Demeter.exp(value['out_exp'], value['value'])
+					sensor.append(value)
+					if not self.data['stat']:
+						self.data['stat'] = value
+				# 获取控制设备
+				if value['hardware_type'] == 3:
+					if value['value'] == '1.0':
+						value['value'] = '1'
+					control.append(value)
+				# 获取摄像头
+				if value['hardware_type'] == 6:
+					value['value'] = value['value'] + '?' + Demeter.date(Demeter.time(), '%Y%m%d%H')
+					self.data['pic'].append(value)
+				# 获取摄像机
+				if value['hardware_type'] == 7:
+					self.data['camera'].append(value)
+		"""
+		if power:
+			power.reverse()
+		"""
+		self.data['list'] = ({'name': '设备状态', 'device': power}, {'name': '数据采集', 'device': sensor}, {'name': '实时设备控制', 'device': control})
+
+	@staticmethod
+	def page_data(self, id):
+		self.data['list'] = self.data['group']
+
+	@staticmethod
+	def group(self, search):
+		self.data['show'] = False
+		self.data['pic'] = []
+		self.data['camera'] = []
+		self.data['stat'] = {}
+		for key, value in enumerate(self.data['group']):
+			if value['devices']:
+				search['id--ins'] = value['devices']
+				if self.data['device_cur'] == 'stat':
+					search['hardware_type--ins'].append(6)
+				self.data['group'][key]['device'] = Device.get(self, search=search)
+				if self.data['group'][key]['device']:
+					for k, v in enumerate(self.data['group'][key]['device']):
+						if v['hardware_type'] == 2 or v['hardware_type'] == 4:
+							#v['value'] = Demeter.exp(v['out_exp'], v['value'])
+							if v['hardware_type'] == 2 and self.data['info']['stat'] == True and not self.data['stat']:
+								self.data['stat'] = v
+							self.data['show'] = True
+						if v['type_id'] > 0:
+							type_info = self.service('common').one('setting_device_type', id=v['type_id'])
+							self.data['group'][key]['device'][k]['unit'] = type_info['unit']
+							self.data['group'][key]['device'][k]['typeName'] = type_info['name']
+
+						if self.data['device_cur'] == 'data':
+							if v['hardware_type'] == 6:
+								slen = len(self.data['group'][key]['device'])
+								if slen < 2:
+									del self.data['group'][key]['device']
+									v['name'] = self.data['group'][key]['name']
+								v['value'] = v['value'] + '?' + Demeter.date(Demeter.time(), '%Y%m%d%H')
+								self.data['pic'].append(v)
+							if v['hardware_type'] == 7:
+								slen = len(self.data['group'][key]['device'])
+								if slen < 2:
+									del self.data['group'][key]['device']
+									v['name'] = self.data['group'][key]['name']
+								self.data['camera'].append(v)
+						if self.data['device_cur'] == 'stat':
+							if v['hardware_type'] == 6:
+								self.data['pic'] = True
+							else:
+								self.data['device'].append(v)
+						else:
+							self.data['device'].append(v)
+
+	@staticmethod
+	def pic(self):
+		id, type = Device.init(self, search={'hardware_type':6})
+		if not id:
+			return
+		state = Device.get(self, search={'hardware_type--ins':(2,4)})
+		if state:
+			self.data['show'] = True
+		device = self.input('device')
+		if not device:
+			#如果没有,就获取第一个
+			self.data['deviceInfo'] = self.data['device'][0]
+		else:
+			self.data['deviceInfo'] = self.service('common').one('device_info', id=device)
+
+		if not self.data['deviceInfo']:
+			self.view('404.html')
+			return
+		self.data['pic'] = self.service('common').list('device_pic', search={'device_id':self.data['deviceInfo']['id']}, page={'num':12}, order='sdate desc')
+		if self.data['pic']:
+			for key, value in enumerate(self.data['pic']):
+				self.data['pic'][key]['cdates'] = Demeter.date(value['sdate'])
+
+	@staticmethod
+	def statBase(self, deviceInfo={}, device = False):
+		
+		if not device:
+			device = self.input('device')
+		method = self.input('method', 'maxmin')
+		if not device:
+			#如果没有,就获取sensor的第一个
+			self.data['deviceInfo'] = deviceInfo
+		else:
+			self.data['deviceInfo'] = self.service('common').one('device_info', id=device)
+
+		if not self.data['deviceInfo']:
+			self.view('404.html')
+			return
+		self.data['type'] = self.service('common').one('setting_device_type', id=self.data['deviceInfo']['type_id'])
+
+		model = Demeter.model('data', 'tsdb')
+		self.data['group'] = model.dateConfig()
+
+		search_group = self.input('group')
+		search_start = self.input('start')
+		search_end = self.input('end')
+
+		search = {}
+		search['device'] = self.data['deviceInfo']['id']
+		if search_group:
+			search['group'] = search_group
+		else:
+			search['group'] = '1'
+		if search_start:
+			search['start'] = search_start
+		if search_end:
+			search['end'] = search_end
+		search['type'] = type
+		search['id'] = id
+		self.data['search'] = search
+		self.data['statList'] = model.getData(method, search, self.data['deviceInfo'])
+		return self.data
+
+	@staticmethod
+	def stat(self):
+		id, type = Device.init(self, search={'hardware_type--ins':[2,4]})
+		if not id:
+			return
+		device = self.input('device')
+		Device.statBase(self, self.data['device'][0], device)
+		self.data['url'] = Device.url('type='+type+'&id=' + id)
+
+	@staticmethod
+	def out(self):
+		id, type = Device.init(self, search={'hardware_type--ins':[2,4]})
+		if not id:
+			return
+
+		out = self.input('out')
+		if not out:
+			device = self.inputs('device')
+			data = []
+			header = []
+			datas = {}
+			header.append('日期')
+			for i in device:
+				result = Device.statBase(self, self.data['device'][0], i)
+				if result['statList']:
+					header.append(result['deviceInfo']['name'])
+
+					for t,v in result['statList'][0]['data']['rows']:
+						if t not in datas:
+							datas[t] = [t,v]
+						else:
+							datas[t].append(v)
+
+			self.data['url'] = Device.url('type='+type+'&id=' + id)
+
+			if datas:
+				import csv,codecs
+				import uuid
+
+				dates = sorted(datas.keys())
+				newData = []
+				for i in dates:
+					newData.append(datas[i])
+				data = newData
+				data.insert(0, header)
+				fileData = data
+
+				day = str(date.today())
+				day = day.split('-')
+				file_name =  self.data['info']['name'] + '.csv'
+				file_path = day[0] + '/' + day[1] + '/' + day[2]
+				file_path = File.mkdirs(os.path.join(Demeter.path, 'runtime','upload', file_path)) + '/' + file_name
+				with open(file_path, 'w') as f:
+					f.write(codecs.BOM_UTF8)
+					writer = csv.writer(f)
+					for row in fileData:
+						writer.writerow(row)
+				url = self.request.protocol + "://" + self.request.host
+				file_path = url + file_path.replace(Demeter.path + 'runtime', '')
+				self.set_header("Content-Type","text/csv,charset=UTF-8")
+				self.set_header('Content-Disposition', 'attachment; filename=' + file_name)
+				self.redirect(file_path)
+
+		else:
+			self.data['search'] = {}
+
+	@staticmethod
+	def log(self):
+		id, type = Device.init(self)
+		if not id:
+			return
+		ids = []
+		device_type = {}
+		device_hard = {}
+		device_list = []
+		for value in self.data['device']:
+			ids.append(value['id'])
+			value['cdates'] = Demeter.date(value['udate'], '%Y.%m.%d')
+			if value['type_id']:
+				info = self.service('common').one('setting_device_type', id=value['type_id'])
+				if info['id'] not in device_type:
+					device_type[info['id']] = {'name':info['name'], 'num':1, 'cdate':value['cdates']}
+				else:
+					num = device_type[info['id']]['num'] + 1
+					device_type[info['id']] = {'name':info['name'], 'num':num, 'cdate':value['cdates']}
+			elif '网关' in value['name']:
+				value['name'] = '通讯网关'
+				device_list.append({'name':value['name'], 'num':1, 'cdate':value['cdates']})
+			elif value['hardware_type'] > 0:
+				info = self.service('common').one('hardware_type', id=value['hardware_type'])
+				if info['id'] not in device_hard:
+					device_hard[info['id']] = {'name':info['name'], 'num':1, 'cdate':value['cdates']}
+				else:
+					num = device_hard[info['id']]['num'] + 1
+					device_hard[info['id']] = {'name':info['name'], 'num':num, 'cdate':value['cdates']}
+		if device_hard:
+			for key, value in device_hard.items():
+				device_list.append({'name':value['name'], 'num':value['num'], 'cdate':value['cdate']})
+
+		if device_type:
+			for key, value in device_type.items():
+				device_list.append({'name':value['name'], 'num':value['num'], 'cdate':value['cdate']})
+		
+
+		self.data['list'] = device_list
+		# 获取设备日志
+		self.data['logs'] = self.service('common').list('msg', state=True, search={'device_id-input-ins':ids}, page={'num':6})
+		if self.data['logs']:
+			for key, value in enumerate(self.data['logs']):
+				type_info = self.service('common').one('msg_type', id=value['type_id'])
+				self.data['logs'][key]['type'] = type_info['name']
+				self.data['logs'][key]['cdates'] = Demeter.date(value['cdate'])
+	@staticmethod
+	def url(param):
+		config = {}
+		config['data'] = '/device/data?' + param;
+		config['stat'] = '/device/stat?' + param;
+		config['log'] = '/device/log?' + param;
+		config['pic'] = '/device/pic?' + param;
+		config['out'] = '/device/out?' + param + '&out=1';
+		return config
+
+	@staticmethod
+	def setUrl():
+		config = {}
+		config['mul'] = '/device/set_mul'
+		config['timing'] = '/device/set_timing'
+		config['loop'] = '/device/set_loop'
+		config['condition'] = '/device/set_condition'
+		return config

+ 764 - 0
front/page/device.py

@@ -0,0 +1,764 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:device.py
+    author:rabin
+"""
+from .__load__ import *
+# 首页
+class index_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		# 获取网关列表
+		self.data['gateway'] = self.service('common').list('device_gateway', state=True, search={'farm_id':self.data['setting']['farm']})
+		# 获取页面
+		self.data['page'] = self.service('common').list('device_page', order='inorder asc,cdate desc', search={'farm_id':self.data['setting']['farm']})
+		self.view("device/index.html")
+
+#批量控制
+class mul_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['list'] = self.service('common').list('device_mul', search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			model = Demeter.model('device_mul_queue')
+			for key, value in enumerate(self.data['list']):
+				model.status.ins((2,3))
+				model.mul_id = value['id']
+				info = model.select()
+				#self.data['list'][key]['oper'] = ''
+				if info:
+					for v in info:
+						if v['oper']:
+							self.data['list'][key]['oper'] = v['oper']
+					
+		self.view("device/mul.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		value = self.input('value')
+		if id:
+			info = self.service('common').one('device_mul', id=id)
+			if info:
+				update = {}
+				update['value'] = value
+				if info['device_type'] == 1:
+					if value == '1':
+						update['oper'] = '批量启动中'
+					else:
+						update['oper'] = '批量关闭中'
+				else:
+					if value == '1':
+						update['oper'] = '批量升起中'
+					elif value == '2':
+						update['oper'] = '批量下降中'
+					elif value == '5':
+						update['oper'] = '批量停止中'
+						
+				self.service('common').update('device_mul', id, update, cdate=False)
+				if info['devices']:
+					devices = tuple(eval(info['devices']))
+					for device in devices:
+						Demeter.service('device').switch(device, switch=value, mul=id)
+			self.out('yes', {'id':id})
+		else:
+			self.out('no')
+
+#大屏幕
+class screen_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		device = self.input('device')
+
+		# 获取摄像头图片
+		self.data['camera'] = Device.get(self, search={'hardware_type':6,'farm_id':self.data['setting']['farm']})
+		# 获取当前数据
+		self.data['device'] = Device.get(self, search={'id--ins':self.data['setting']['farmInfo']['gateway'], 'hardware_type--ins':(2,4,5),'farm_id':self.data['setting']['farm']})
+		deviceInfo = {}
+		if self.data['device']:
+			for key, value in enumerate(self.data['device']):
+				if value['type_id'] > 0:
+					type_info = self.service('common').one('setting_device_type', id=value['type_id'])
+					self.data['device'][key]['unit'] = type_info['unit']
+					self.data['device'][key]['typeName'] = type_info['name']
+					if not device and not deviceInfo:
+						deviceInfo = self.data['device'][key]
+		self.data['list'] = ({'name':'实时数据监测', 'device':self.data['device']},)
+
+		Device.statBase(self, deviceInfo)
+		log_search = {}
+		if device:
+			log_search['device_id'] = device
+		else:
+			log_search['device_id--ins'] = self.data['setting']['farmInfo']['gateways']
+		log_search['device_id--ins'] = self.data['setting']['farmInfo']['gateways']
+		log_search['type_id'] = 2
+		log_search['farm_id'] = self.data['setting']['farm']
+		# 获取设备日志
+		self.data['logs'] = self.service('common').list('msg', search=log_search, limit='0,1')
+		if self.data['logs']:
+			for key, value in enumerate(self.data['logs']):
+				type_info = self.service('common').one('msg_type', id=value['type_id'])
+				self.data['logs'][key]['type'] = type_info['name']
+				self.data['logs'][key]['cdates'] = Demeter.date(value['cdate'])
+		self.data['info'] = self.data['setting']['farmInfo']
+		if not self.data['info']['welcome']:
+			self.data['info']['welcome'] = self.data['info']['name']
+
+		self.data['noset'] = True
+		self.data['stat'] = True
+		self.view("device/screen.html")
+
+#大屏幕设置
+class screen_set_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['info'] = self.data['setting']['farmInfo']
+		self.data['info']['devices'] = self.data['info']['gateway']
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type--ins' : (2,4,5),'farm_id':self.data['setting']['farm']})
+		self.view("device/alert/screen.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['welcome'] = self.input('update_name')
+		update['gateway'] = self.inputs('update_devices')
+		if not update['gateway']:
+			self.out(u'请选择设备')
+			return
+		update['gateway'] = str(update['gateway'])
+		if update['welcome']:
+			value = update['welcome']
+		else:
+			value = self.data['setting']['farmInfo']['name']
+		key = 'update/w/' + id
+		from demeter.mqtt import Pub
+		pub = Pub()
+		pub.push(key, value)
+		state = self.service('common').update('farm', id, update)
+		self.out('yes', {'id':state})
+
+#特殊的大屏幕
+class screens_path(Load):
+	@Web.setting
+	def get(self):
+		farm = self.input('ids', '2,3,4')
+		self.data['farm'] = farm
+		farm = farm.split(',')
+		device = self.input('device')
+		farmInfo = self.service('common').one('farm', id=farm[0])
+		# 获取摄像头图片
+		#self.data['camera'] = Device.get(self, search={'hardware_type':6,'farm_id--ins':farm})
+		self.data['camera'] = []
+		# 获取当前数据
+		deviceList = Device.get(self, search={'hardware_type--ins':(2,4,5),'farm_id--ins':farm})
+		self.data['device'] = {}
+		for v in farm:
+			self.data['device'][v] = []
+		deviceInfo = {}
+		devices = []
+		if deviceList:
+			for key, value in enumerate(deviceList):
+				if value['type_id'] > 0:
+					type_info = self.service('common').one('setting_device_type', id=value['type_id'])
+					value['unit'] = type_info['unit']
+					value['typeName'] = type_info['name']
+					self.data['device'][str(value['farm_id'])].append(value)
+					devices.append(value['id'])
+					if not device and not deviceInfo:
+						deviceInfo = value
+				else:
+					self.data['device'][str(value['farm_id'])].append(value)
+					devices.append(value['id'])
+		self.data['deviceList'] = {}
+		for v in farm:
+			farmData = self.service('common').one('farm', id=int(v))
+			if farmData:
+				self.data['deviceList'][v] = ({'name':farmData['name'] + '实时检测', 'device':self.data['device'][v]},)
+
+		Device.statBase(self, deviceInfo)
+		log_search = {}
+		if device:
+			log_search['device_id'] = device
+		else:
+			log_search['device_id--ins'] = devices
+		log_search['device_id--ins'] = devices
+		log_search['type_id'] = 2
+		log_search['farm_id--ins'] = farm
+		# 获取设备日志
+		self.data['logs'] = self.service('common').list('msg', search=log_search, limit='0,1')
+		if self.data['logs']:
+			for key, value in enumerate(self.data['logs']):
+				type_info = self.service('common').one('msg_type', id=value['type_id'])
+				self.data['logs'][key]['type'] = type_info['name']
+				self.data['logs'][key]['cdates'] = Demeter.date(value['cdate'])
+		self.data['info'] = farmInfo
+		if not self.data['info']['welcome']:
+			self.data['info']['welcome'] = self.data['info']['name']
+		self.data['info']['welcome'] = '保定清苑农业局物联网监测系统'
+		self.data['noset'] = True
+		self.data['stat'] = True
+		self.view("device/screens.html")
+
+#获取设备数据和设备控制
+class data_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Device.data(self)
+		if 'stat' in self.data and self.data['stat']:
+			Device.statBase(self, self.data['stat'])
+		self.view("device/data.html")
+
+#获取图像
+class pic_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Device.pic(self)
+		self.view("device/pic.html")
+
+#数据统计
+class stat_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Device.stat(self)
+		self.view("device/stat.html")
+
+#数据导出
+class out_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		#Device.out(self)
+		self.view("device/out.html")
+
+#设备日志
+class log_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Device.log(self)
+		self.view("device/logs.html")
+
+#设备分组
+class group_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		# 获取页面
+		self.data['page'] = self.service('common').list('device_page', order='inorder asc,cdate desc', search={'farm_id':self.data['setting']['farm']})
+		if self.data['page']:
+			for key, value in enumerate(self.data['page']):
+				self.data['page'][key]['group'] = self.service('common').list('device_group', search={'page_id':value['id'],'farm_id':self.data['setting']['farm']} , order='inorder asc,cdate desc')
+
+				if self.data['page'][key]['group']:
+					for groupk, groupv in enumerate(self.data['page'][key]['group']):
+						self.data['page'][key]['group'][groupk]['device'] = Device.get(self, search={'id--ins':groupv['devices'],'farm_id':self.data['setting']['farm']})
+		self.view("device/group.html")
+
+#更新设备的上下限
+class update_device_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('device_id')
+		if id:
+			Device.data(self)
+		else:
+			id = self.input('id')
+		self.data['set'] = {}
+		if id:
+			self.data['set'] = self.service('common').one('device_info', id=id)
+			if self.data['set'] and self.data['set']['type_id'] > 0:
+				self.data['type'] = self.service('common').one('setting_device_type', id=self.data['set']['type_id'])
+		self.view("device/alert/device.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['max'] = self.input('update_max')
+		update['min'] = self.input('update_min')
+		if not update['max'] and not update['min']:
+			self.out(u'请至少输入一个上限或者下限')
+			return
+		if not update['min']:
+			del update['min']
+		if not update['max']:
+			del update['max']
+		state = self.service('common').update('device_info', id, update)
+		self.out('yes', {'id':state})
+
+
+#更新页面
+class update_page_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		#self.data['ico'] = ('cj', 'kz', 'syt', 'wg', 'pl', 'dpm', 'fz', 'zn')
+		self.data['ico'] = ('cj', 'kz', 'syt')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('device_page', id=id)
+		else:
+			self.data['info']['ico'] = self.data['ico'][0]
+		self.view("device/alert/page.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+		update['ico'] = self.input('update_ico')
+		update['inorder'] = self.input('update_inorder', 0)
+		if not update['inorder']:
+			update['inorder'] = 0
+		update['inorder'] = int(update['inorder'])
+		update['stat'] = self.input('update_stat')
+		if not update['name']:
+			self.out(u'请输入页面名称')
+			return
+		if not update['ico']:
+			self.out(u'请选择图标')
+			return
+		if update['stat']:
+			update['stat'] = True
+		else:
+			update['stat'] = False
+		state = self.service('common').update('device_page', id, update)
+		self.out('yes', {'id':state})
+
+#更新分组
+class update_group_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		page = self.input('page')
+		self.data['page'] = self.service('common').one('device_page', id=page)
+
+		id = self.input('id')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('device_group', id=id)
+
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'farm_id':self.data['setting']['farm']})
+		self.view("device/alert/group.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['page_id'] = self.input('update_page_id')
+		update['name'] = self.input('update_name')
+		update['devices'] = self.inputs('update_devices')
+		update['inorder'] = self.input('update_inorder', 0)
+		if not update['inorder']:
+			update['inorder'] = 0
+		update['inorder'] = int(update['inorder'])
+		if not update['name']:
+			self.out(u'请输入分组名称')
+			return
+		if not update['devices']:
+			self.out(u'请选择设备')
+			return
+		update['devices'] = str(update['devices'])
+		state = self.service('common').update('device_group', id, update)
+		self.out('yes', {'id':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.service('common').rDelete('device_group', id)
+		self.out('yes', {'state':state})
+
+#智能设置-批量设置
+class set_mul_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['name'] = '批量控制'
+		Device.set(self)
+		self.data['mul'] = self.service('common').list('device_mul', search={'farm_id':self.data['setting']['farm']})
+		if self.data['mul']:
+			for key, value in enumerate(self.data['mul']):
+				self.data['mul'][key]['device'] = Device.get(self, search={'id--ins':value['devices'],'farm_id':self.data['setting']['farm']})
+		self.view("device/set/mul.html")
+
+#更新批量控制
+class update_set_mul_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('device_mul', id=id)
+
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type' : 3,'farm_id':self.data['setting']['farm']})
+		self.data['type'] = ({'id':1, 'name':'开关'},{'id':2, 'name':'卷帘'})
+		self.view("device/alert/mul.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+		update['device_type'] = self.input('update_type')
+		update['devices'] = self.inputs('update_devices')
+		if not update['name']:
+			self.out(u'请输入名称')
+			return
+		if not update['device_type']:
+			self.out(u'请选择设备类型')
+			return
+		if not update['devices']:
+			self.out(u'请选择设备')
+			return
+		update['devices'] = str(update['devices'])
+		state = self.service('common').update('device_mul', id, update)
+		self.out('yes', {'id':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.service('common').rDelete('device_mul', id)
+		self.out('yes', {'state':state})
+
+#智能设置-定时设置
+class set_timing_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['name'] = '定时设置'
+		Device.set(self)
+		Device.setCronOper(self)
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type': 3,'farm_id':self.data['setting']['farm']})
+		self.data['list'] = self.service('common').list('device_set_timing', state=True, page={'num':10}, search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['device'] = []
+				if value['devices']:
+					device = Device.get(self, search={'id--ins':value['devices'],'farm_id':self.data['setting']['farm']})
+					if device:
+						self.data['list'][key]['device'] = device
+				self.data['list'][key]['oper'] = self.data['oper'][value['oper']-1]['name']
+
+				self.data['list'][key]['cdates'] = Demeter.date(value['cdate'])
+				self.data['list'][key]['zdates'] = Demeter.date(value['zdate'])
+
+				if value['status'] == 1:
+					self.data['list'][key]['status_text'] = '执行成功'
+				elif value['status'] == 2:
+					self.data['list'][key]['status_text'] = '执行失败'
+
+		self.view("device/set/timing.html")
+
+class update_set_timing_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		Device.setCronOper(self)
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('device_set_timing', id=id)
+			if self.data['info'] and self.data['info']['zdate']:
+				self.data['info']['zdate'] = Demeter.date(self.data['info']['zdate'])
+
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type' : 3,'farm_id':self.data['setting']['farm']})
+		self.view("device/alert/timing.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['devices'] = self.inputs('update_devices')
+		update['oper'] = self.input('update_oper')
+		update['zdate'] = self.input('update_zdate')
+		if not update['devices']:
+			self.out(u'请选择设备')
+			return
+		if not update['oper']:
+			self.out(u'请选择执行结果')
+			return
+		if not update['zdate']:
+			self.out(u'请选择执行时间')
+			return
+
+		update['devices'] = str(update['devices'])
+		state = self.service('common').update('device_set_timing', id, update)
+		self.out('yes', {'id':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.service('common').rDelete('device_set_timing', id)
+		self.out('yes', {'state':state})
+
+#智能设置-周期设置
+class set_loop_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['name'] = '周期设置'
+		Device.set(self)
+		Device.setCronOper(self)
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type': 3,'farm_id':self.data['setting']['farm']})
+		self.data['list'] = self.service('common').list('device_set_loop', page={'num':10}, search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['device'] = []
+				if value['devices']:
+					device = Device.get(self, search={'id--ins':value['devices'],'farm_id':self.data['setting']['farm']})
+					if device:
+						self.data['list'][key]['device'] = device
+				if value['looptype'] == 2:
+					value['loop'] = value['loop'].split(',')
+					loop = []
+					for v in self.data['week']:
+						if str(v['id']) in value['loop']:
+							loop.append(v['name'])
+					loop = ' '.join(loop) + ' '
+				elif value['looptype'] == 3:
+					loop = value['loop'].replace(',', ' ') + ' '
+				else:
+					loop = ''
+				self.data['list'][key]['loop'] = loop
+				self.data['list'][key]['oper'] = self.data['oper'][value['oper']-1]['name']
+				self.data['list'][key]['looptype'] = self.data['looptype'][value['looptype']-1]['list']
+				self.data['list'][key]['cdates'] = Demeter.date(value['cdate'])
+				self.data['list'][key]['hour'] = Demeter.hour(value['hour'])
+				self.data['list'][key]['minute'] = Demeter.hour(value['minute'])
+
+		self.view("device/set/loop.html")
+
+class update_set_loop_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		Device.setCronOper(self)
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('device_set_loop', id=id)
+
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type' : 3,'farm_id':self.data['setting']['farm']})
+		self.view("device/alert/loop.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['devices'] = self.inputs('update_devices')
+		update['oper'] = self.input('update_oper')
+		update['loop'] = self.input('update_loop')
+		update['hour'] = self.input('update_hour')
+		update['minute'] = self.input('update_minute')
+		update['looptype'] = self.input('update_looptype')
+		if not update['devices']:
+			self.out(u'请选择设备')
+			return
+		if not update['oper']:
+			self.out(u'请选择执行结果')
+			return
+		if not update['hour']:
+			self.out(u'请选择执行时间')
+			return
+		if not update['looptype']:
+			self.out(u'请选择执行时间')
+			return
+		if update['looptype'] != '1' and not update['loop']:
+			self.out(u'请选择执行时间')
+			return
+		update['devices'] = str(update['devices'])
+		state = self.service('common').update('device_set_loop', id, update)
+		self.out('yes', {'id':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		update = {}
+		update['status'] = state
+		state = self.service('common').update('device_set_loop', id, update)
+		self.out('yes', {'state':state})
+
+#智能设置-条件控制
+class set_condition_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['name'] = '条件控制'
+		Device.set(self)
+		Device.setCronOper(self)
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type': 3,'farm_id':self.data['setting']['farm']})
+		self.data['list'] = self.service('common').list('device_set_condition', state=True, page={'num':10}, search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['device'] = []
+				if value['devices']:
+					device = Device.get(self, search={'id--ins':value['devices'],'farm_id':self.data['setting']['farm']})
+					if device:
+						self.data['list'][key]['device'] = device
+				self.data['list'][key]['cdates'] = Demeter.date(value['cdate'])
+				self.data['list'][key]['oper'] = self.data['opers'][value['oper']-1]['name']
+				self.data['list'][key]['condition'] = self.data['condition'][value['condition']-1]['exp']
+				gateway = self.service('common').one('device_gateway', id=value['gateway_id'])
+				self.data['list'][key]['gatewayName'] = gateway['name']
+				device = self.service('common').one('device_info', id=value['device_id'])
+				if device:
+					self.data['list'][key]['deviceName'] = device['name']
+					type_info = self.service('common').one('setting_device_type', id=device['type_id'])
+					self.data['list'][key]['unit'] = type_info['unit']
+
+		self.view("device/set/condition.html")
+
+class update_set_condition_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		Device.setCronOper(self)
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('device_set_condition', id=id)
+
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type' : 3,'farm_id':self.data['setting']['farm']})
+		self.data['device_list'] = self.service('common').list('device_info', search={'hardware_type--ins' : (2,4),'gateway_id':self.data['gateway'][0]['id']})
+		self.view("device/alert/condition.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['devices'] = self.inputs('update_devices')
+		update['oper'] = self.input('update_oper')
+		update['gateway_id'] = self.input('update_gateway_id')
+		update['device_id'] = self.input('update_device_id')
+		update['condition'] = self.input('update_condition')
+		update['value'] = self.input('update_value')
+		update['notice'] = self.input('update_notice')
+		if not update['devices']:
+			self.out(u'请选择设备')
+			return
+		if not update['oper']:
+			self.out(u'请选择执行结果')
+			return
+		if not update['gateway_id']:
+			self.out(u'请选择设备条件')
+			return
+		if not update['device_id']:
+			self.out(u'请选择设备条件')
+			return
+		if not update['condition']:
+			self.out(u'请选择判断条件')
+			return
+		if not update['value']:
+			self.out(u'请输入判断条件的值')
+			return
+		if update['notice']:
+			update['notice'] = True
+		else:
+			update['notice'] = False
+		
+		update['devices'] = str(update['devices'])
+		state = self.service('common').update('device_set_condition', id, update)
+		self.out('yes', {'id':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		update = {}
+		update['status'] = state
+		state = self.service('common').update('device_set_condition', id, update)
+		self.out('yes', {'state':state})
+
+#更新控制设备的状态
+class update_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		value = self.input('value')
+		if id:
+			Demeter.service('device').switch(id, switch=value)
+			
+			self.out('yes', {'id':id})
+			"""
+			yield self.switch(id, value)
+			Shell.popen(Demeter.path + 'switch.py ' + id + ' ' + value, bg=True)
+			response = response.replace("\n", "")
+			if response == 'ok':
+				self.out('yes', {'id':id})
+			else:
+				model = Demeter.model('notice_type')
+				model.key = response
+				info = model.select(type='fetchone')
+				if info:
+					response = info['name']
+
+				self.out(response)
+			"""
+		else:
+			self.out('no')
+
+	@tornado.gen.coroutine
+	def switch(self, id, value):
+		Demeter.service('device').switch(id, switch=value)
+
+class get_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		# 根据网关id获取设备
+		id = self.input('id')
+		device = Device.get(self, search={'gateway_id':id, 'hardware_type': 2,'farm_id':self.data['setting']['farm']})
+		self.view("device/alert/select_device.html")

+ 244 - 0
front/page/main.py

@@ -0,0 +1,244 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:main.py
+    author:rabin
+"""
+from .__load__ import *
+
+class Farm(object):
+	@staticmethod
+	def init(self, search={}):
+		if 'edit' in self.request.uri:
+			self.data['farm_cur'] = 'edit'
+		elif 'product' in self.request.uri:
+			self.data['farm_cur'] = 'product'
+		elif 'env' in self.request.uri:
+			self.data['farm_cur'] = 'env'
+		else:
+			self.data['farm_cur'] = 'index'
+		self.data['url'] = Farm.url()
+
+	@staticmethod
+	def url():
+		config = {}
+		config['info'] = '/'
+		config['edit'] = '/main/edit'
+		config['product'] = '/main/product'
+		config['env'] = '/main/env'
+		return config
+
+class index_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		mobile = Demeter.checkMobile(self.request)
+		if mobile:
+			self.redirect('/device')
+			return
+
+		Farm.init(self)
+		self.view("farm/index.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.data['setting']['farm']
+		update = {}
+		update['info'] = self.input('update_info')
+		if not update['info']:
+			self.out(u'请输入农场介绍')
+			return
+		state = self.service('common').update('farm', id, update)
+		self.out('修改成功')
+
+class edit_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Farm.init(self)
+		self.view("farm/edit.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.data['setting']['farm']
+		update = {}
+		update['name'] = self.input('update_name')
+		update['pic'] = self.input('update_pic')
+		update['location'] = self.input('update_location')
+		update['master_name'] = self.input('update_master_name')
+		update['master_pic'] = self.input('update_master_pic')
+		update['tel'] = self.input('update_tel')
+		update['address'] = self.input('update_address')
+		update['welcome'] = self.input('update_welcome')
+		if not update['name']:
+			self.out(u'请输入名称')
+			return
+		if not update['pic']:
+			self.out(u'请选择图片')
+			return
+		if not update['location']:
+			self.out(u'请输入位置')
+			return
+		if not update['master_name']:
+			self.out(u'请输入姓名')
+			return
+		if not update['master_pic']:
+			self.out(u'请选择图片')
+			return
+		if not update['tel']:
+			self.out(u'请输入联系电话')
+			return
+		if not update['address']:
+			self.out(u'请输入联系地址')
+			return
+		state = self.service('common').update('farm', id, update)
+		self.out('修改成功')
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.service('common').rDelete('farm', id)
+		self.out('yes', {'state':state})
+
+class product_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Farm.init(self)
+		self.data['list'] = self.service('common').list('farm_product', search={'farm_id':self.data['setting']['farm']})
+		self.view("farm/product.html")
+
+class product_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('farm_product', id=id)
+		self.view("farm/product_update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+		update['pic'] = self.input('update_pic')
+		update['area'] = self.input('update_area')
+		update['yields'] = self.input('update_yields')
+		update['charact'] = self.input('update_charact')
+		update['notice'] = self.input('update_notice')
+
+		if not update['name']:
+			self.out(u'请输入名称')
+			return
+		if not update['area']:
+			self.out(u'请输入种植面积')
+			return
+		if not update['yields']:
+			self.out(u'请输入平均亩产')
+			return
+		"""
+		if not update['charact']:
+			self.out(u'请输入特点')
+			return
+		if not update['notice']:
+			self.out(u'请输入使用须知')
+			return
+		"""
+		if not update['pic']:
+			self.out(u'请选择图片')
+			return
+		state = self.service('common').update('farm_product', id, update)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', '1')
+		update = {}
+		if state == '1':
+			update['status'] = True
+		else:
+			update['status'] = False
+		state = self.service('common').update('farm_product', id, update)
+		self.out('yes', {'state':state})
+
+class env_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Farm.init(self)
+		self.data['list'] = self.service('common').list('farm_env', order='inorder asc,cdate desc', search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				info = self.service('common').one('device_info', id=value['device_id'])
+				self.data['list'][key]['device'] = info
+				info = self.service('common').one('device_type', id=value['type_id'])
+				self.data['list'][key]['type'] = info
+		self.view("farm/env.html")
+
+class env_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('farm_env', id=id)
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type' : 2,'farm_id':self.data['setting']['farm']})
+		self.view("farm/env_update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+		update['device_id'] = self.input('update_device_id')
+		update['inorder'] = self.input('update_inorder', 0)
+
+		if not update['name']:
+			self.out(u'请输入环境名称')
+			return
+		if not update['device_id']:
+			self.out(u'请选择设备')
+			return
+		if not update['inorder']:
+			update['inorder'] = 0
+		"""
+		if update['inorder'] and not Check.number(update['inorder']):
+			self.out(u'排序必须是数字')
+			return
+		"""
+		device = self.service('common').one('device_info', id=update['device_id'])
+		if not device:
+			self.out(u'请选择设备')
+			return
+		update['type_id'] = device['type_id']
+		state = self.service('common').update('farm_env', id, update)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		state = self.service('common').rDelete('farm_env', id)
+		self.out('yes', {'state':state})

+ 23 - 0
front/page/msg.py

@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:msg.py
+    author:rabin
+"""
+from .__load__ import *
+
+class index_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.data['list'] = self.service('common').list('msg', search={'farm_id':self.data['setting']['farm']}, page=True, order='status asc, cdate desc')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				type_info = self.service('common').one('msg_type', id=value['type_id'])
+				self.data['list'][key]['type'] = type_info['name']
+				self.data['list'][key]['cdates'] = Demeter.date(value['cdate'])
+				id = value['id']
+				update = {}
+				update['status'] = True
+				self.service('common').update('msg', id, update, cdate=False)
+		self.view("msg/index.html")

+ 210 - 0
front/page/origin.py

@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:origin.py
+    author:rabin
+"""
+from .__load__ import *
+#import qrcode
+from datetime import *
+import os
+import short_url
+import uuid
+import random
+
+class Code(object):
+	@staticmethod
+	def get(self, value):
+		cdate = Demeter.date(value['cdate'], '%Y%m%d%H%M%S')
+		#number = Demeter.compressUuid(value['id']).upper()
+		min = 1000
+		max = 9999
+		number = 'XN' + str(value['farm_id'] + 10000) + '-' + str(value['cdate']) + str(random.randint(min, max))
+
+		info = self.service('common').one('origin_batch', number=number)
+
+		if info and info['id'] != value['id']:
+			return Code.get(self, value)
+
+		#url = Demeter.config['front']['qrcode'] + self.data['setting']['web'] + 'origin/view?qrcode=' + self.data['list'][key]['number']
+		update = {}
+		update['number'] = number
+		state = self.service('common').update('origin_batch', value['id'], update)
+		return number
+
+class index_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		mobile = Demeter.checkMobile(self.request)
+		if mobile:
+			self.redirect('/device')
+			return
+
+		self.data['list'] = self.service('common').list('origin_batch', search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['cdates'] = Demeter.date(value['cdate'], '%Y%m%d')
+				self.data['list'][key]['zzdates'] = Demeter.date(value['zzdate'], '%Y-%m-%d')
+				self.data['list'][key]['csdates'] = Demeter.date(value['csdate'], '%Y-%m-%d')
+				product = self.service('common').one('farm_product', id=value['product_id'])
+				if product:
+					self.data['list'][key]['product'] = product['name']
+				else:
+					self.data['list'][key]['product'] = ''
+
+				if not value['number']:
+					self.data['list'][key]['number'] = Code.get(self, value)
+					value['number'] = self.data['list'][key]['number']
+				self.data['list'][key]['url'] = '/origin/view?id=' + value['id']
+		self.view("origin/index.html")
+
+
+class view_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['info'] = self.service('common').one('origin_batch', id=id)
+		#self.data['url'] = self.data['setting']['web'] + 'origin?id=' + id + '&code=' + self.data['info']['number']
+		self.data['url'] = self.data['setting']['originurl'] + id + '&code=' + self.data['info']['number']
+		self.data['qrcode'] = Demeter.config['front']['qrcode'] + self.data['url']
+		self.view("origin/view.html")
+
+class update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		copy_id = self.input('copy_id')
+		if copy_id:
+			id = copy_id
+		self.data['product'] = self.service('common').list('farm_product', search={'status':True,'farm_id':self.data['setting']['farm']})
+		self.data['land'] = self.service('common').list('farm_work_land', search={'farm_id':self.data['setting']['farm']})
+		self.data['gateway'] = self.service('common').list('device_gateway', search={'farm_id':self.data['setting']['farm']})
+		self.data['device'] = Device.getByGateway(self, search={'hardware_type' : 2,'farm_id':self.data['setting']['farm']})
+		self.data['camera'] = self.service('common').list('device_info', search={'hardware_type': 6,'farm_id':self.data['setting']['farm']})
+		self.data['info'] = {}
+		self.data['growth'] = []
+		if id:
+			self.data['growth'] = self.service('common').list('origin_growth', search={'batch_id': id})
+			if self.data['growth']:
+				for key, value in enumerate(self.data['growth']):
+					self.data['growth'][key]['date'] = Demeter.date(value['date'], '%Y-%m-%d')
+			self.data['info'] = self.service('common').one('origin_batch', id=id)
+			if self.data['info']:
+				self.data['info']['zzdate'] = Demeter.date(self.data['info']['zzdate'], '%Y-%m-%d')
+				self.data['info']['csdate'] = Demeter.date(self.data['info']['csdate'], '%Y-%m-%d')
+				if copy_id:
+					self.data['info']['id'] = None
+		self.view("origin/update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['devices'] = self.inputs('update_devices')
+		update['amount'] = self.input('update_amount')
+		update['product_id'] = self.input('update_product_id')
+		update['device_camera_id'] = self.input('update_device_camera_id')
+		update['land_id'] = self.input('update_land_id')
+		update['name'] = self.input('update_name')
+		update['zzdate'] = self.input('update_zzdate')
+		update['csdate'] = self.input('update_csdate')
+		growth = {}
+		growth['name'] = self.inputs('update_growth_name')
+		growth['date'] = self.inputs('update_growth_date')
+		growth['pic'] = self.inputs('update_growth_pic')
+		growth['id'] = self.inputs('update_growth_id')
+
+		if not update['name']:
+			self.out(u'请输入批次名称')
+			return
+		if not update['product_id']:
+			self.out(u'请选择产品')
+			return
+		if not update['land_id']:
+			self.out(u'请选择地块')
+			return
+		if not update['devices']:
+			self.out(u'请选择设备')
+			return
+		if not update['device_camera_id']:
+			self.out(u'请选择摄像头')
+			return
+		if not update['zzdate'] or not update['csdate']:
+			self.out(u'请选择生长周期')
+			return
+		if not growth['name'] or not growth['date'] or not growth['pic']:
+			self.out(u'请添加生长阶段')
+			return
+		if not update['amount']:
+			self.out(u'请输入本批产量')
+			return
+			
+		update['devices'] = str(update['devices'])
+		state = self.service('common').update('origin_batch', id, update)
+		if state:
+			model = Demeter.model('origin_growth')
+			model.batch_id = state
+			model.delete()
+			for key,value in enumerate(growth['name']):
+				if value and growth['date'][key]:
+					gid = growth['id'][key]
+					gupdate = {}
+					gupdate['name'] = value
+					gupdate['date'] = growth['date'][key]
+					gupdate['pic'] = growth['pic'][key]
+					gupdate['batch_id'] = state
+					self.service('common').update('origin_growth', gid, gupdate)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		state = self.service('common').delete('origin_batch', id, state)
+		self.out('yes', {'state':state})
+
+class printer_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		table_id = self.input('table_id');
+		self.data['info'] = {}
+		self.data['printer'] = self.service('common').list('device_printer', search={'farm_id':self.data['setting']['farm']})
+		self.data['table_id'] = table_id
+		if id:
+			self.data['info'] = self.service('common').one('device_printer_log', id=id)
+		self.view("origin/printer.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['printer_id'] = self.input('update_printer_id')
+		update['num'] = self.input('update_num')
+
+		if not update['printer_id']:
+			self.out(u'请选择打印机')
+			return
+		if not update['num']:
+			self.out(u'请输入张数')
+			return
+		update['uid'] = self.data['setting']['userInfo']['id']
+		update['table_name'] = 'origin_batch'
+		update['table_id'] = self.input('update_table_id')
+		if not update['table_id']:
+			self.out(u'错误的来源')
+			return
+		info = self.service('common').one(update['table_name'], id=update['table_id'])
+		update['content'] = '打印' + info['name'] + '溯源码:' + str(update['num']) + '张'
+		state = self.service('common').update('device_printer_log', id, update)
+		self.out('已发送至打印机队列')

+ 29 - 0
front/page/upload.py

@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:upload.py
+    author:rabin
+"""
+from .__load__ import *
+from datetime import *
+import os
+import uuid
+
+class upload_path(Load):
+	@Web.auth
+	@Web.setting
+	def post(self, *args, **kwargs):
+		url = self.request.protocol + "://" + self.request.host
+		file_metas = self.request.files["file"]
+
+		# print(file_metas)
+		day = str(date.today())
+		day = day.split('-')
+		for meta in file_metas:
+			#meta['filename']
+			file_name =  str(uuid.uuid5(uuid.uuid1(), 'file'))
+			file_path = day[0] + '/' + day[1] + '/' + day[2]
+			file_path = File.mkdirs(os.path.join(Demeter.path, 'runtime','upload', file_path)) + '/' + Demeter.md5(file_name) + '.jpg'
+			with open(file_path, 'wb') as up:
+				up.write(meta['body'])
+		self.out('yes', {'src':url + file_path.replace(Demeter.path + 'runtime', '')})

+ 34 - 0
front/page/user.py

@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:user.py
+    author:rabin
+"""
+from .__load__ import *
+
+class login_path(Load):
+	def get(self):
+		#url = Demeter.config['web']['url']
+		#self.redirect(url)
+		self.data['url'] = self.input('url', '/device')
+		self.view("login.html")
+	def post(self):
+		mobile = self.input('username')
+		password = self.input('password')
+		if mobile and password:
+			user = self.service('common').one('farm_user', mobile=mobile)
+			if user:
+				temp = user['password'].split('_')
+				if Demeter.md5(password, temp[1]) == user['password']:
+					self.set_secure_cookie('user', str(user['id']))
+					self.out('yes', {'id':user['id']})
+					return
+		self.out('手机号或安全码错误,登录失败')
+
+		
+
+
+class loginout_path(Load):
+	def get(self):
+		self.set_secure_cookie('user', '')
+		self.redirect('/user/login')

+ 221 - 0
front/page/work.py

@@ -0,0 +1,221 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web page
+    name:work.py
+    author:rabin
+"""
+from .__load__ import *
+
+class Work(object):
+	@staticmethod
+	def init(self, search={}):
+		if 'set' in self.request.uri:
+			self.data['work_cur'] = 'set'
+		else:
+			self.data['work_cur'] = 'index'
+		self.data['url'] = Work.url()
+
+	@staticmethod
+	def url():
+		config = {}
+		config['index'] = '/work'
+		config['set'] = '/work/set'
+		return config
+
+class index_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		mobile = Demeter.checkMobile(self.request)
+		if mobile:
+			self.redirect('/device')
+			return
+			
+		Work.init(self)
+		self.data['list'] = self.service('common').list('farm_work', search={'farm_id':self.data['setting']['farm']})
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				self.data['list'][key]['workdates'] = Demeter.date(value['workdate'], '%Y-%m-%d %H:%M')
+				category = self.service('common').one('farm_work_category', id=value['category_id'])
+				self.data['list'][key]['category'] = category['name']
+				method = self.service('common').one('farm_work_method', id=value['method_id'])
+				self.data['list'][key]['method'] = method['name']
+				land = self.service('common').one('farm_work_land', id=value['land_id'])
+				self.data['list'][key]['land'] = land['name']
+		self.view("work/index.html")
+
+class update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['category'] = self.service('common').list('farm_work_category', search={'farm_id':self.data['setting']['farm']})
+		self.data['method'] = self.service('common').list('farm_work_method', search={'farm_id':self.data['setting']['farm']})
+		self.data['land'] = self.service('common').list('farm_work_land', search={'farm_id':self.data['setting']['farm']})
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('farm_work', id=id)
+			if self.data['info'] and self.data['info']['workdate']:
+				self.data['info']['workdate'] = Demeter.date(self.data['info']['workdate'])
+		self.view("work/update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['amount'] = self.input('update_amount')
+		update['category_id'] = self.input('update_category_id')
+		update['method_id'] = self.input('update_method_id')
+		update['land_id'] = self.input('update_land_id')
+		update['pic'] = self.input('update_pic')
+		update['workdate'] = self.input('update_workdate')
+
+		if not update['category_id']:
+			self.out(u'请选择劳作类别')
+			return
+		if not update['method_id'] or update['method_id'] == '0' or update['method_id'] == 0:
+			self.out(u'请选择劳作方式')
+			return
+		if not update['land_id']:
+			self.out(u'请选择操作地块')
+			return
+		if not update['workdate']:
+			self.out(u'请选择农事日期')
+			return
+		if not update['amount']:
+			self.out(u'请输入劳作用量')
+			return
+		if not update['pic']:
+			self.out(u'请选择图片')
+			return
+		state = self.service('common').update('farm_work', id, update)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		state = self.service('common').delete('farm_work', id, state)
+		self.out('yes', {'state':state})
+
+class set_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		Work.init(self)
+		self.data['category'] = self.service('common').list('farm_work_category', search={'farm_id':self.data['setting']['farm']})
+		self.data['method'] = self.service('common').list('farm_work_method', search={'farm_id':self.data['setting']['farm']})
+		self.data['land'] = self.service('common').list('farm_work_land', search={'farm_id':self.data['setting']['farm']})
+		self.view("work/set.html")
+
+class land_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('farm_work_land', id=id)
+		self.view("work/land_update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+
+		if not update['name']:
+			self.out(u'请输入地块名称')
+			return
+		state = self.service('common').update('farm_work_land', id, update)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		state = self.service('common').delete('farm_work_land', id, state)
+		self.out('yes', {'state':state})
+
+class category_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('farm_work_category', id=id)
+		self.view("work/category_update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+
+		if not update['name']:
+			self.out(u'请输入农事内容分类名称')
+			return
+		state = self.service('common').update('farm_work_category', id, update)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		state = self.service('common').delete('farm_work_category', id, state)
+		self.out('yes', {'state':state})
+
+class method_update_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		id = self.input('id')
+		self.data['category'] = self.input('category')
+		self.data['info'] = {}
+		if id:
+			self.data['info'] = self.service('common').one('farm_work_method', id=id)
+		self.view("work/method_update.html")
+
+	@Web.auth
+	@Web.setting
+	def post(self):
+		id = self.input('id')
+		update = {}
+		update['name'] = self.input('update_name')
+		update['category_id'] = self.input('update_category_id')
+
+		if not update['name']:
+			self.out(u'请输入农事内容名称')
+			return
+		if not update['category_id']:
+			self.out(u'请选择农事分类')
+			return
+		state = self.service('common').update('farm_work_method', id, update)
+		self.out('yes', {'state':state})
+
+	@Web.auth
+	@Web.setting
+	def delete(self):
+		id = self.input('id')
+		if not id:
+			self.out('no')
+			return
+		state = self.input('state', False)
+		state = self.service('common').delete('farm_work_method', id, state)
+		self.out('yes', {'state':state})

+ 52 - 0
front/static/mobile/analytics.html

@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"></head>
+
+<body>
+    <section class="has-bbar">
+        <div class="form-group-head">设备周期选择</div>
+        <ul>
+            <li class="form-input">
+                <label>
+                    <select>
+                        <option>设备选择</option>
+                    </select>
+                    <p><i>&gt;</i></p>
+                </label>
+            </li>
+            <li class="form-input">
+                <label>
+                    <select>
+                        <option>周期选择(默认一天)</option>
+                    </select>
+                    <p><i>&gt;</i></p>
+                </label>
+            </li>
+        </ul>
+        <input type="button" name="" class="button primary btn-mt btn-mb" value="查看曲线">
+        <div class="form-group-head">周期曲线</div>
+        <section>
+            <img src="images/b667b90e.charts.jpg" width="100%">
+        </section>
+    </section>
+    <section class="bbar">
+        <ul>
+            <li><a href=""><i class="ico ico-b-1"></i><p>设备监控</p></a></li>
+            <li class="cur"><a href=""><i class="ico ico-b-2"></i><p>数据统计</p></a></li>
+            <li><a href=""><i class="ico ico-b-3"></i><p>图像记录</p></a></li>
+            <li><a href=""><i class="ico ico-b-4"></i><p>设备日志</p></a></li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/analytics.js"></script></body>
+
+</html>

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
front/static/mobile/css/farm.css


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
front/static/mobile/css/global.css


+ 1 - 0
front/static/mobile/css/imgs.css

@@ -0,0 +1 @@
+section>*{background-color:#fff}.scroll{width:100%;background:#fff;overflow-x:auto;margin-bottom:.266667rem}.scroll ul{width:1000%}.scroll li{width:2.8rem;text-align:center;font-size:.373333rem;float:left;padding:.533333rem 0 .32rem;line-height:.64rem}.scroll li p{margin-top:.133333rem}.scroll li .ico{width:24px;height:30px}.scroll li a{color:#333}.li-1{overflow:hidden;padding-bottom:.3rem}.li-1 dl{margin:.29333rem 0 0 .29333rem;width:4.56rem;float:left}.li-1 dl dt{margin-bottom:.2rem}.li-1 dl dt img{display:block;border-radius:5px}.li-1 dl dd{font-size:.346667rem;text-align:center;color:#666;line-height:.613333rem}.li-1 dl dd:last-child{color:#333}

+ 1 - 0
front/static/mobile/css/index.css

@@ -0,0 +1 @@
+.h1{font-size:.56rem;line-height:2.853333rem;background-color:#4a7cf9;text-align:center;color:#fff}

+ 1 - 0
front/static/mobile/css/login.css

@@ -0,0 +1 @@
+.logo{width:4.213333rem;margin:1.266667rem auto 1rem}.logo img{display:block}.button{margin-top:.933333rem}

+ 1 - 0
front/static/mobile/css/logs.css

@@ -0,0 +1 @@
+.h1{font-size:.56rem;line-height:2.853333rem;background-color:#4a7cf9;text-align:center;color:#fff}

+ 0 - 0
front/static/mobile/css/msgs.css


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
front/static/mobile/css/origins.css


+ 1 - 0
front/static/mobile/css/station.css

@@ -0,0 +1 @@
+.h1{font-size:.56rem;line-height:2.853333rem;background-color:#4a7cf9;text-align:center;color:#fff}

+ 105 - 0
front/static/mobile/farm.html

@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"><link href="css/farm.css" rel="stylesheet"></head>
+
+<body>
+    <h1 class="h1">水润佳禾保定农场试验田</h1>
+    <section class="banner">
+        <img src="images/6f5ddf93.tmp5.jpg" width="100%">
+    </section>
+    <section class="m-wrapper">
+        <h2>农场环境 <p>Farm environment</p> </h2>
+        <section class="environment">
+            <dl>
+                <dd><i class="icon icon-temperature"></i></dd>
+                <dt>28</dt>
+                <dd>温度( ℃ )</dd>
+            </dl><dl>
+                <dd><i class="icon icon-humidity"></i></dd>
+                <dt>28</dt>
+                <dd>温度( ℃ )</dd>
+            </dl><dl>
+                <dd><i class="icon icon-light"></i></dd>
+                <dt>28</dt>
+                <dd>温度( ℃ )</dd>
+            </dl><dl>
+                <dd><i class="icon icon-speed"></i></dd>
+                <dt>28</dt>
+                <dd>温度( ℃ )</dd>
+            </dl><dl>
+                <dd><i class="icon icon-direction"></i></dd>
+                <dt>28</dt>
+                <dd>温度( ℃ )</dd>
+            </dl>
+        </section>
+    </section>
+
+    <section class="m-wrapper introduction">
+        <h2>农场介绍 <p>Farm introduction</p> </h2>
+        <p>小汤山镇是中国北京市昌平区下辖的一个镇,位于县境中部偏东距北京首都国际机场19公里。维基百科,  以友谊农场五分场二队为例介绍了实现客户/服务器模式的精准农业,  地理信息系统的开发。以友谊农场五分场二队为例介绍了实现客户/服务器模式的精准农业地理信息系统的开发。</p>
+        <a href="#" class="more">点击查看更多</a>
+    </section>
+    
+    <section class="m-wrapper">
+        <h2>地理位置 <p>geographical position</p> </h2>
+        <section class="img-wrap">
+            <img src="images/8909d634.map.jpg" width="100%">
+        </section>
+    </section>
+
+    <section class="m-wrapper">
+        <h2>农场产品 <p>Farm products</p> </h2>
+        <section class="li-1">
+            <dl>
+                <dt><img src="images/a1e19d4f.tmp.jpg" width="100%"></dt>
+                <dd>成熟期</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/a1e19d4f.tmp.jpg" width="100%"></dt>
+                <dd>成熟期</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/a1e19d4f.tmp.jpg" width="100%"></dt>
+                <dd>成熟期</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/a1e19d4f.tmp.jpg" width="100%"></dt>
+                <dd>成熟期</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/a1e19d4f.tmp.jpg" width="100%"></dt>
+                <dd>成熟期</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/a1e19d4f.tmp.jpg" width="100%"></dt>
+                <dd>成熟期</dd>
+            </dl>
+        </section>
+    </section>
+
+    <section class="m-wrapper contact">
+        <h2>联系方式 <p>Contact information</p> </h2>
+        <section >
+            <dl>
+                <dt><i class="icon icon-ct1"></i></dt>
+                <dd>农场主:刘厂长</dd>
+            </dl>
+            <dl>
+                <dt><i class="icon icon-ct2"></i></dt>
+                <dd><a href="tel://400-123-1234">电话:400-123-1234</a></dd>
+            </dl>
+        </section>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/farm.js"></script></body>
+
+</html>

+ 83 - 0
front/static/mobile/greenhouse.html

@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"></head>
+
+<body>
+    <section class="has-bbar">
+        <div class="form-group-head">设备状态</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-6"></i><span>网关状态</span><p><span class="error">断开</span></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-7"></i><span>电源状态</span><p><span>220V</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-7"></i><span>四要素电量</span><p><span>4.1V</span><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <div class="form-group-head">实时视频(或时时图像,都有则上下排列)</div>
+        <section>
+            <img src="images/a1e19d4f.tmp.jpg" width="100%">
+        </section>
+        <div class="form-group-head">设备采集 2016.8.29 12:50</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <span>温度<b class="txt-block">28</b><u class="degree">℃</u></span><p><span>正常</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>湿度<b class="txt-block">780</b><u class="degree">%RH</u></span><p><span class="error">上限超标</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>EC值<b class="txt-block">140</b><u class="degree">ms/cm</u></span><p><span class="error">下限超标</span><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <div class="form-group-head">设备控制</div>
+        <ul>
+            <li class="form-input">
+                <label><span>1号阀门</span><p><a class="btn btn-switch "><i></i></a></p></label>
+            </li>
+            <li class="form-input">
+                <label><span>补光灯</span><p><a class="btn btn-switch open"><i></i></a></p></label>
+            </li>
+            <li class="form-input">
+                <label><span>雾化喷淋</span><p><a class="btn btn-switch loading"><i></i></a></p></label>
+            </li>
+            <li class="form-input">
+                <label><span>放风</span><p><a class="btn btn-switch open loading"><i></i></a></p></label>
+            </li>
+        </ul>
+    </section>
+    <section class="bbar">
+        <ul>
+            <li class="cur"><a href=""><i class="ico ico-b-1"></i><p>设备监控</p></a></li>
+            <li><a href=""><i class="ico ico-b-2"></i><p>数据统计</p></a></li>
+            <li><a href=""><i class="ico ico-b-3"></i><p>图像记录</p></a></li>
+            <li><a href=""><i class="ico ico-b-4"></i><p>设备日志</p></a></li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/greenhouse.js"></script></body>
+
+</html>

BIN
front/static/mobile/images/1fef2694.tmp2.jpg


BIN
front/static/mobile/images/35441c2e.ico.png


BIN
front/static/mobile/images/3fd94561.charts1.jpg


BIN
front/static/mobile/images/4fe4e197.ico.png


BIN
front/static/mobile/images/649cd7ee.tmp4.jpg


BIN
front/static/mobile/images/6f5ddf93.tmp5.jpg


BIN
front/static/mobile/images/786c7f25.farmicon.png


BIN
front/static/mobile/images/888db1cc.tmp1.jpg


BIN
front/static/mobile/images/8909d634.map.jpg


BIN
front/static/mobile/images/a1e19d4f.tmp.jpg


BIN
front/static/mobile/images/b667b90e.charts.jpg


BIN
front/static/mobile/images/bdc1f518.logo.jpg


BIN
front/static/mobile/images/f7a3ef62.banner.jpg


+ 58 - 0
front/static/mobile/imgs.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"><link href="css/imgs.css" rel="stylesheet"></head>
+
+<body>
+    <section class="scroll">
+        <ul>
+            <li><a href="#"><i class="ico ico-cam"></i><p>一号摄像头</p></a></li>
+            <li><a href="#"><i class="ico ico-cam"></i><p>一号摄像头</p></a></li>
+            <li><a href="#"><i class="ico ico-cam"></i><p>一号摄像头</p></a></li>
+            <li><a href="#"><i class="ico ico-cam"></i><p>一号摄像头</p></a></li>
+            <li><a href="#"><i class="ico ico-cam"></i><p>一号摄像头</p></a></li>
+            <li><a href="#"><i class="ico ico-cam"></i><p>一号摄像头</p></a></li>
+        </ul>
+    </section>
+    <section class="m-wrapper">
+        <section class="li-1">
+            <dl>
+                <dt><img src="images/888db1cc.tmp1.jpg" width="100%"></dt>
+                <dd>2017-07-27</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/888db1cc.tmp1.jpg" width="100%"></dt>
+                <dd>2017-07-27</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/888db1cc.tmp1.jpg" width="100%"></dt>
+                <dd>2017-07-27</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/888db1cc.tmp1.jpg" width="100%"></dt>
+                <dd>2017-07-27</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/888db1cc.tmp1.jpg" width="100%"></dt>
+                <dd>2017-07-27</dd>
+            </dl>
+            <dl>
+                <dt><img src="images/888db1cc.tmp1.jpg" width="100%"></dt>
+                <dd>2017-07-27</dd>
+            </dl>
+        </section>
+
+        <section class="loading-more"><i></i>加载中...</section>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/imgs.js"></script></body>
+
+</html>

+ 72 - 0
front/static/mobile/index.html

@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"><link href="css/index.css" rel="stylesheet"></head>
+
+<body>
+    <h1 class="h1">水润佳禾保定农场试验田</h1>
+    <section>
+        <div class="form-group-head">设备综合管控</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-1"></i><span>采集设备</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-2"></i><span>控制设备</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-3"></i><span>批量控制</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <div class="form-group-head">设备管理</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-4"></i><span>号温室系统</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-4"></i><span>气象站</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-4"></i><span>大田阀门灌溉</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <div class="form-group-head">设备管理</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-5"></i><span>基础信息通知</span><p><b>99+</b><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <ul class="mt22">
+            <li class="form-input">
+                <a href="#">
+                    <span>退出登录</span><p><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/index.js"></script></body>
+
+</html>

+ 1 - 0
front/static/mobile/js/analytics.js

@@ -0,0 +1 @@
+webpackJsonp([11],{26:function(n,t,c){n.exports=c(4)},4:function(n,t,c){"use strict";c(0)}},[26]);

+ 1 - 0
front/static/mobile/js/farm.js

@@ -0,0 +1 @@
+webpackJsonp([6],{20:function(n,t){},27:function(n,t,c){n.exports=c(5)},5:function(n,t,c){"use strict";c(0),c(20)}},[27]);

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
front/static/mobile/js/global.js


+ 1 - 0
front/static/mobile/js/greenhouse.js

@@ -0,0 +1 @@
+webpackJsonp([10],{29:function(n,t,c){n.exports=c(6)},6:function(n,t,c){"use strict";c(0)}},[29]);

Різницю між файлами не показано, бо вона завелика
+ 13 - 0
front/static/mobile/js/imgs.js


+ 1 - 0
front/static/mobile/js/index.js

@@ -0,0 +1 @@
+webpackJsonp([5],{3:function(n,t){},31:function(n,t,c){n.exports=c(8)},8:function(n,t,c){"use strict";c(0),c(3)}},[31]);

+ 1 - 0
front/static/mobile/js/login.js

@@ -0,0 +1 @@
+webpackJsonp([4],{22:function(n,t){},32:function(n,t,c){n.exports=c(9)},9:function(n,t,c){"use strict";c(0),c(22)}},[32]);

+ 1 - 0
front/static/mobile/js/logs.js

@@ -0,0 +1 @@
+webpackJsonp([3],{10:function(n,t,c){"use strict";c(0),c(3)},3:function(n,t){},33:function(n,t,c){n.exports=c(10)}},[33]);

+ 1 - 0
front/static/mobile/js/msgs.js

@@ -0,0 +1 @@
+webpackJsonp([2],{11:function(n,t,c){"use strict";c(0),c(23)},23:function(n,t){},34:function(n,t,c){n.exports=c(11)}},[34]);

Різницю між файлами не показано, бо вона завелика
+ 13 - 0
front/static/mobile/js/origins.js


+ 1 - 0
front/static/mobile/js/set.js

@@ -0,0 +1 @@
+webpackJsonp([9],{13:function(n,t,c){"use strict";c(0)},36:function(n,t,c){n.exports=c(13)}},[36]);

+ 1 - 0
front/static/mobile/js/soil.js

@@ -0,0 +1 @@
+webpackJsonp([8],{14:function(n,t,c){"use strict";c(0)},37:function(n,t,c){n.exports=c(14)}},[37]);

+ 1 - 0
front/static/mobile/js/station.js

@@ -0,0 +1 @@
+webpackJsonp([7],{15:function(n,t,c){"use strict";c(0)},38:function(n,t,c){n.exports=c(15)}},[38]);

+ 48 - 0
front/static/mobile/login.html

@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"><link href="css/login.css" rel="stylesheet"></head>
+
+<body>
+    <section class="logo">
+        <img src="images/bdc1f518.logo.jpg" width="100%" />
+    </section>
+    <section>
+        <form>
+            <ul>
+                <li class="form-input">
+                    <label>手机号</label>
+                    <input type="text" name="" placeholder="请填写手机号码">
+                </li>
+                <li class="form-input">
+                    <label>安全码</label>
+                    <input type="text" name="" placeholder="请填写安全码">
+                </li>
+            </ul>
+            <label class="form-label-checkbox"><input type="checkbox" name=""><span>保存账号密码</span></label>
+            <input type="button" name="" class="button primary" value="确认">
+            <p class="tip">没有安全码?请查看设备说明书</p>
+        </form>
+    </section>
+    <section class="layer">
+        <section class="container">
+            <section class="area">
+                <p>手机号或安全码错误!</p>
+            </section>
+            <section class="ctrls">
+                <a href="javascript:;">知道了</a>
+            </section>
+        </section>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/login.js"></script></body>
+
+</html>

+ 74 - 0
front/static/mobile/logs.html

@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"><link href="css/logs.css" rel="stylesheet"></head>
+
+<body>
+    <section class="has-bbar">
+        <h2 class="common-tit">设备日志记录</h2>
+        <div class="form-group-head">设备清单</div>
+        <ul>
+            <li class="form-th">
+                <p>设备名称</p>
+                <p class="txt-m">数量</p>
+                <p class="txt-m">日期</p>
+            </li>
+            <li class="form-tr">
+                <p>通讯网关</p>
+                <p class="ora txt-m">1</p>
+                <p class="txt-m">15.10.10</p>
+            </li>
+            <li class="form-tr">
+                <p>通讯网关</p>
+                <p class="ora txt-m">1</p>
+                <p class="txt-m">15.10.10</p>
+            </li>
+            <li class="form-tr">
+                <p>通讯网关</p>
+                <p class="ora txt-m">1</p>
+                <p class="txt-m">15.10.10</p>
+            </li>
+            <li class="form-tr">
+                <p>通讯网关</p>
+                <p class="ora txt-m">1</p>
+                <p class="txt-m">15.10.10</p>
+            </li>
+        </ul>
+        <div class="form-group-head">设备分布图纸</div>
+        <section>
+            <img src="images/a1e19d4f.tmp.jpg" width="100%">
+        </section>
+        <div class="form-group-head">设备日志</div>
+        <section>
+            <dl class="msg-card">
+                <dt><span class="warn">系统消息</span></dt>
+                <dd>由各种物质组成的巨型球状天体,叫做星球。星球有一定的形状,有自己的运行轨道。</dd>
+                <dd class="date">2015.10.29 18:10</dd>
+            </dl>
+            <dl class="msg-card">
+                <dt><span class="warn">系统消息</span></dt>
+                <dd>由各种物质组成的巨型球状天体,叫做星球。星球有一定的形状,有自己的运行轨道。</dd>
+                <dd class="date">2015.10.29 18:10</dd>
+            </dl>
+        </section>
+    </section>
+    <section class="bbar">
+        <ul>
+            <li><a href=""><i class="ico ico-b-1"></i><p>设备监控</p></a></li>
+            <li><a href=""><i class="ico ico-b-2"></i><p>数据统计</p></a></li>
+            <li><a href=""><i class="ico ico-b-3"></i><p>图像记录</p></a></li>
+            <li class="cur"><a href=""><i class="ico ico-b-4"></i><p>设备日志</p></a></li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/logs.js"></script></body>
+
+</html>

+ 45 - 0
front/static/mobile/msgs.html

@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"><link href="css/msgs.css" rel="stylesheet"></head>
+
+<body>
+    <section class="msg-group">
+        <a href="#" class="msg-card">
+            <dl>
+                <dt><span>系统消息</span><em></em></dt>
+                <dd>由各种物质组成的巨型球状天体,叫做星球。星球有一定的形状,有自己的运行轨道。</dd>
+                <dd class="date">2015.10.29 18:10</dd>
+            </dl>
+        </a>
+    </section>
+    <section class="msg-group">
+        <a href="#" class="msg-card">
+            <dl>
+                <dt><span>警告提醒</span></dt>
+                <dd>由各种物质组成的巨型球状天体,叫做星球。星球有一定的形状,有自己的运行轨道。</dd>
+                <dd class="date">2015.10.29 18:10</dd>
+            </dl>
+        </a>
+    </section>
+    <section class="msg-group">
+        <a href="#" class="msg-card">
+            <dl>
+                <dt><span>操作提示</span></dt>
+                <dd>由各种物质组成的巨型球状天体,叫做星球。星球有一定的形状,有自己的运行轨道。</dd>
+                <dd class="date">2015.10.29 18:10</dd>
+            </dl>
+        </a>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/msgs.js"></script></body>
+
+</html>

Різницю між файлами не показано, бо вона завелика
+ 89 - 0
front/static/mobile/origins.html


+ 46 - 0
front/static/mobile/set.html

@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"></head>
+
+<body>
+    <header>
+        <a href="#"><span>返回</span></a>设置
+    </header>
+    <section class="has-bbar">
+        <h2 class="common-tit">温度限值设置</h2>
+        <form>
+            <div class="form-group-head">单位:摄氏度</div>
+            <ul>
+                <li class="form-input">
+                    <label>最大上限</label>
+                    <input type="text" name="" placeholder="">
+                </li>
+                <li class="form-input">
+                    <label>最小下限</label>
+                    <input type="text" name="" placeholder="">
+                </li>
+            </ul>
+            <input type="button" name="" class="button primary btn-mt" value="确认设置">
+        </form>
+    </section>
+    <section class="bbar">
+        <ul>
+            <li class="cur"><a href=""><i class="ico ico-b-1"></i><p>设备监控</p></a></li>
+            <li><a href=""><i class="ico ico-b-2"></i><p>数据统计</p></a></li>
+            <li><a href=""><i class="ico ico-b-3"></i><p>图像记录</p></a></li>
+            <li><a href=""><i class="ico ico-b-4"></i><p>设备日志</p></a></li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/set.js"></script></body>
+
+</html>

+ 59 - 0
front/static/mobile/soil.html

@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"></head>
+
+<body>
+    <section class="has-bbar">
+        <div class="form-group-head">设备状态</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-6"></i><span>网关状态</span><p><span class="error">断开</span></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-7"></i><span>电源状态</span><p><span>4.1V</span><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <div class="form-group-head">LastTime: 2016.8.29 12:50</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <span>温度<b class="txt-block">28</b><u class="degree">℃</u></span>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>湿度<b class="txt-block">780</b><u class="degree">%RH</u></span>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>EC值<b class="txt-block">140</b><u class="degree">ms/cm</u></span>
+                </a>
+            </li>
+        </ul>
+    </section>
+    <section class="bbar">
+        <ul>
+            <li class="cur"><a href=""><i class="ico ico-b-1"></i><p>设备监控</p></a></li>
+            <li><a href=""><i class="ico ico-b-2"></i><p>数据统计</p></a></li>
+            <li><a href=""><i class="ico ico-b-3"></i><p>图像记录</p></a></li>
+            <li><a href=""><i class="ico ico-b-4"></i><p>设备日志</p></a></li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/soil.js"></script></body>
+
+</html>

+ 69 - 0
front/static/mobile/station.html

@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="black" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <title>首页</title>
+    <meta name="Keywords" content="" />
+    <meta name="Description" content="" />
+<link href="css/global.css" rel="stylesheet"></head>
+
+<body>
+    <section class="has-bbar">
+        <div class="form-group-head">设备状态</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-6"></i><span>网关状态</span><p><span class="error">断开</span></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <i class="ico ico-7"></i><span>电源状态</span><p><span>4.1V</span><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+        <div class="form-group-head">LastTime: 2016.8.29 12:50</div>
+        <ul>
+            <li class="form-input">
+                <a href="#">
+                    <span>温度<b class="txt-block">28</b><u class="degree">℃</u></span><p><span>正常</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>湿度<b class="txt-block">780</b><u class="degree">%RH</u></span><p><span>正常</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>光照<b class="txt-block">28</b><u class="degree">LUX</u></span><p><span class="error">下限超标</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>风速<b class="txt-block">3</b><u class="degree">m/s(三级风)</u></span><p><span class="error">上限超标</span><i>&gt;</i></p>
+                </a>
+            </li>
+            <li class="form-input">
+                <a href="#">
+                    <span>PM2.5<b class="txt-block">270</b></span><p><span class="disable">离线</span><i>&gt;</i></p>
+                </a>
+            </li>
+        </ul>
+    </section>
+    <section class="bbar">
+        <ul>
+            <li class="cur"><a href=""><i class="ico ico-b-1"></i><p>设备监控</p></a></li>
+            <li><a href=""><i class="ico ico-b-2"></i><p>数据统计</p></a></li>
+            <li><a href=""><i class="ico ico-b-3"></i><p>图像记录</p></a></li>
+            <li><a href=""><i class="ico ico-b-4"></i><p>设备日志</p></a></li>
+        </ul>
+    </section>
+<script type="text/javascript" src="js/global.js"></script><script type="text/javascript" src="js/station.js"></script></body>
+
+</html>

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
front/static/pc/css/global.css


+ 1 - 0
front/static/pc/css/login.css

@@ -0,0 +1 @@
+.header{background:#247ed0;width:100%;height:80px}.header .logo{padding:15px;display:inline-block;vertical-align:middle}.header .logo img{display:block}.header h1{display:inline-block;font-size:24px;color:#fff;line-height:60px;padding-left:21px;vertical-align:middle}.right-cont{margin-left:0}.right-cont .main .pannel{height:80%}.right-cont .main .pannel .form{border-bottom:none;padding:100px 0}.right-cont .main .pannel .form input[type=password],.right-cont .main .pannel .form input[type=text]{width:300px;display:block;margin:15px auto 0}.right-cont .main .pannel .form input[type=button]{display:block;width:300px;height:38px;font-size:14px;line-height:38px;border:1px solid #49a0ff;border-radius:5px;text-align:center;color:#fff;background-color:#49a0ff;margin:30px auto}

+ 1 - 0
front/static/pc/css/logs.css

@@ -0,0 +1 @@
+.logs li{padding:8px 0;border-bottom:1px solid #f5f5f5}.logs li p{color:#727a93;line-height:19px;margin-bottom:10px}.logs li h2{margin-bottom:10px;color:#2e3254}.logs li h3 em{width:10px;height:10px;background-color:#fb253a;border-radius:50%;display:inline-block;vertical-align:middle;margin-left:5px}.logs li .time{font-size:12px;margin-bottom:0}.logs li:last-child{border-bottom:none}.grid li{border-bottom:1px solid #f5f5f5;padding:5px 0;overflow:hidden;color:#727a93}.grid li.th{color:#2e3254;padding-top:12px}.grid li span{display:block;float:left;width:33.33333%}.grid li span.t-l{text-align:left}.grid li span.t-c{text-align:center}.grid li span.t-r{text-align:right}.grid li:last-child{border-bottom:none}

+ 1 - 0
front/static/pc/css/pmjk.css

@@ -0,0 +1 @@
+.right-cont{margin-left:0}.right-cont .top{background:none;height:auto}.right-cont .top h1{font-size:34px;text-align:center;line-height:110px}.right-cont .main{overflow:hidden}.right-cont .main .pannel .cam-list{position:relative}.right-cont .main .pannel .cam-list .cam img{display:block;margin-bottom:5px}.right-cont .main .pannel .cam-tabs{text-align:center}.right-cont .main .pannel .cam-tabs a{display:inline-block;color:#2e3254;margin:0 10px}.right-cont .main .pannel .cam-tabs a.cur,.right-cont .main .pannel .cam-tabs a:hover{color:#4090db}.logs li{padding:8px 0;border-bottom:1px solid #f5f5f5}.logs li p{color:#727a93;line-height:19px;margin-bottom:10px}.logs li h2{margin-bottom:10px;color:#2e3254}.logs li h3.error{color:#f05d5d}.logs li .time{font-size:12px;margin-bottom:0}.logs li:last-child{border-bottom:none}.w-half.left{width:42%}.w-half.right{width:56%}

+ 1 - 0
front/static/pc/css/sy_cplb.css

@@ -0,0 +1 @@
+.right-cont .main .pannel .ul7 dl{display:-webkit-box;display:-ms-flexbox;display:flex;border-bottom:1px solid #f2f2f2}.right-cont .main .pannel .ul7 dl>*{color:#727a93;-webkit-box-flex:1;-ms-flex:1;flex:1}.right-cont .main .pannel .ul7 dl>* img{width:100px;display:block}.right-cont .main .pannel .ul7 dl dd:nth-child(4),.right-cont .main .pannel .ul7 dl dd:nth-child(9),.right-cont .main .pannel .ul7 dl dt:nth-child(4),.right-cont .main .pannel .ul7 dl dt:nth-child(9){-webkit-box-flex:2;-ms-flex:2;flex:2}.right-cont .main .pannel .ul7 dl dt{padding:0 0 18px}.right-cont .main .pannel .ul7 dl dd{padding:25px 0;position:relative}.right-cont .main .pannel .ul7 dl dd p{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.right-cont .main .pannel .ul7 dl dd p a{display:inline-block;color:#4090db;margin:0 8px}.right-cont .main .pannel .ul7 dl:last-child{border-bottom:none}

Різницю між файлами не показано, бо вона завелика
+ 19 - 0
front/static/pc/dsml.html


Різницю між файлами не показано, бо вона завелика
+ 19 - 0
front/static/pc/fmgg.html


BIN
front/static/pc/images/0ca089fc.icons.png


BIN
front/static/pc/images/20255880.tmp.jpg


BIN
front/static/pc/images/376a00e6.tmp2.jpg


BIN
front/static/pc/images/4c9b8ed6.tmp4.jpg


BIN
front/static/pc/images/4e9ffe8f.charts1.jpg


BIN
front/static/pc/images/51b4c576.icons.png


BIN
front/static/pc/images/8f932958.tmp1.jpg


BIN
front/static/pc/images/ac6b66f2.icons.png


BIN
front/static/pc/images/cd8fcfa0.icons.png


BIN
front/static/pc/images/e645d80a.tmp3.jpg


Різницю між файлами не показано, бо вона завелика
+ 19 - 0
front/static/pc/index.html


+ 1 - 0
front/static/pc/js/dsml.js

@@ -0,0 +1 @@
+webpackJsonp([19],{3:function(n,t,c){"use strict";c(0)},32:function(n,t,c){n.exports=c(3)}},[32]);

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
front/static/pc/js/echarts.common.min.js


+ 1 - 0
front/static/pc/js/fmgg.js

@@ -0,0 +1 @@
+webpackJsonp([18],{33:function(n,t,c){n.exports=c(4)},4:function(n,t,c){"use strict";c(0)}},[33]);

Деякі файли не було показано, через те що забагато файлів було змінено