├── .gitignore ├── .idea ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── odoo_mobile.iml └── workspace.xml ├── .settings └── org.eclipse.core.resources.prefs ├── README.md └── mobile ├── __init__.py ├── __openerp__.py ├── index.html ├── mobile_model.py ├── mobile_model.pyc ├── mobile_model.xml ├── security └── ir.model.access.csv └── static ├── html ├── css │ └── app.5914b78bd7790e9371ccc0f4cfc5093c.css ├── images │ └── default.png ├── js │ ├── app.45632234eddc404cf63d.js │ └── registerSw.8b75daa54b1bf5dbf84b.js ├── json │ └── offline.json ├── logo.png ├── manifest.json └── vux_logo.png ├── index.html ├── service-worker.js └── sw.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | .* 3 | !.gitignore -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/odoo_mobile.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//mobile/__openerp__.py=utf-8 3 | encoding//mobile/mobile_model.py=utf-8 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![996.icu](https://img.shields.io/badge/link-996.icu-red.svg) 2 | # odoo_mobile 3 | # master 分支为最新的代码 10.0的。 4 | ## 图文演示 http://blog.sina.com.cn/s/blog_bc7dee2d0102xrl7.html 5 | 对应的前端VUX 项目 https://github.com/gilbert-yuan/odoo_mobile_test 6 | vux 实现对接odoo 配置出手机端 () 7 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/10.0/mobile/odoo_mobile.gif) 8 | 9 | 10 | 图片示例 11 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/QQ20180629-101702.png) 12 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/QQ20180629-101646.png) 13 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/QQ20180629-101742.png) 14 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/2018-07-23%2017.23.37.gif) 15 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/2018-07-23%2017.27.12.gif) 16 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/2018-07-23%2017.27.47.gif) 17 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/2018-07-23%2017.31.17.gif) 18 | ![](https://github.com/gilbert-yuan/odoo_mobile/blob/8.0/mobile/description/2018-07-23%2017.30.40.gif) 19 | 1. 安装模块 20 | 找到对应的版本安装模块 21 | 22 | 2. 配置手机端的要显示的模型 Grid Action View 23 | 字段的设置还不完善。 24 | 25 | 3.访问链接登录 http://127.0.0.1:8888/odoo/mobile#/odoo/grid 26 | 27 | 测试性,写odoo 8 的手机端,功能尽量做到能配置页面。odoo模块对应的是8.0 28 | 29 | 待完善地方 30 | 31 | 1. 前端登录页面的创建 32 | 2. odoo模块 中write 方法的进一步的完善 33 | 3. 按钮的隐藏显示的完善,按钮的样式 34 | 4. 字段的显示的完善。 35 | 5.readonly form的美化 36 | 6.集成进去pyecharts 在手机端能够方便的查看 查看一些简单的报表视图 37 | 38 | 使用、开发odoo很长一段时间了,受odoo的影响,在做一些工功能的时候就会想着做成可以配置的。 39 | 所以就有了现在的模块,公司已经对接了微信,所以很多小功能就希望写在微信中,希望在微信里面有快捷的操作的页面。 40 | 41 | 这个是初始的需求,加班调休功能做到手机端。 42 | 43 | :-: 过了几天居然又要求加一个报销功能,也要加到手机端。于是就在想能加到手机端当然是很棒的呀,很方便,但是写的时候却是很痛苦,每个页面都要手动的写太麻烦了,因为是erp类的给内部员工用的,页面也不需要很炫,特殊的定制化的东西也是比较少,可不可以像odoo一样可以在后台进行配置呢,然后前台就动态的显示页面于是就有了现在的项目 44 | 45 | 46 | 47 | 48 | ## pyechart 是一个极好的库希望能够进一步学习这个库 抽时间把它应用到这个项目中 49 | 50 | -------------------------------------------------------------------------------- /mobile/__init__.py: -------------------------------------------------------------------------------- 1 | import mobile_model 2 | -------------------------------------------------------------------------------- /mobile/__openerp__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | { 4 | "name": "VUE 实现手机端的页面", 5 | "description": 6 | """ 7 | 手机端页面的配置实现 8 | """, 9 | 'author': "静静(gilbert@osbzr.com)", 10 | 'website': "http://control.blog.sina.com.cn/blog_rebuild/profile/controllers/points_action.php", 11 | "category": "osbzr", 12 | "version": "8.0.0.1", 13 | "depends": ['base'], 14 | "data": [ 15 | 'mobile_model.xml', 16 | ], 17 | 'installable': True, 18 | 'application': False, 19 | } 20 | -------------------------------------------------------------------------------- /mobile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | odoo_vue 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /mobile/mobile_model.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # -*- coding: utf-8 -*- 3 | import jinja2, sys, os 4 | import json, odoo 5 | from odoo.addons.web.controllers.main import ensure_db 6 | from odoo import http 7 | from odoo.http import request 8 | from odoo import api, fields, models, _ 9 | from odoo.tools.float_utils import float_round as float_round 10 | import copy, datetime 11 | from dateutil.relativedelta import relativedelta 12 | ISODATEFORMAT = '%Y-%m-%d' 13 | ISODATETIMEFORMAT = "%Y-%m-%d %H:%M:%S" 14 | MOBILEDATETIMEFORMAT = "%Y-%m-%d %H:%M" 15 | SUPERUSER_ID = 1 16 | 17 | if hasattr(sys, 'frozen'): 18 | # When running on compiled windows binary, we don't have access to package loader. 19 | path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'static')) 20 | loader = jinja2.FileSystemLoader(path) 21 | else: 22 | loader = jinja2.PackageLoader('odoo.addons.mobile', "static") 23 | 24 | env = jinja2.Environment('<%', '%>', '${', '}', '%', loader=loader, autoescape=True) 25 | 26 | 27 | class MobileGridLabel(models.Model): 28 | """ 29 | 30 | """ 31 | _name = 'mobile.grid.label' 32 | 33 | name = fields.Char(u'名称') 34 | sequence = fields.Integer(u'顺序') 35 | 36 | 37 | class MobileAction(models.Model): 38 | _name = 'mobile.action' 39 | _rec_name = 'mobile_grid_id' 40 | 41 | def _compute_mobile_view_id(self): 42 | for action_id in self: 43 | view_id = self.env['mobile.view'].search([('mobile_action_id', '=', action_id.id)], limit=1) 44 | action_id.mobile_view_id = view_id.id 45 | 46 | model_id = fields.Many2one('ir.model', u'模型名称') 47 | name = fields.Char(u'名称') 48 | limit = fields.Integer('limit') 49 | offset = fields.Integer('offset') 50 | order = fields.Char('order') 51 | context = fields.Char('context') 52 | mobile_grid_id = fields.Many2one('mobile.grid', u'Grid ID') 53 | mobile_view_id = fields.Many2one('mobile.view', compute='_compute_mobile_view_id', string=u'Grid ID') 54 | 55 | _sql_constraints =[ 56 | ('model_mobile_grid_id_field_id_uniq', 'unique (mobile_grid_id)', u'一个菜单只能对应一个动作'), 57 | ] 58 | 59 | 60 | class MobileView(models.Model): 61 | _name = 'mobile.view' 62 | _rec_name = 'mobile_action_id' 63 | 64 | mobile_action_id = fields.Many2one('mobile.action', u'动作') 65 | mobile_field_ids = fields.One2many('mobile.field', 'view_id', string=u'视图表', copy=True) 66 | no_form = fields.Boolean(u'不显示form', defult=True) 67 | model_id = fields.Many2one('ir.model', u'模型名称', copy=True) 68 | domain_ids = fields.One2many('mobile.domain', 'view_id', string="domain", copy=True) 69 | view_type = fields.Selection([('tree', u'列表视图'), ('card', u'看板'), 70 | ('view_form', u'表单'), ('edit_form', '编辑表单')], u'view type', copy=True) 71 | button_ids = fields.One2many('mobile.button', 'view_id', string='buttons', copy=True) 72 | show_form_view = fields.Many2one('mobile.view', u'展示表单', copy=True) 73 | context = fields.Text(u'附加值') 74 | 75 | _defaults = { 76 | 'no_form': True 77 | } 78 | 79 | _sql_constraints =[ 80 | ('model_mobile_action_id_field_id_uniq', 'unique (mobile_action_id)', u'一个动作只能对应一个主视图'), 81 | ] 82 | 83 | 84 | class One2ManyField(models.Model): 85 | _name = 'one.many.field' 86 | 87 | mobile_field_ids = fields.Many2many('mobile.field', 'view_id', string=u'视图表') 88 | 89 | 90 | class MobileDomain(models.Model): 91 | _name = 'mobile.domain' 92 | _order = 'sequence' 93 | 94 | view_id = fields.Many2one('mobile.view', string='view', copy=True) 95 | domain = fields.Char(u'domain', copy=True) 96 | sequence = fields.Integer(u'顺序', copy=True) 97 | name = fields.Char(u'名称', copy=True) 98 | 99 | 100 | class MobileButton(models.Model): 101 | _name = 'mobile.button' 102 | 103 | name = fields.Char(u'名称', copy=True) 104 | button_method = fields.Char(u'方法名', copy=True) 105 | show_condition = fields.Char(u'显示前提', copy=True, default='[]') 106 | view_id = fields.Many2one('mobile.view', string=u'视图', copy=True) 107 | group_ids = fields.Many2many('res.groups', 'button_groups_rel', 'button_id', 'group_id', string='用户组') 108 | 109 | 110 | class MobileField(models.Model): 111 | _name = 'mobile.field' 112 | _order = 'sequence' 113 | 114 | @api.model 115 | def _get_field_types(self): 116 | # retrieve the possible field types from the field classes' metaclass 117 | return sorted((key, key) for key in fields.MetaField.by_type) 118 | 119 | sequence = fields.Integer(u'序列') 120 | view_id = fields.Many2one('mobile.view', u'视图ID', copy=True) 121 | ir_field = fields.Many2one('ir.model.fields', u'字段', copy=True) 122 | domain = fields.Char(u'domain') 123 | field_type = fields.Selection(selection='_get_field_types', related="ir_field.ttype", string=u'字段类型', readonly=True, copy=True) 124 | field_relation = fields.Char(related="ir_field.relation", string=u'字段关联', readonly=True, copy=True) 125 | field_selection = fields.Char(related="ir_field.selection", string=u'选择项目', readonly=True, copy=True) 126 | model_id = fields.Many2one('ir.model', string=u'类型', copy=True) 127 | required = fields.Boolean(u'必输', copy=True) 128 | readonly = fields.Boolean(u'只读', copy=True) 129 | invisible = fields.Boolean(u'不可见', copy=True) 130 | #is_show_edit_form = fields.Boolean(u'form不可见', copy=True) 131 | #is_show_form_tree = fields.Boolean(u'tree不可见', copy=True) 132 | field_id = fields.Many2one('mobile.field', 'field_id', copy=True) 133 | many_field = fields.One2many('mobile.field', 'field_id', string='one2many', copy=True) 134 | 135 | 136 | class MobileGrid(models.Model): 137 | _name = 'mobile.grid' 138 | _rec_name = 'title' 139 | _order = 'sequence' 140 | 141 | def _compute_mobile_action_id(self): 142 | 143 | for grid in self: 144 | action_id = self.env['mobile.action'].search([('mobile_grid_id', '=', grid.id)], limit=1) 145 | grid.mobile_action_id = action_id.id 146 | 147 | label_id = fields.Many2one('mobile.grid.label', u'分类') 148 | sequence = fields.Integer(related='label_id.sequence', string=u'顺序', readonly=True) 149 | image = fields.Binary(u'图片') 150 | mobile_action_id = fields.Many2one('mobile.action', compute='_compute_mobile_action_id', string=u'动作') 151 | title = fields.Char(u'名称') 152 | 153 | 154 | view_type = { 155 | 'tree': 'Tree', 156 | 'card': 'OdooCard' 157 | } 158 | 159 | 160 | class MobileController(http.Controller): 161 | 162 | @http.route('/odoo/mobile', auth='public') 163 | def odoo_mobile(self, **kwargs): 164 | template = env.get_template("index.html") 165 | return template.render() 166 | 167 | @http.route('/odoo/mobile/get/all/grid_data', auth='none', type='http', methods=['GET'], csrf=False) 168 | def get_all_grid_data(self, *args, **kwargs): 169 | print SUPERUSER_ID 170 | uid = request.session.get('uid') or SUPERUSER_ID 171 | grid_obj = request.env['mobile.grid'].sudo() 172 | allGridData = {} 173 | for grid in grid_obj.search([]): 174 | allGridData.setdefault(grid.label_id, []).append({ 175 | 'title': grid.title, 176 | 'actionId': grid.mobile_action_id.id, 177 | 'image': 'data:image/png;base64,' + grid.image 178 | }) 179 | gridList = [{'groupTitle': label.name, 'sequence': label.sequence, 180 | 'gridCols': 4, 'gridRow': row} for label, row in allGridData.iteritems()] 181 | gridList = sorted(gridList, key=lambda grid: grid.get('sequence')) 182 | return json.dumps(gridList) 183 | 184 | @http.route('/odoo/mobile/get/action/views', auth='none', type='http', methods=['GET'],csrf=False) 185 | def get_action_views(self, **args): 186 | action_id = int(args.get('actionId', 0)) 187 | uid = request.session.get('uid') or SUPERUSER_ID 188 | action_row = request.env['mobile.action'].sudo().browse(action_id) 189 | views_data = [{'title': domain.name, 190 | 'sequence': domain.sequence, 191 | 'domain': domain.domain} for domain in action_row.mobile_view_id.domain_ids] 192 | sorted(views_data, key=lambda view: view.get('sequence')) 193 | return_val = { 194 | 'title': action_row.name, 195 | 'modelID': action_row.model_id.id, 196 | 'view_id': action_row.mobile_view_id.id, 197 | 'noForm': action_row.mobile_view_id.no_form, 198 | 'model': action_row.model_id.model, 199 | 'limit': action_row.limit or 6, 200 | 'offset': action_row.offset or 6, 201 | 'order': action_row.order or 'id DESC', 202 | 'context': action_row.mobile_view_id.context, 203 | 'viewsData': views_data, 204 | 'view_type': view_type.get(action_row.mobile_view_id.view_type) 205 | } 206 | return json.dumps(return_val) 207 | 208 | @http.route('/odoo/mobile/get/list/view/data', auth='none', type='http', methods=['GET'],csrf=False) 209 | def get_action_form_pre_view(self, **args): 210 | action_id = int(args.get('actionId', '0')) 211 | offset = int(args.get('offset', '0')) 212 | limit = int(args.get('limit', '0')) 213 | order = args.get('order', 'id DESC') 214 | domain = eval(args.get('domain', '[]')) 215 | view_id = int(args.get('view_id', '0')) 216 | if not args.get('model'): 217 | return json.dumps({}) 218 | model_name = args.get('model') 219 | if not model_name: 220 | return json.dumps({}) 221 | uid = request.session.get('uid') or SUPERUSER_ID 222 | record_rows = request.env[model_name].sudo().search(domain, offset=offset, limit=limit, order=order) 223 | return_val = [] 224 | for view_row in request.env['mobile.view'].sudo().browse(view_id): 225 | return_val = self.get_view_type_function(view_row.view_type)(view_row, record_rows, model_name) 226 | return json.dumps(return_val) 227 | return json.dumps(return_val) 228 | 229 | def get_view_type_function(self, type): 230 | type_dict = { 231 | 'card': self.get_card_view_data, 232 | 'tree': self.get_tree_view_data 233 | } 234 | return type_dict.get(type) 235 | 236 | def get_all_field_setting(self, field): 237 | return { 238 | 'title': field.ir_field.field_description, 239 | 'type': field.field_type, 240 | 'value': '', 241 | 'required': field.required, 242 | 'readonly': field.readonly, 243 | 'invisible': field.invisible, 244 | 'name': field.ir_field.name, 245 | } 246 | 247 | def get_tree_view_data(self, view_row, record_rows, model_name): 248 | return_val = [] 249 | all_field = [] 250 | for field in view_row.mobile_field_ids: 251 | all_field.append(self.get_all_field_setting(field)) 252 | for button in view_row.button_ids: 253 | domain = eval(button.show_condition or '[]') + [('id', 'in', [record.id for record in record_rows])] 254 | mode_ids = request.env[model_name].sudo().search(domain) 255 | all_field.append({ 256 | 'title': button.name, 257 | 'type': 'button', 258 | 'value': button.button_method, 259 | 'user_ids': [user.id for group in button.group_ids for user in group.users], 260 | 'model': model_name, 261 | 'ids': mode_ids, 262 | 'invisible': button.show_condition 263 | }) 264 | for record in record_rows: 265 | new_fields = copy.deepcopy(all_field) 266 | [field.update(self.card_show_val(record, field)) 267 | for field in new_fields] 268 | tree_val = { 269 | 'title': record['display_name'], 270 | 'id': record.id, 271 | 'meta': new_fields 272 | } 273 | return_val.append(tree_val) 274 | return return_val 275 | 276 | def get_card_view_data(self, view_row, record_rows, model_name): 277 | return_val = [] 278 | all_field = [] 279 | for field in view_row.mobile_field_ids: 280 | all_field.append(self.get_all_field_setting(field)) 281 | for button in view_row.button_ids: 282 | domain = eval(button.show_condition or '[]') + [('id', 'in', [record.id for record in record_rows])] 283 | mode_ids = request.env[model_name].sudo().search(domain) 284 | all_field.append({ 285 | 'title': button.name, 286 | 'type': 'button', 287 | 'value': button.button_method, 288 | 'user_ids': [user.id for group in button.group_ids for user in group.users], 289 | 'model': model_name, 290 | 'ids': mode_ids, 291 | 'invisible': button.show_condition 292 | }) 293 | for record in record_rows: 294 | new_fields = copy.deepcopy(all_field) 295 | [field.update(self.card_show_val(record, field)) 296 | for field in new_fields] 297 | return_val.append({'fieldVals': new_fields, 'id': record.id}) 298 | return return_val 299 | 300 | def card_show_val(self, record, field): 301 | return_value = {} 302 | if field.get('type') not in ('button', 'one2many', 'many2one'): 303 | return_value.update({'value': self.card_field_type_get_val(field, record)}) 304 | elif field.get('type') == 'many2one': 305 | options = self.card_field_type_get_val(field, record) 306 | return_value.update({'options': self.card_field_type_get_val(field, record), 307 | 'value': options and options[0] and options[0].get('key')}) 308 | elif field.get('type') == 'many2many': 309 | options = self.card_field_type_get_val(field, record) 310 | return_value.update({'options': self.card_field_type_get_val(field, record), 311 | 'value': options and options[0] and options[0].get('key')}) 312 | elif field.get('type') == 'button': 313 | return_value.update( 314 | {'invisible': False if record['id'] in field.get('ids') and self._uid in field.get('user_ids', []) else True}) 315 | elif field.get('type') == 'one2many': 316 | value, ids = self.get_show_tree_one2many(record, field) 317 | return_value.update({'value': value, 318 | 'ids': ids, 319 | 'table': self.get_record_one2many(record, field, 320 | context={'table': True}) 321 | }) 322 | elif field.get('type') == 'selection': 323 | value = self.card_field_type_get_val(record, field) 324 | return_value.update({'value': value, 325 | 'options': [{'key': value[0], 'value': value[1]} for value in 326 | record._fields[field.get('name')].selection] 327 | }) 328 | return return_value 329 | 330 | def get_show_tree_one2many(self, record, field): 331 | all_tree_row, table_body, line_ids = [], [], [] 332 | many_field = field.get('many_field', []) 333 | if not (many_field and field.get('name')): 334 | return '', '' 335 | for line in record[field.get('name')]: 336 | line_ids.append(line['id']) 337 | new_fields = copy.deepcopy(many_field) 338 | [field.update(self.card_show_val(line, field, context=dict(context, **{'table': True}))) 339 | for field in new_fields] 340 | tree_val = { 341 | 'title': line['display_name'], 342 | 'id': line.id, 343 | 'meta': new_fields 344 | } 345 | all_tree_row.append(tree_val) 346 | return all_tree_row, line_ids 347 | 348 | def card_field_type_get_val(self, field, record): 349 | type = field.get('type') 350 | value = record[field.get('name')] 351 | if not value: 352 | return '' 353 | if type in ('char', 'text', 'boolean', 'integer'): 354 | return value 355 | elif type == 'many2one': 356 | if value and value.name_get(): 357 | name = value.name_get() 358 | return [{'key': name[0][0], 'value': name[0][1]}] 359 | elif type == 'date': 360 | date_obj = datetime.datetime.strptime(value, ISODATEFORMAT) 361 | return (date_obj + relativedelta(hours=8)).strftime(ISODATEFORMAT) 362 | elif type == 'datetime': 363 | date_obj = datetime.datetime.strptime(value, ISODATETIMEFORMAT) 364 | return (date_obj + relativedelta(hours=8)).strftime(MOBILEDATETIMEFORMAT) 365 | elif type == 'float': 366 | return float_round(value, precision_digits=2) 367 | elif type == 'selection': 368 | return value 369 | return '' 370 | 371 | def get_record_one2many(self,record, field, context={}): 372 | table_header, table_body = [], [] 373 | many_field = field.get('many_field', []) 374 | if not (many_field and field.get('name')): 375 | return '' 376 | for son_field in many_field: 377 | table_header.append(son_field.get('title')) 378 | for line in record[field.get('name')]: 379 | new_fields = copy.deepcopy(many_field) 380 | [field.update(self.card_show_val(line, field)) 381 | for field in new_fields] 382 | table_body.append(new_fields) 383 | return {'tableTh': table_header, 'tableBody': table_body} 384 | 385 | # /odoo/button/method 386 | @http.route('/odoo/mobile/button/method', auth='none', type='http', methods=['GET'],csrf=False) 387 | def mobile_button_method(self, **args): 388 | uid = request.session.get('uid') or SUPERUSER_ID 389 | model = args.get('model') 390 | method = args.get('method') 391 | ids = int(args.get('ids')) 392 | model_obj = request.env[model].sudo().browse(ids) 393 | if model_obj and hasattr(model_obj, method) and ids: 394 | try: 395 | getattr(model_obj, method)(ids) 396 | return json.dumps({'success': True}) 397 | except Exception as exc: 398 | if isinstance(exc, basestring): 399 | return json.dumps({'success': False, 'errMsg': u'%s' % exc}) 400 | if exc and hasattr(exc, 'value'): 401 | return json.dumps({'success': False, 'errMsg': u'%s' % exc.value}) 402 | if exc and hasattr(exc, 'message') and hasattr(exc, 'diag'): 403 | return json.dumps({'success': False, 'errMsg': u'%s' % exc.diag.message_primary}) 404 | elif exc and hasattr(exc, 'message'): 405 | return json.dumps({'success': False, 'errMsg': u'%s' % exc.message}) 406 | elif exc and hasattr(exc, dict): 407 | return json.dumps({'success': False, 'errMsg': u'%s' % exc.get('message')}) 408 | 409 | def get_many_field_value(self, field): 410 | field_value = self.get_all_field_setting(field) 411 | if field.field_type == 'many2one': 412 | field_value.update({'model': field.ir_field.relation, 'domain': field.domain, 'options': []}) 413 | return field_value 414 | 415 | def set_default_val(self,field_value, default_val): 416 | if default_val.get(field_value.get('name')): 417 | if field_value.get('type') == 'many2one': 418 | options = request.env[field_value.get('model')].name_get(default_val.get(field_value.get('name'))) 419 | return {'value': default_val.get(field_value.get('name')), 'options': [{'key': option[0], 'value':option[1]} for option in options]} 420 | else: 421 | return {'value': default_val.get(field_value.get('name'))} 422 | return {} 423 | 424 | def get_form_view_data(self, view_row, record_ids, model_name): 425 | all_field = [] 426 | default_val = request.env[model_name].sudo().default_get([field.ir_field.name for field 427 | in view_row.mobile_field_ids]) 428 | for field in view_row.mobile_field_ids: 429 | field_value = self.get_all_field_setting(field) 430 | if field.field_type == 'many2one': 431 | field_value.update({'model': field.ir_field.relation, 'domain': field.domain or []}) 432 | if field.field_type == 'selection': 433 | field_value.update({'options': [{'key': value[0], 'value': value[1]} for value in 434 | request.env[model_name]._fields[field_value.get('name')].selection]}) 435 | if field.field_type == 'one2many': 436 | field_value.update({'many_field': [self.get_many_field_value(field) for field in field.many_field], 437 | 'value': []}) 438 | if field.field_type == 'many2many': 439 | field_value.update({'model': field.ir_field.relation, 'domain': field.domain or []}) 440 | 441 | field_value.update(self.set_default_val(field_value, default_val)) 442 | all_field.append(field_value) 443 | for button in view_row.button_ids: 444 | domain = eval(button.show_condition or '[]') + [('id', '=', record_ids)] 445 | mode_ids = request.env[model_name].search(domain) 446 | all_field.append({ 447 | 'title': button.name, 448 | 'type': 'button', 449 | 'value': button.button_method, 450 | 'user_ids': [user.id for group in button.group_ids for user in group.users], 451 | 'model': model_name, 452 | 'ids': mode_ids, 453 | 'invisible': button.show_condition 454 | }) 455 | for record in request.env[model_name].browse(record_ids): 456 | new_fields = copy.deepcopy(all_field) 457 | [field.update(self.card_show_val(record, field)) 458 | for field in new_fields] 459 | return {'fieldVals': new_fields, 'id': record.id} 460 | 461 | return {'fieldVals': all_field, 'id': 0} 462 | 463 | # /odoo/form/view/data 464 | @http.route('/odoo/mobile/form/view/data', auth='none', type='http', methods=['GET'],csrf=False) 465 | def get_odoo_view_data(self, **args): 466 | uid = request.session.get('uid') or SUPERUSER_ID 467 | model_name = args.get('model', '') 468 | view_id = int(args.get('viewId', '0')) 469 | id = int(args.get('id', '0')) 470 | view_row = request.env['mobile.view'].sudo().browse(view_id) 471 | return_val = {} 472 | if model_name: 473 | return_val = self.get_form_view_data(view_row.show_form_view, id, model_name) 474 | return json.dumps(return_val) 475 | 476 | @http.route('/odoo/mobile/model/name_search', auth='none', type='http', methods=['GET'],csrf=False ) 477 | def get_odoo_model_name_search(self, **args): 478 | uid = request.session.get('uid') or SUPERUSER_ID 479 | model_name = args.get('model') 480 | limit = int(args.get('limit', '15')) 481 | value = args.get('value', '') 482 | domain = eval(args.get('domain', '[]')) 483 | model_row = request.env[model_name] 484 | return_val_list_dict = [] 485 | if model_row: 486 | if value: 487 | return_val = getattr(model_row, 'name_search')(cr, uid, name=value, operator='ilike', args=domain, 488 | limit=limit, context=context) 489 | else: 490 | return_ids = getattr(model_row, 'search')(cr, uid, domain, limit=limit, context=context) 491 | return_val = getattr(model_row, 'name_get')(cr, uid, return_ids, context=context) 492 | return_val_list_dict = [{'key': val[0], 'value': val[1]} for val in return_val] 493 | return json.dumps(return_val_list_dict) 494 | 495 | def construct_model_vals(self, id, vals): 496 | dict_val = {} 497 | for val in vals: 498 | if not val.get('value'): 499 | continue 500 | if val.get('type') in ('text', 'char', 'date', 'selection') \ 501 | and val.get('name') != 'id': 502 | dict_val.update({val.get('name'): val.get('value')}) 503 | elif val.get('type') in ['datetime']: 504 | date_obj = datetime.datetime.strptime(val.get('value', 0) + ':00', ISODATETIMEFORMAT) 505 | dict_val.update({val.get('name'): (date_obj - relativedelta(hours=8)).strftime(ISODATETIMEFORMAT)}) 506 | elif val.get('type') in ['integer', 'many2one']: 507 | dict_val.update({val.get('name'): int(val.get('value', 0))}) 508 | elif val.get('type') in ['float']: 509 | dict_val.update({val.get('name'): float(val.get('value', 0))}) 510 | elif val.get('type') in ['one2many']: 511 | line_vals = [] 512 | line_ids, origin_ids = [], val.get('ids') 513 | for line_val in val.get('value'): 514 | line_ids.append(line_val.get('id')) 515 | record_row = {} 516 | for field in line_val.get('meta'): 517 | record_row.update({field.get('name'): field.get('value')}) 518 | if not id or not line_val.get('id'): 519 | line_vals.append((0, 0, record_row)) 520 | else: 521 | line_vals.append((1, line_val.get('id'), record_row)) 522 | if origin_ids and origin_ids: 523 | for delete_id in set(origin_ids) - set(line_ids): 524 | line_vals.append((2, delete_id, False)) 525 | dict_val.update({val.get('name'): line_vals}) 526 | elif val.get('type') in ['many2many']: 527 | dict_val.update({val.get('name'): [(6, 0, val.get('value', []))]}) 528 | return dict_val 529 | 530 | @http.route('/odoo/mobile/save/record', auth='none', type='json', csrf=False) 531 | def create_new_record(self, **args): 532 | uid = request.session.get('uid') or SUPERUSER_ID 533 | model = request.jsonrequest.get('model') 534 | vals = request.jsonrequest.get('value') 535 | id = request.jsonrequest.get('id') 536 | vals = self.construct_model_vals(id, vals) 537 | context_val = eval(request.jsonrequest.get('context', '{}') or '{}') 538 | try: 539 | if not id: 540 | vals.update(context_val.get('default_vals', {})) 541 | request.env[model].sudo().create(vals) 542 | return {'success': True, 'errMsg': u'创建成功!'} 543 | else: 544 | request.env[model].sudo().browse(id).write(vals) 545 | return {'success': True, 'errMsg': u'修改成功!'} 546 | except Exception as exc: 547 | if isinstance(exc, basestring): 548 | return {'success': False, 'errMsg': u'%s' % exc} 549 | if exc and hasattr(exc, 'value'): 550 | return {'success': False, 'errMsg': u'%s' % exc.value} 551 | if exc and hasattr(exc, 'message') and hasattr(exc, 'diag'): 552 | return {'success': False, 'errMsg': u'%s' % exc.diag.message_primary} 553 | elif exc and hasattr(exc, 'message'): 554 | return {'success': False, 'errMsg': u'%s' % exc.message} 555 | 556 | @http.route('/odoo/mobile/login', auth='public', type='json', csrf=False) 557 | def login_mobile(self, *args, **kwargs): 558 | print kwargs 559 | name = kwargs.get('name') 560 | password = kwargs.get('password') 561 | ensure_db() 562 | if not request.uid: 563 | request.uid = odoo.SUPERUSER_ID 564 | uid = request.env['res.users'].sudo().authenticate(request.db, name, password, None) 565 | if uid: 566 | return {'success': True, 'errMsg': u'登录成功!', 'uid': uid} 567 | else: 568 | error = "Wrong login/password" 569 | return {'success': False, 'errMsg': error} 570 | -------------------------------------------------------------------------------- /mobile/mobile_model.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbert-yuan/odoo_mobile/a2ed286a9b3000832ca363f273dac59515eae2de/mobile/mobile_model.pyc -------------------------------------------------------------------------------- /mobile/mobile_model.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | mobile.grid.tree 8 | mobile.grid 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Grid 20 | mobile.grid 21 | form 22 | tree 23 | 24 |

25 | Click to register new expenses. 26 |

27 |

28 |
29 |
30 | 32 | 33 | 34 | mobile action tree 35 | mobile.action 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | action 50 | mobile.action 51 | form 52 | tree 53 | 54 |

55 | Click to register new expenses. 56 |

57 |

58 |
59 |
60 | 62 | 63 | 64 | mobile field tree 65 | mobile.field 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | mobile.field.tree 82 | mobile.field 83 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
99 |
100 |
101 | 102 | action 103 | mobile.field 104 | form 105 | tree,form 106 | 107 |

108 | Click to register new expenses. 109 |

110 |

111 |
112 |
113 | 114 | 115 | 116 | 117 | 118 | mobile.view.tree 119 | mobile.view 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | mobile.view.form 131 | mobile.view 132 | 133 |
134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 |
145 |
146 |
147 | 148 | action 149 | mobile.view 150 | form 151 | tree,form 152 | 153 |

154 | Click to register new expenses. 155 |

156 |

157 |
158 |
159 | 161 | 162 | 163 | mobile.domain.form 164 | mobile.domain 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | domain 175 | mobile.domain 176 | form 177 | tree 178 | 179 |

180 | Click to register new expenses. 181 |

182 |

183 |
184 |
185 | 186 | 187 | mobile.button.form 188 | mobile.button 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | mobile.button.form 200 | mobile.button 201 | 202 |
203 | 204 | 205 | 206 | 207 | 208 | 209 |
210 |
211 |
212 | 213 | button 214 | mobile.button 215 | form 216 | tree 217 | 218 |

219 | Click to register new expenses. 220 |

221 |

222 |
223 |
224 |
225 |
-------------------------------------------------------------------------------- /mobile/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink 2 | group_user_model_mobile_grid_label,group_user_model_mobile_grid_label,model_mobile_grid_label,base.group_user,1,1,1,0 3 | group_user_model_mobile_action,group_user_model_mobile_action,model_mobile_action,base.group_user,1,1,1,0 4 | group_user_model_mobile_view,group_user_model_mobile_view,model_mobile_view,base.group_user,1,1,1,0 5 | group_user_model_one_many_field,group_model_one_many_field,model_one_many_field,base.group_user,1,1,1,0 6 | group_user_model_mobile_domain,group_user_model_mobile_domain,model_mobile_domain,base.group_user,1,1,1,0 7 | group_user_model_mobile_button,group_user_model_mobile_button,model_mobile_button,base.group_user,1,1,1,0 8 | group_user_model_mobile_field,group_user_model_mobile_field,model_mobile_field,base.group_user,1,1,1,0 9 | group_user_model_mobile_grid,group_user_model_mobile_grid,model_mobile_grid,base.group_user,1,1,1,0 10 | -------------------------------------------------------------------------------- /mobile/static/html/css/app.5914b78bd7790e9371ccc0f4cfc5093c.css: -------------------------------------------------------------------------------- 1 | body{background-color:#fbf9fe}body,html{height:100%;width:100%;overflow-x:hidden}.demo-icon-22{font-family:vux-demo;font-size:22px;color:#888}.vux-demo-tabbar .weui-bar__item_on .demo-icon-22{color:#f70968}.vux-demo-tabbar .weui-tabbar_item.weui-bar__item_on .vux-demo-tabbar-icon-home{color:#35495e}.demo-icon-22:before{content:attr(icon)}.vux-demo-tabbar-component{background-color:#f70968;color:#fff;border-radius:7px;padding:0 4px;line-height:14px}.weui-tabbar__icon+.weui-tabbar__label{margin-top:0!important}.vux-demo-header-box{z-index:100;position:absolute;width:100%;left:0;top:0}@font-face{font-family:vux-demo;src:url(//at.alicdn.com/t/font_70323_wlronpvr565yiudi.eot);src:url(//at.alicdn.com/t/font_70323_wlronpvr565yiudi.eot#iefix) format("embedded-opentype"),url(//at.alicdn.com/t/font_70323_wlronpvr565yiudi.woff) format("woff"),url(//at.alicdn.com/t/font_70323_wlronpvr565yiudi.ttf) format("truetype"),url(//at.alicdn.com/t/font_70323_wlronpvr565yiudi.svg#iconfont) format("svg")}.demo-icon{font-family:vux-demo;font-size:20px;color:#04be02}.demo-icon-big{font-size:28px}.demo-icon:before{content:attr(icon)}.router-view{width:100%;top:46px}.vux-pop-in-enter-active,.vux-pop-out-enter,.vux-pop-out-enter-active,.vux-pop-out-leave-active{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.vux-pop-in-enter,.vux-pop-out-leave-active{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.vux-pop-in-leave-active{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.menu-title{color:#888}.weui-cell_radio>*{pointer-events:none}.vux-radio-icon{width:24px;height:24px;display:inline-block;margin-right:5px}.vux-radio-icon,.vux-radio-label{vertical-align:middle}.weui-cells_radio.vux-radio-disabled .weui-check:checked+.weui-icon-checked:before{opacity:.5}.vux-blank-half:before{content:"\2002";speak:none}.vux-blank-full:before{content:"\2003";speak:none}.vux-no-group-title{margin-top:.77em}.vux-group-footer-title.weui-cells__title{margin-top:.3em;margin-bottom:.77em;padding-top:0;font-size:12px}.vux-cell-placeholder,.vux-cell-value{color:#999}.vux-tap-active{tap-highlight-color:transparent;-webkit-user-select:none;user-select:none}.vux-tap-active:active{background-color:#ececec}.vux-label{word-wrap:break-word;word-break:break-all}.vux-label,.weui-cell__ft .weui-loading{display:inline-block}.weui-cell__ft.vux-cell-align-left{text-align:left}.weui-cell.vux-cell-no-border-intent:before{left:0}.weui-cell_access .weui-cell__ft.vux-cell-arrow-down:after{-webkit-transform:matrix(.71,.71,-.71,.71,0,0) rotate(90deg);transform:matrix(.71,.71,-.71,.71,0,0) rotate(90deg)}.weui-cell_access .weui-cell__ft.vux-cell-arrow-up:after{-webkit-transform:matrix(.71,.71,-.71,.71,0,0) rotate(-90deg);transform:matrix(.71,.71,-.71,.71,0,0) rotate(-90deg)}.vux-cell-arrow-transition:after{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.vux-cell-disabled .vux-label{color:#b2b2b2}.vux-cell-disabled.weui-cell_access .weui-cell__ft:after{border-color:#e2e2e2}.vux-label-desc{font-size:14px;color:#666}.vux-badge{display:inline-block;text-align:center;background:#f74c31;color:#fff;font-size:12px;height:16px;line-height:16px;border-radius:8px;padding:0 6px;background-clip:padding-box;vertical-align:middle}.vux-badge-single{padding:0;width:16px}.vux-badge-dot{height:auto;padding:5px}.vux-drawer{display:block;position:relative;top:0;left:0;width:100%;height:100%}.vux-drawer>.vux-drawer-body{height:100%;position:absolute;top:0;left:0;right:0;bottom:0;-webkit-transition:visibility .38s,-webkit-transform .38s ease-in-out;transition:visibility .38s,-webkit-transform .38s ease-in-out;transition:transform .38s ease-in-out,visibility .38s;transition:transform .38s ease-in-out,visibility .38s,-webkit-transform .38s ease-in-out}.vux-drawer>.vux-drawer-body>.drawer-mask{z-index:9999;position:absolute;top:0;left:0;right:0;bottom:0;visibility:hidden;opacity:0;-webkit-transition:opacity .38s ease-in-out,visibility .38s ease-in-out;transition:opacity .38s ease-in-out,visibility .38s ease-in-out;background-color:rgba(0,0,0,.3)}.vux-drawer>.vux-drawer-body>.vux-drawer-active{visibility:visible;opacity:1}.vux-drawer>.vux-drawer-content{background-color:#fff;position:absolute;top:0;height:100%;overflow:hidden;pointer-events:none;visibility:hidden;-webkit-transition:visibility .38s,-webkit-transform .38s ease-in-out;transition:visibility .38s,-webkit-transform .38s ease-in-out;transition:transform .38s ease-in-out,visibility .38s;transition:transform .38s ease-in-out,visibility .38s,-webkit-transform .38s ease-in-out;will-change:none}.vux-drawer>.drawer-left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.vux-drawer>.drawer-right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.vux-drawer>.vux-drawer-active{pointer-events:inherit;visibility:visible;-webkit-transform:translateX(0);transform:translateX(0)}.weui-actionsheet{position:fixed;left:0;bottom:0;-webkit-transform:translateY(100%);transform:translateY(100%);-webkit-backface-visibility:hidden;backface-visibility:hidden;z-index:5000;width:100%;background-color:#efeff4;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.weui-actionsheet__menu{background-color:#fff}.weui-actionsheet__action{margin-top:6px;background-color:#fff}.weui-actionsheet__cell{position:relative;padding:10px 0;text-align:center;font-size:18px}.weui-actionsheet__cell:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #d9d9d9;color:#d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-actionsheet__cell:active{background-color:#ececec}.weui-actionsheet__cell:first-child:before{display:none}.weui-skin_android .weui-actionsheet{position:fixed;left:50%;top:50%;bottom:auto;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:274px;box-sizing:border-box;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:transparent;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.weui-skin_android .weui-actionsheet__action{display:none}.weui-skin_android .weui-actionsheet__menu{border-radius:2px;box-shadow:0 6px 30px 0 rgba(0,0,0,.1)}.weui-skin_android .weui-actionsheet__cell{padding:13px 24px;font-size:16px;line-height:1.4;text-align:left}.weui-skin_android .weui-actionsheet__cell:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.weui-skin_android .weui-actionsheet__cell:last-child{border-bottom-left-radius:2px;border-bottom-right-radius:2px}.weui-actionsheet_toggle{-webkit-transform:translate(0);transform:translate(0)}.vux-actionsheet-menu-primary{color:#1aad19}.vux-actionsheet-menu-warn{color:#e64340}.vux-actionsheet-menu-default{color:#000}.vux-actionsheet-menu-disabled{color:#ccc}.vux-actionsheet-mask-enter,.vux-actionsheet-mask-leave-active,.vux-android-actionsheet-enter,.vux-android-actionsheet-leave-active{opacity:0}.vux-actionsheet-mask-enter-active,.vux-actionsheet-mask-leave-active,.vux-android-actionsheet-enter-active,.vux-android-actionsheet-leave-active{-webkit-transition:opacity .3s!important;transition:opacity .3s!important}.vux-button-group{-webkit-touch-callout:none;display:-webkit-box;display:-webkit-flex;display:flex}.vux-button-group>a.vux-button-tab-item-last{border-top-right-radius:32px;border-bottom-right-radius:32px}.vux-button-group>a.vux-button-tab-item-last:after{content:" ";position:absolute;left:0;top:0;width:200%;height:1px;border-right:1px solid #04be02;border-top:1px solid #04be02;border-bottom:1px solid #04be02;border-left:none;color:#04be02;height:200%;-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:scale(.5);transform:scale(.5);z-index:1;border-top-right-radius:32px;border-bottom-right-radius:32px}.vux-button-group>a.vux-button-tab-item-first{border-top-left-radius:32px;border-bottom-left-radius:32px}.vux-button-group>a.vux-button-tab-item-first:after{border:1px solid #04be02;height:200%;border-top-left-radius:32px;border-bottom-left-radius:32px}.vux-button-group>a.vux-button-tab-item-first:after,.vux-button-group>a.vux-button-tab-item-middle:after{content:" ";position:absolute;left:0;top:0;width:200%;color:#04be02;-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:scale(.5);transform:scale(.5)}.vux-button-group>a.vux-button-tab-item-middle:after{height:1px;border-right:1px solid #04be02;border-top:1px solid #04be02;border-bottom:1px solid #04be02;border-left:none;height:200%;z-index:1}.vux-button-group>a{display:block;position:relative;-webkit-box-flex:1;-webkit-flex:1;flex:1;width:100%;height:30px;padding:0;font-size:14px;line-height:31px;text-align:center;color:#999;white-space:nowrap;background:#fdfdfd;-webkit-tap-highlight-color:rgba(255,0,0,0)}.vux-button-group>a:after{background-clip:padding-box;box-sizing:border-box}.vux-button-group>a.vux-button-group-current{color:#fff;background:#04be02}.vux-button-group>a.vux-button-group-current:disabled,.vux-button-group>a:disabled{border-color:#cdcdcd;background:#e5e5e5;box-shadow:0 1px 0 hsla(0,0%,100%,.6);text-shadow:0 1px 0 hsla(0,0%,100%,.8);color:#aaa}.vux-header{position:relative;padding:3px 0;box-sizing:border-box;background-color:#35495e}.vux-header .vux-header-title{line-height:40px;text-align:center;font-size:18px;font-weight:400;color:#fff}.vux-header-title-area,.vux-header .vux-header-title{margin:0 88px;height:40px;width:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vux-header .vux-header-title>span{display:inline-block}.vux-header .vux-header-left,.vux-header .vux-header-right{position:absolute;top:14px;display:block;font-size:14px;line-height:21px;color:#ccc}.vux-header .vux-header-left a,.vux-header .vux-header-left button,.vux-header .vux-header-right a,.vux-header .vux-header-right button{float:left;margin-right:8px;color:#ccc}.vux-header .vux-header-left a:active,.vux-header .vux-header-left button:active,.vux-header .vux-header-right a:active,.vux-header .vux-header-right button:active{opacity:.5}.vux-header .vux-header-left{left:18px}.vux-header .vux-header-left .vux-header-back{padding-left:16px}.vux-header .vux-header-left .left-arrow{position:absolute;width:30px;height:30px;top:-5px;left:-5px}.vux-header .vux-header-left .left-arrow:before{content:"";position:absolute;width:12px;height:12px;border:1px solid #ccc;border-width:1px 0 0 1px;-webkit-transform:rotate(315deg);transform:rotate(315deg);top:8px;left:7px}.vux-header .vux-header-right{right:15px}.vux-header .vux-header-right a,.vux-header .vux-header-right button{margin-left:8px;margin-right:0}.vux-header .vux-header-right .vux-header-more:after{content:"\2022 \2022 \2022 ";font-size:16px}.vux-header-fade-in-right-enter-active{-webkit-animation:fadeinR .5s;animation:fadeinR .5s}.vux-header-fade-in-left-enter-active{-webkit-animation:fadeinL .5s;animation:fadeinL .5s}@-webkit-keyframes fadeinR{0%{opacity:0;-webkit-transform:translateX(150px);transform:translateX(150px)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes fadeinR{0%{opacity:0;-webkit-transform:translateX(150px);transform:translateX(150px)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes fadeinL{0%{opacity:0;-webkit-transform:translateX(-150px);transform:translateX(-150px)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes fadeinL{0%{opacity:0;-webkit-transform:translateX(-150px);transform:translateX(-150px)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.weui-tabbar{display:-webkit-box;display:-webkit-flex;display:flex;position:absolute;z-index:500;bottom:0;width:100%;background-color:#f7f7fa}.weui-tabbar:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #c0bfc4;color:#c0bfc4;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-tabbar__item{display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;padding:5px 0 0;font-size:0;color:#999;text-align:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-tabbar__item.weui-bar__item_on .weui-tabbar__icon,.weui-tabbar__item.weui-bar__item_on .weui-tabbar__icon>i,.weui-tabbar__item.weui-bar__item_on .weui-tabbar__label{color:#09bb07}.weui-tabbar__icon{display:inline-block;width:27px;height:27px}.weui-tabbar__icon>i,i.weui-tabbar__icon{font-size:24px;color:#999}.weui-tabbar__icon img{width:100%;height:100%}.weui-tabbar__label{text-align:center;color:#999;font-size:10px;line-height:1.8}.weui-tab{position:relative;height:100%}.weui-tab__panel{box-sizing:border-box;height:100%;padding-bottom:50px;overflow:auto;-webkit-overflow-scrolling:touch}.weui-tab__content{display:none}.vux-reddot,.vux-reddot-border,.vux-reddot-s{position:relative}.vux-reddot-border:after,.vux-reddot-s:after,.vux-reddot:after{background-color:#f74c31;right:-3px;top:-3px}.vux-reddot-border:after,.vux-reddot-border:before,.vux-reddot-s:after,.vux-reddot:after{content:"";position:absolute;display:block;width:8px;height:8px;border-radius:5px;background-clip:padding-box}.vux-reddot-border:before{background-color:#fff;right:-4px;top:-4px;padding:1px}.vux-reddot-s:after{width:6px;height:6px;top:-5px;right:-5px}.weui-tabbar__icon{position:relative}.weui-tabbar__icon>sup{position:absolute;top:-8px;left:100%;-webkit-transform:translateX(-50%);transform:translateX(-50%);z-index:101}.weui-tabbar__item.vux-tabbar-simple{padding:0;height:50px;line-height:50px}.vux-tabbar-simple .weui-tabbar__label{font-size:14px;line-height:50px}.vux-loading .weui-toast{z-index:5001}.weui-icon_toast.weui-loading{display:inline-block}.vux-mask-enter,.vux-mask-enter-active,.vux-mask-leave-active{position:relative;z-index:1}.vux-loading-no-text .weui-toast{min-height:98px}.weui-toast{position:fixed;z-index:5001;width:7.6em;min-height:7.6em;top:180px;left:50%;margin-left:-3.8em;background:hsla(0,0%,7%,.7);text-align:center;border-radius:5px;color:#fff}.weui-icon_toast{margin:22px 0 0;display:block}.weui-icon_toast.weui-icon-success-no-circle:before{color:#fff;font-size:55px}.weui-icon_toast.weui-loading{margin:30px 0 0;width:38px;height:38px;vertical-align:baseline}.weui-toast__content{margin:0 0 15px}.weui-toast.vux-toast-top{top:10px}.weui-toast.vux-toast-bottom{top:auto;bottom:10px;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.weui-toast.vux-toast-middle{top:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.vux-slide-from-top-enter,.vux-slide-from-top-leave-active{opacity:0;-webkit-transform:translateX(-50%) translateY(-100%)!important;transform:translateX(-50%) translateY(-100%)!important}.vux-slide-from-bottom-enter,.vux-slide-from-bottom-leave-active{opacity:0;-webkit-transform:translateX(-50%) translateY(100%)!important;transform:translateX(-50%) translateY(100%)!important}.vux-slide-from-bottom-enter-active,.vux-slide-from-bottom-leave-active,.vux-slide-from-top-enter-active,.vux-slide-from-top-leave-active{-webkit-transition:all .4s cubic-bezier(.36,.66,.04,1);transition:all .4s cubic-bezier(.36,.66,.04,1)}.weui-toast{-webkit-transform:translateX(-50%);transform:translateX(-50%);margin-left:0!important}.weui-toast.weui-toast_forbidden{color:#f76260}.weui-toast.weui-toast_forbidden .weui-toast__content{margin-top:10px}.weui-toast.weui-toast_text{min-height:0}.weui-toast_text .weui-toast__content{margin:0;padding-top:10px;padding-bottom:10px;border-radius:15px}.weui-toast__content{font-size:16px}.weui-loading_toast .weui-toast__content{margin-top:0}.weui-toast_success .weui-icon_toast:before{content:"\EA08"}.weui-toast_cancel .weui-icon_toast:before{content:"\EA0D"}.weui-toast_forbidden .weui-icon_toast.weui-icon-success-no-circle:before{content:"\EA0B";color:#f76260}.overwrite-title-demo{margin-top:5px}.weui-grids{position:relative;overflow:hidden}.weui-grids:before{right:0;height:1px;border-top:1px solid #d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-grids:after,.weui-grids:before{content:" ";position:absolute;left:0;top:0;color:#d9d9d9}.weui-grids:after{width:1px;bottom:0;border-left:1px solid #d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-grid{position:relative;float:left;padding:20px 10px;width:33.33333333%;box-sizing:border-box}.weui-grid:before{top:0;width:1px;border-right:1px solid #d9d9d9;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-grid:after,.weui-grid:before{content:" ";position:absolute;right:0;bottom:0;color:#d9d9d9}.weui-grid:after{left:0;height:1px;border-bottom:1px solid #d9d9d9;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-grid:active{background-color:#ececec}.weui-grid__icon{width:28px;height:28px;margin:0 auto}.weui-grid__icon img{display:block;width:100%;height:100%}.weui-grid__icon+.weui-grid__label{margin-top:5px}.weui-grid__label{display:block;text-align:center;color:#000;font-size:14px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.weui-grid.vux-grid-item-no-border:before,.weui-grids.vux-grid-no-lr-borders:after{display:none}.divcss6_right{margin-top:100%;position:absolute;margin-left:85%}.floating-button{position:absolute;right:16px;bottom:66px;width:56px;height:56px;border-radius:50%;z-index:1500;box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23);background-color:#2196f3;color:#fff;overflow:hidden;-webkit-transition-duration:.3s;transition-duration:.3s;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.floating-button.active-state,html:not(.watch-active-state) .floating-button:active{background:#0c82df}.floating-button-toolbar,.speed-dial{position:absolute;right:16px;bottom:36px;z-index:1500}.floating-button-toolbar .floating-button,.speed-dial .floating-button{right:0;bottom:0;position:relative}i.icon.icon-plus{width:24px;height:24px;font-size:0;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg fill='%23FFF' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E")}.weui-cells.vux-search_show{overflow-y:auto!important;position:fixed!important;width:100%!important;height:auto!important}.weui-cells.vux-search_show .weui-cell:last-child{margin-bottom:0!important}.weui-media-box__title{font-size:15px;color:#080209;padding:5px 0 0 10px}.weui-panel__hd{color:#080209}.weui-media-box__info{padding:0 0 10px 10px;margin-top:8px}.weui-media-box__info__meta{color:#92888f}.line_color_value{color:#080209}.custom-primary-red{border-radius:99px!important;border-color:#ce3c39!important;color:#ce3c39!important}.custom-primary-red:active{border-color:rgba(206,60,57,.6)!important;color:rgba(206,60,57,.6)!important;background-color:transparent}.weui-cell_vcode{padding-top:0;padding-right:0;padding-bottom:0}.weui-vcode-btn,.weui-vcode-img{margin-left:5px;height:44px;vertical-align:middle}.weui-vcode-btn{display:inline-block;padding:0 .6em 0 .7em;border-left:1px solid #e5e5e5;line-height:44px;font-size:17px;color:#3cc51f}button.weui-vcode-btn{background-color:transparent;border-top:0;border-right:0;border-bottom:0;outline:0}.weui-vcode-btn:active{color:#52a341}.vux-x-input .vux-x-input-placeholder-right input::-webkit-input-placeholder{text-align:right}.vux-x-input .vux-x-input-placeholder-center input::-webkit-input-placeholder{text-align:center}.vux-input-icon.weui-icon-success:before,.vux-input-icon.weui-icon-warn:before,.vux-x-input .vux-input-icon{font-size:21px}.vux-x-input .weui-icon{padding-left:5px}.vux-x-input.weui-cell_vcode{padding-top:0;padding-right:0;padding-bottom:0}.vux-x-input.disabled .weui-input{text-fill-color:#888;-webkit-text-fill-color:#888;opacity:1}.vux-x-input-right-full{margin-left:5px;height:44px;vertical-align:middle}.vux-x-input-right-full img{height:44px}.vux-x-input-has-right-full{padding-top:0;padding-right:0;padding-bottom:0}.icon-big:before{font-size:93px}.vux-popup-dialog{position:fixed;left:0;bottom:0;width:100%;background:#eee;z-index:501;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;-webkit-transition-duration:.3s;transition-duration:.3s;max-height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}.vux-popup-dialog.vux-popup-left{width:auto;height:100%;top:0;right:auto;bottom:auto;left:0}.vux-popup-dialog.vux-popup-right{width:auto;height:100%;top:0;right:0;bottom:auto;left:auto}.vux-popup-dialog.vux-popup-top{width:100%;top:0;right:auto;bottom:auto;left:0}.vux-popup-mask{display:block;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);opacity:0;tap-highlight-color:transparent;z-index:-1;-webkit-transition:opacity .4s;transition:opacity .4s}.vux-popup-mask.vux-popup-show{opacity:1}.vux-popup-animate-bottom-enter,.vux-popup-animate-bottom-leave-active{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}.vux-popup-animate-left-enter,.vux-popup-animate-left-leave-active{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.vux-popup-animate-right-enter,.vux-popup-animate-right-leave-active{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.vux-popup-animate-top-enter,.vux-popup-animate-top-leave-active{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}.weui-search-bar{position:relative;padding:8px 10px;display:-webkit-box;display:-webkit-flex;display:flex;box-sizing:border-box;background-color:#efeff4}.weui-search-bar:before{top:0;border-top:1px solid #d7d6dc;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-search-bar:after,.weui-search-bar:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#d7d6dc}.weui-search-bar:after{bottom:0;border-bottom:1px solid #d7d6dc;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-search-bar.weui-search-bar_focusing .weui-search-bar__cancel-btn{display:block}.weui-search-bar.weui-search-bar_focusing .weui-search-bar__label{display:none}.weui-search-bar__form{position:relative;-webkit-box-flex:1;-webkit-flex:auto;flex:auto;background-color:#efeff4}.weui-search-bar__form:after{content:"";position:absolute;left:0;top:0;width:200%;height:200%;-webkit-transform:scale(.5);transform:scale(.5);-webkit-transform-origin:0 0;transform-origin:0 0;border-radius:10px;border:1px solid #e6e6ea;box-sizing:border-box;background:#fff}.weui-search-bar__box{position:relative;padding-left:30px;padding-right:30px;height:100%;width:100%;box-sizing:border-box;z-index:1}.weui-search-bar__box .weui-search-bar__input{padding:4px 0;width:100%;height:1.42857143em;border:0;font-size:14px;line-height:1.42857143em;box-sizing:content-box;background:transparent}.weui-search-bar__box .weui-search-bar__input:focus{outline:none}.weui-search-bar__box .weui-icon-search{position:absolute;left:10px;top:0;line-height:28px}.weui-search-bar__box .weui-icon-clear{position:absolute;top:0;right:0;padding:0 10px;line-height:28px}.weui-search-bar__label{position:absolute;top:1px;right:1px;bottom:1px;left:1px;z-index:2;border-radius:3px;text-align:center;color:#9b9b9b;background:#fff}.weui-search-bar__label span{display:inline-block;font-size:14px;vertical-align:middle}.weui-search-bar__label .weui-icon-search{margin-right:5px}.weui-search-bar__cancel-btn{display:none;margin-left:10px;line-height:28px;color:#09bb07;white-space:nowrap}.weui-search-bar__input:not(:valid)~.weui-icon-clear{display:none}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration,input[type=search]::-webkit-search-results-button,input[type=search]::-webkit-search-results-decoration{display:none}.vux-search-fixed{position:fixed;left:0;top:0;z-index:5;background:#fff;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}.vux-search-box{width:100%}.weui-cells.vux-search_show{margin-top:0!important;overflow-y:auto;position:fixed;width:100%;max-height:100%}.weui-cells.vux-search_show .weui-cell:last-child{margin-bottom:150px}.weui-cells.vux-search_show::-webkit-scrollbar{display:none}.weui-cells.vux-search_show:after{display:none}.vux-search-mask{position:absolute;left:0;top:0;width:90%;height:100%;z-index:5}.weui-cell_select{padding:0}.weui-cell_select .weui-select{padding-right:30px}.weui-cell_select .weui-cell__bd:after{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;right:15px;margin-top:-4px}.weui-select{-webkit-appearance:none;border:0;outline:0;background-color:transparent;width:100%;font-size:inherit;height:44px;line-height:44px;position:relative;z-index:1;padding-left:15px}.weui-cell_select-before{padding-right:15px}.weui-cell_select-before .weui-select{width:105px;box-sizing:border-box}.weui-cell_select-before .weui-cell__hd{position:relative}.weui-cell_select-before .weui-cell__hd:after{content:" ";position:absolute;right:0;top:0;width:1px;bottom:0;border-right:1px solid #d9d9d9;color:#d9d9d9;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-cell_select-before .weui-cell__hd:before{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;right:15px;margin-top:-4px}.weui-cell_select-before .weui-cell__bd{padding-left:15px}.weui-cell_select-before .weui-cell__bd:after{display:none}.weui-cell_select-after{padding-left:15px}.vux-selector-no-padding,.weui-cell_select-after .weui-select{padding-left:0}.vux-selector.weui-cell_select{padding:0}.vux-selector.weui-cell_select-after{padding-left:15px}.vux-selector-readonly{width:100%}.vux-popup-radio-popup{background-color:#fff}.vux-flexbox{width:100%;text-align:left;display:-webkit-box;display:flex;display:-webkit-flex;box-align:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.vux-flexbox .vux-flexbox-item{-webkit-box-flex:1;flex:1;-webkit-flex:1;min-width:20px;width:0%}.vux-flexbox .vux-flexbox-item:first-child{margin-left:0!important;margin-top:0!important}.vux-flex-row{box-direction:row;box-orient:horizontal;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row}.vux-flex-col,.vux-flex-row{-webkit-box-direction:normal}.vux-flex-col{box-orient:vertical;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}.vux-flex-col>.vux-flexbox-item{width:100%}.dp-container.vux-datetime-view{position:static;-webkit-transition:none;transition:none}.dp-container.vux-datetime-view .dp-header{display:none}.vux-datetime-clear{text-align:center}.scroller-component{display:block;position:relative;height:238px;overflow:hidden;width:100%}.scroller-content{z-index:-1}.scroller-content,.scroller-mask{position:absolute;left:0;top:0;width:100%}.scroller-mask{height:100%;margin:0 auto;z-index:3;background-image:-webkit-linear-gradient(top,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6)),-webkit-linear-gradient(bottom,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6));background-image:linear-gradient(180deg,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6)),linear-gradient(0deg,hsla(0,0%,100%,.95),hsla(0,0%,100%,.6));background-position:top,bottom;background-size:100% 102px;background-repeat:no-repeat}.scroller-item{text-align:center;font-size:16px;height:34px;line-height:34px;color:#000}.scroller-indicator{width:100%;height:34px;position:absolute;left:0;top:102px;z-index:3;background-image:-webkit-linear-gradient(top,#d0d0d0,#d0d0d0,transparent,transparent),-webkit-linear-gradient(bottom,#d0d0d0,#d0d0d0,transparent,transparent);background-image:linear-gradient(180deg,#d0d0d0,#d0d0d0,transparent,transparent),linear-gradient(0deg,#d0d0d0,#d0d0d0,transparent,transparent);background-position:top,bottom;background-size:100% 1px;background-repeat:no-repeat}.dp-container{bottom:0;z-index:10000;background-color:#fff;display:none;-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease;-webkit-transform:translateY(100%);transform:translateY(100%)}.dp-container,.dp-mask{position:fixed;width:100%;left:0}.dp-mask{z-index:998;height:100%;top:0;opacity:0;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in;background-color:#000;z-index:9999}.dp-header{display:-webkit-box;display:-webkit-flex;display:flex;width:100%;box-align:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;background-image:-webkit-linear-gradient(top,#e7e7e7,#e7e7e7,transparent,transparent);background-image:linear-gradient(180deg,#e7e7e7,#e7e7e7,transparent,transparent);background-position:bottom;background-size:100% 1px;background-repeat:no-repeat}.dp-header .dp-item{color:#04be02;font-size:16px;height:44px;line-height:44px;cursor:pointer}.dp-header .dp-item.dp-left{color:#828282}.dp-header .dp-item.dp-right{color:#04be02}.dp-content{display:-webkit-box;display:-webkit-flex;display:flex;width:100%;box-align:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;padding:10px 0}.dp-content .dp-item,.dp-header .dp-item{box-sizing:border-box;-webkit-box-flex:1;-webkit-flex:1;flex:1}.vux-datetime-cancel{text-align:left;padding-left:15px}.vux-datetime-confirm{text-align:right;padding-right:15px}.vux-datetime{color:#000;text-decoration:none}.vux-datetime .vux-input-icon{float:right}.vux-cell-primary{-webkit-box-flex:1;-webkit-flex:1;flex:1}.vux-number-input{float:left;height:20px;font-size:20px;color:#666;-webkit-appearance:none;appearance:none;border:1px solid #ececec;padding:3px 0;text-align:center;border-radius:1px}.vux-number-round .vux-number-input{border:none}.vux-number-selector{float:left;height:20px;font-size:25px;line-height:18px;color:#3cc51f;border:1px solid #ececec}.vux-number-round .vux-number-selector{width:20px;border-radius:13px}.vux-number-selector svg{fill:#3cc51f}.vux-number-selector.vux-number-disabled svg{fill:#ccc}.vux-number-round .vux-number-selector.vux-number-disabled{border-color:#ececec}.vux-number-round .vux-number-selector.vux-number-disabled svg{fill:#ccc}.vux-number-selector-sub{border-right:none;padding:4px 8px 2px;border-radius:2px 0 0 2px}.vux-number-selector-plus{border-left:none;margin-right:5px;padding:3px 8px;border-radius:0 2px 2px 0}.vux-number-round .vux-number-selector-sub svg{position:relative;top:1px}.vux-number-round .vux-number-selector-plus,.vux-number-round .vux-number-selector-sub{padding:2px;border:1px solid #3cc51f;text-align:center}.vux-x-textarea.weui-cell{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start}.weui-label{display:block;width:105px;word-wrap:break-word;word-break:break-all}.weui-input{width:100%;border:0;outline:0;-webkit-appearance:none;background-color:transparent;font-size:inherit;color:inherit;height:1.41176471em;line-height:1.41176471}.weui-input::-webkit-inner-spin-button,.weui-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.weui-textarea{display:block;border:0;resize:none;width:100%;color:inherit;font-size:1em;line-height:inherit;outline:0}.weui-textarea-counter{color:#b2b2b2;text-align:right}.weui-cell_warn .weui-textarea-counter{color:#e64340}.weui-toptips{display:none;position:fixed;-webkit-transform:translateZ(0);transform:translateZ(0);top:0;left:0;right:0;padding:5px;font-size:14px;text-align:center;color:#fff;z-index:5000;word-wrap:break-word;word-break:break-all}.weui-toptips_warn{background-color:#e64340}.weui-cells_form .weui-cell__ft{font-size:0}.weui-cells_form .weui-icon-warn{display:none}.weui-cells_form input,.weui-cells_form label[for],.weui-cells_form textarea{-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-cell_warn{color:#e64340}.weui-cell_warn .weui-icon-warn{display:inline-block}.weui-cell_switch{padding-top:6px;padding-bottom:6px}.weui-switch{-webkit-appearance:none;appearance:none}.weui-switch,.weui-switch-cp__box{position:relative;width:52px;height:32px;border:1px solid #dfdfdf;outline:0;border-radius:16px;box-sizing:border-box;background-color:#dfdfdf;-webkit-transition:background-color .1s,border .1s;transition:background-color .1s,border .1s}.weui-switch-cp__box:before,.weui-switch:before{content:" ";position:absolute;top:0;left:0;width:50px;height:30px;border-radius:15px;background-color:#fdfdfd;-webkit-transition:-webkit-transform .35s cubic-bezier(.45,1,.4,1);transition:-webkit-transform .35s cubic-bezier(.45,1,.4,1);transition:transform .35s cubic-bezier(.45,1,.4,1);transition:transform .35s cubic-bezier(.45,1,.4,1),-webkit-transform .35s cubic-bezier(.45,1,.4,1)}.weui-switch-cp__box:after,.weui-switch:after{content:" ";position:absolute;top:0;left:0;width:30px;height:30px;border-radius:15px;background-color:#fff;box-shadow:0 1px 3px rgba(0,0,0,.4);-webkit-transition:-webkit-transform .35s cubic-bezier(.4,.4,.25,1.35);transition:-webkit-transform .35s cubic-bezier(.4,.4,.25,1.35);transition:transform .35s cubic-bezier(.4,.4,.25,1.35);transition:transform .35s cubic-bezier(.4,.4,.25,1.35),-webkit-transform .35s cubic-bezier(.4,.4,.25,1.35)}.weui-switch-cp__input:checked~.weui-switch-cp__box,.weui-switch:checked{border-color:#04be02;background-color:#04be02}.weui-switch-cp__input:checked~.weui-switch-cp__box:before,.weui-switch:checked:before{-webkit-transform:scale(0);transform:scale(0)}.weui-switch-cp__input:checked~.weui-switch-cp__box:after,.weui-switch:checked:after{-webkit-transform:translateX(20px);transform:translateX(20px)}.weui-switch-cp__input{position:absolute;left:-9999px}.weui-switch-cp__box{display:block}.weui-cell_switch .weui-cell__ft{font-size:0;position:relative}input.weui-switch[disabled]{opacity:.6}.vux-x-switch.weui-cell_switch{padding-top:6px;padding-bottom:6px}.vux-x-switch-overlay{width:60px;height:50px;position:absolute;right:0;top:0;opacity:0}.weui-loading{width:20px;height:20px;display:inline-block;vertical-align:middle;-webkit-animation:weuiLoading 1s steps(12) infinite;animation:weuiLoading 1s steps(12) infinite;background:transparent url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=") no-repeat;background-size:100%}.weui-loading.weui-loading_transparent{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMjAnIGhlaWdodD0nMTIwJyB2aWV3Qm94PScwIDAgMTAwIDEwMCc+PHBhdGggZmlsbD0nbm9uZScgZD0nTTAgMGgxMDB2MTAwSDB6Jy8+PHJlY3QgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjU2KScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3RyYW5zbGF0ZSgwIC0zMCknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjUpJyByeD0nNScgcnk9JzUnIHRyYW5zZm9ybT0ncm90YXRlKDMwIDEwNS45OCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjQzKScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSg2MCA3NS45OCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjM4KScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSg5MCA2NSA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjMyKScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSgxMjAgNTguNjYgNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4yOCknIHJ4PSc1JyByeT0nNScgdHJhbnNmb3JtPSdyb3RhdGUoMTUwIDU0LjAyIDY1KScvPjxyZWN0IHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyB4PSc0Ni41JyB5PSc0MCcgZmlsbD0ncmdiYSgyNTUsMjU1LDI1NSwuMjUpJyByeD0nNScgcnk9JzUnIHRyYW5zZm9ybT0ncm90YXRlKDE4MCA1MCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjIpJyByeD0nNScgcnk9JzUnIHRyYW5zZm9ybT0ncm90YXRlKC0xNTAgNDUuOTggNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4xNyknIHJ4PSc1JyByeT0nNScgdHJhbnNmb3JtPSdyb3RhdGUoLTEyMCA0MS4zNCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjE0KScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSgtOTAgMzUgNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4xKScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSgtNjAgMjQuMDIgNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4wMyknIHJ4PSc1JyByeT0nNScgdHJhbnNmb3JtPSdyb3RhdGUoLTMwIC01Ljk4IDY1KScvPjwvc3ZnPgo=")}@-webkit-keyframes weuiLoading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes weuiLoading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.weui-btn.vux-x-button-no-border:after{display:none}.vux-swipeout{width:100%;overflow:hidden}.vux-swipeout-item{position:relative}.vux-swipeout-button-box{position:absolute;top:0;right:0;bottom:0;left:0;font-size:0;text-align:right}.vux-swipeout-button-box-left{text-align:left}.vux-swipeout-button-box>div{height:100%}.vux-swipeout-button{height:100%;text-align:center;font-size:14px;color:#fff;border:none}.vux-swipeout-content{position:relative;background:#fff}.vux-swipeout-content.vux-swipeout-content-animated{-webkit-transition:-webkit-transform .2s;transition:-webkit-transform .2s;transition:transform .2s;transition:transform .2s,-webkit-transform .2s}.vux-swipeout-button-primary{background-color:#1aad19}.vux-swipeout-button-warn{background-color:#e64340}.vux-swipeout-button-default{background-color:#c8c7cd}.weui-cell_access{-webkit-tap-highlight-color:rgba(0,0,0,0);color:inherit}.weui-cell_access:active{background-color:#ececec}.weui-cell_access .weui-cell__ft{padding-right:13px;position:relative}.weui-cell_access .weui-cell__ft:after{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;margin-top:-4px;right:2px}.weui-cell_link{color:#586c94;font-size:14px}.weui-cell_link.weui-cell:first-child:before{display:block}.weui-cell_access.vux-cell-box{padding-right:13px;position:relative}.weui-cell_access.vux-cell-box:after{content:" ";display:inline-block;height:6px;width:6px;border-width:2px 2px 0 0;border-color:#c8c8cd;border-style:solid;-webkit-transform:matrix(.71,.71,-.71,.71,0,0);transform:matrix(.71,.71,-.71,.71,0,0);position:relative;top:-2px;position:absolute;top:50%;margin-top:-4px;right:17px}.weui-panel{background-color:#fff;margin-top:10px;position:relative;overflow:hidden}.weui-panel:first-child{margin-top:0}.weui-panel:before{top:0;border-top:1px solid #e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-panel:after,.weui-panel:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#e5e5e5}.weui-panel:after{bottom:0;border-bottom:1px solid #e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-panel__hd{padding:14px 15px 10px;color:#999;font-size:13px;position:relative}.weui-panel__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-media-box{padding:15px;position:relative}.weui-media-box:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #e5e5e5;color:#e5e5e5;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-media-box:first-child:before{display:none}a.weui-media-box{color:#000;-webkit-tap-highlight-color:rgba(0,0,0,0)}a.weui-media-box:active{background-color:#ececec}.weui-media-box__title{font-weight:400;font-size:17px;width:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal;word-wrap:break-word;word-break:break-all}.weui-media-box__desc{color:#999;font-size:13px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.weui-media-box__info{margin-top:15px;padding-bottom:5px;font-size:13px;color:#cecece;line-height:1em;list-style:none;overflow:hidden}.weui-media-box__info__meta{float:left;padding-right:1em}.weui-media-box__info__meta_extra{padding-left:1em;border-left:1px solid #cecece}.weui-media-box_text .weui-media-box__title{margin-bottom:8px}.weui-media-box_appmsg{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-media-box_appmsg .weui-media-box__hd{margin-right:.8em;width:60px;height:60px;line-height:60px;text-align:center}.weui-media-box_appmsg .weui-media-box__thumb{width:100%;max-height:100%;vertical-align:top}.weui-media-box_appmsg .weui-media-box__bd{-webkit-box-flex:1;-webkit-flex:1;flex:1;min-width:0}.weui-media-box_small-appmsg{padding:0}.weui-media-box_small-appmsg .weui-cells{margin-top:0}.weui-media-box_small-appmsg .weui-cells:before{display:none}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{line-height:1.6;font-family:-apple-system-font,Helvetica Neue,sans-serif}*{margin:0;padding:0}a img{border:0}a{text-decoration:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}::-webkit-input-placeholder{font-family:-apple-system-font,Helvetica Neue,sans-serif}a{-webkit-touch-callout:none}.no-data-text{display:inline-block;vertical-align:middle;position:relative;top:-.9em;padding:0 .55em;color:#999;width:65%;margin:1.5em auto;line-height:1.6em;font-size:14px;text-align:center}.weui-form-preview{position:relative;background-color:#fff}.weui-form-preview:before{top:0;border-top:1px solid #d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-form-preview:after,.weui-form-preview:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#d9d9d9}.weui-form-preview:after{bottom:0;border-bottom:1px solid #d9d9d9;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-form-preview__hd{position:relative;padding:10px 15px;text-align:right;line-height:2.5em}.weui-form-preview__hd:after{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #d9d9d9;color:#d9d9d9;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-form-preview__hd .weui-form-preview__value{font-style:normal;font-size:1.6em}.weui-form-preview__bd{padding:10px 15px;font-size:.9em;text-align:right;color:#999;line-height:2}.weui-form-preview__ft{position:relative;line-height:50px;display:-webkit-box;display:-webkit-flex;display:flex}.weui-form-preview__ft:after{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-form-preview__item{overflow:hidden}.weui-form-preview__label{float:left;margin-right:1em;min-width:4em;color:#999;text-align:justify;text-align-last:justify}.weui-form-preview__value{display:block;overflow:hidden;word-break:normal;word-wrap:break-word}.weui-form-preview__btn{position:relative;display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;color:#3cc51f;text-align:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}button.weui-form-preview__btn{background-color:transparent;border:0;outline:0;line-height:inherit;font-size:inherit}.weui-form-preview__btn:active{background-color:#eee}.weui-form-preview__btn:after{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-form-preview__btn:first-child:after{display:none}.weui-form-preview__btn_default{color:#999}.weui-form-preview__btn_primary{color:#0bb20c}.vux-cell-form-preview .weui-form-preview__bd{width:100%;padding:0}.weui-form-preview-ft{display:-webkit-flex;display:-webkit-box;display:flex;line-height:50px;position:relative}button.weui-form-preview-btn{background-color:transparent;border:0 none;font-size:inherit;outline:0 none}.weui-form-preview-btn:active{background-color:#eee}.weui-form-preview-btn:after{border-left:1px solid #d5d5d6;bottom:0;color:#d5d5d6;content:" ";left:0;position:absolute;top:0;-webkit-transform:scaleX(.5);transform:scaleX(.5);-webkit-transform-origin:0 0 0;transform-origin:0 0 0;width:1px}.weui-form-preview-btn:first-child:after{display:none}.weui-form-preview-btn-default{color:#999}.weui-form-preview-btn-primary{color:#0bb20c}.vux-tab-ink-bar{position:absolute;height:2px;bottom:0;left:0;background-color:#04be02;text-align:center}.vux-tab-ink-bar-transition-forward{-webkit-transition:right .3s cubic-bezier(.35,0,.25,1),left .3s cubic-bezier(.35,0,.25,1) .09s;transition:right .3s cubic-bezier(.35,0,.25,1),left .3s cubic-bezier(.35,0,.25,1) .09s}.vux-tab-ink-bar-transition-backward{-webkit-transition:right .3s cubic-bezier(.35,0,.25,1) .09s,left .3s cubic-bezier(.35,0,.25,1);transition:right .3s cubic-bezier(.35,0,.25,1) .09s,left .3s cubic-bezier(.35,0,.25,1)}.vux-tab-bar-top .vux-tab-ink-bar{top:0}.vux-tab{display:-webkit-box;display:-webkit-flex;display:flex;background-color:#fff;height:44px;position:relative}.vux-tab button{padding:0;border:0;outline:0;background:0 0;-webkit-appearance:none;appearance:none}.vux-tab .vux-tab-item{display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;width:100%;height:100%;box-sizing:border-box;background:-webkit-linear-gradient(top,#e5e5e5,#e5e5e5,hsla(0,0%,90%,0)) 0 100% no-repeat;background:linear-gradient(180deg,#e5e5e5,#e5e5e5,hsla(0,0%,90%,0)) 0 100% no-repeat;background-size:100% 1px;font-size:14px;text-align:center;line-height:44px;color:#666}.vux-tab .vux-tab-item.vux-tab-selected{color:#04be02;border-bottom:3px solid #04be02}.vux-tab-bar-top .vux-tab .vux-tab-item{background:-webkit-linear-gradient(top,#e5e5e5,#e5e5e5,hsla(0,0%,90%,0)) 0 0 no-repeat;background:linear-gradient(180deg,#e5e5e5,#e5e5e5,hsla(0,0%,90%,0)) 0 0 no-repeat;background-size:100% 1px}.vux-tab-bar-top .vux-tab .vux-tab-item.vux-tab-selected{border-bottom:none;border-top:3px solid #04be02}.vux-tab .vux-tab-item.vux-tab-disabled{color:#ddd}.vux-tab.vux-tab-no-animate .vux-tab-item.vux-tab-selected{background:0 0}.vux-tab-bar-inner{display:block;background-color:#04be02;margin:auto;height:100%;-webkit-transition:width .3s cubic-bezier(.35,0,.25,1);transition:width .3s cubic-bezier(.35,0,.25,1)}.vux-tab-item-badge{position:absolute;top:0;bottom:0;box-sizing:border-box;display:inline-block;height:18px;min-width:18px;padding:0 4px;border-radius:30px;margin:auto 0 auto 4px;line-height:18px;font-size:11px;background-clip:padding-box;vertical-align:middle}.vux-tab-wrap{position:relative;padding-top:44px}.vux-tab-container{height:44px;top:0;left:0;right:0;overflow:hidden;position:absolute}.scrollable{overflow-y:hidden;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:17px;box-sizing:content-box}.scrollable::-webkit-scrollbar{display:none}.scrollable .vux-tab-ink-bar{bottom:17px;position:absolute}.scrollable .vux-tab-item{-webkit-box-flex:0;-webkit-flex:0 0 22%;flex:0 0 22%}.vux-sticky-box{z-index:500}.vux-sticky{width:100%;position:-webkit-sticky;position:sticky;top:0}.vux-fixed{width:100%;position:fixed;top:0;-webkit-transform:translateZ(0);transform:translateZ(0)}.vux-sticky-fill{display:none}.vux-fixed+.vux-sticky-fill{display:block}.vux-1px,.vux-1px-b,.vux-1px-l,.vux-1px-r,.vux-1px-t,.vux-1px-tb{position:relative}.vux-1px:before{content:" ";position:absolute;left:0;top:0;width:200%;border:1px solid #c7c7c7;color:#c7c7c7;height:200%;-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:scale(.5);transform:scale(.5)}.vux-1px-t:before{top:0;border-top:1px solid #c7c7c7;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.vux-1px-b:after,.vux-1px-t:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#c7c7c7}.vux-1px-b:after{bottom:0;border-bottom:1px solid #c7c7c7;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.vux-1px-tb:before{top:0;border-top:1px solid #c7c7c7;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.vux-1px-tb:after,.vux-1px-tb:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#c7c7c7}.vux-1px-tb:after{bottom:0;border-bottom:1px solid #c7c7c7;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.vux-1px-l:before{left:0;border-left:1px solid #c7c7c7;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.vux-1px-l:before,.vux-1px-r:after{content:" ";position:absolute;top:0;width:1px;bottom:0;color:#c7c7c7}.vux-1px-r:after{right:0;border-right:1px solid #c7c7c7;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.vux-table{line-height:40px;position:relative;width:100%;border-collapse:collapse}.vux-table:after{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #c7c7c7;color:#c7c7c7;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.vux-table th{font-weight:500}.vux-table.vux-table-bordered:before{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1px solid #c7c7c7;color:#c7c7c7;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.vux-table td,.vux-table th{border-bottom:1px solid #e0e0e0;border-right:1px solid #e0e0e0;text-align:center;position:relative;border-right:0;border-bottom:0}.vux-table td:before,.vux-table th:before{content:" ";position:absolute;left:0;bottom:0;right:0;height:1px;border-bottom:1px solid #c7c7c7;color:#c7c7c7;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.vux-table.vux-table-no-content-bordered td:before{border-bottom-width:0}.vux-table.vux-table-no-content-bordered tr:last-child td:before{border-bottom-width:1px}.vux-table td:after,.vux-table th:after{content:" ";position:absolute;right:0;top:0;width:1px;bottom:0;border-right:1px solid #c7c7c7;color:#c7c7c7;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.vux-table.vux-table-no-cell-bordered td:after,.vux-table.vux-table-no-cell-bordered th:after,.vux-table tr td:last-child:after,.vux-table tr th:last-child:after{border-right-width:0}.vux-table.vux-table-bordered tr td:last-child:after,.vux-table.vux-table-bordered tr th:last-child:after{border-right-width:1px}.vux-check-icon{display:inline-block}.vux-check-icon>span{line-height:23px;color:#222;vertical-align:middle}.vux-check-icon>.weui-icon-success-circle:before,.vux-check-icon>.weui-icon-success:before{color:#09bb07}.weui-cells{margin-top:1.17647059em;background-color:#fff;line-height:1.41176471;font-size:17px;overflow:hidden;position:relative}.weui-cells:before{top:0;border-top:1px solid #d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-cells:after,.weui-cells:before{content:" ";position:absolute;left:0;right:0;height:1px;color:#d9d9d9}.weui-cells:after{bottom:0;border-bottom:1px solid #d9d9d9;-webkit-transform-origin:0 100%;transform-origin:0 100%;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-cells__title{margin-top:.77em;margin-bottom:.3em;padding-left:15px;padding-right:15px;color:#999;font-size:14px}.weui-cells__title+.weui-cells{margin-top:0}.weui-cells__tips{margin-top:.3em;color:#999;padding-left:15px;padding-right:15px;font-size:14px}.weui-cell{padding:10px 15px;position:relative;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.weui-cell:before{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #d9d9d9;color:#d9d9d9;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5);left:15px}.weui-cell:first-child:before{display:none}.weui-cell_primary{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start}.weui-cell__bd{-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-cell__ft{text-align:right;color:#999}.vux-cell-justify{height:1.41176471em}.vux-cell-justify.vux-cell-justify:after{content:".";display:inline-block;width:100%;overflow:hidden;height:0}.weui-check__label{-webkit-tap-highlight-color:rgba(0,0,0,0)}.weui-check__label:active{background-color:#ececec}.weui-check{position:absolute;left:-9999em}.weui-cells_radio .weui-cell__ft{padding-left:.35em}.weui-cells_radio .weui-check:checked+.weui-icon-checked:before{display:block;content:"\EA08";color:#09bb07;font-size:16px}.weui-cells_checkbox .weui-cell__hd{padding-right:.35em}.weui-cells_checkbox .weui-icon-checked:before{content:"\EA01";color:#c9c9c9;font-size:23px;display:block}.weui-cells_checkbox .weui-check:checked+.weui-icon-checked:before{content:"\EA06";color:#09bb07}.weui-cells_checkbox .weui-check:checked+.vux-checklist-icon-checked:before{color:#09bb07}.weui-cells_checkbox>label>*{pointer-events:none}.vux-checklist-disabled .vux-checklist-icon-checked:before{opacity:.5}.vux-checklist-label-left{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;flex-direction:row-reverse}.vux-group-tip,.vux-group-tip p{font-size:14px;color:#888;text-align:center;padding-top:.3em;padding-left:10px;padding-right:5px}.vux-group-tip .weui-icon{padding-right:3px}@font-face{font-weight:400;font-style:normal;font-family:weui;src:url("data:application/octet-stream;base64,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") format("truetype")}[class*=" weui-icon-"],[class^=weui-icon-]{display:inline-block;vertical-align:middle;font:normal normal normal 14px/1 weui;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased}[class*=" weui-icon-"]:before,[class^=weui-icon-]:before{display:inline-block;margin-left:.2em;margin-right:.2em}.weui-icon-circle:before{content:"\EA01"}.weui-icon-download:before{content:"\EA02"}.weui-icon-info:before{content:"\EA03"}.weui-icon-safe-success:before{content:"\EA04"}.weui-icon-safe-warn:before{content:"\EA05"}.weui-icon-success:before{content:"\EA06"}.weui-icon-success-circle:before{content:"\EA07"}.weui-icon-success-no-circle:before{content:"\EA08"}.weui-icon-waiting:before{content:"\EA09"}.weui-icon-waiting-circle:before{content:"\EA0A"}.weui-icon-warn:before{content:"\EA0B"}.weui-icon-info-circle:before{content:"\EA0C"}.weui-icon-cancel:before{content:"\EA0D"}.weui-icon-search:before{content:"\EA0E"}.weui-icon-clear:before{content:"\EA0F"}.weui-icon-back:before{content:"\EA10"}.weui-icon-delete:before{content:"\EA11"}[class*=" weui-icon_"]:before,[class^=weui-icon_]:before{margin:0}.weui-icon-success{font-size:23px;color:#09bb07}.weui-icon-waiting{font-size:23px;color:#10aeff}.weui-icon-warn{font-size:23px;color:#f43530}.weui-icon-info{font-size:23px;color:#10aeff}.weui-icon-success-circle,.weui-icon-success-no-circle{font-size:23px;color:#09bb07}.weui-icon-waiting-circle{font-size:23px;color:#10aeff}.weui-icon-circle{font-size:23px;color:#c9c9c9}.weui-icon-download,.weui-icon-info-circle{font-size:23px;color:#09bb07}.weui-icon-safe-success{color:#09bb07}.weui-icon-safe-warn{color:#ffbe00}.weui-icon-cancel{color:#f43530;font-size:22px}.weui-icon-clear,.weui-icon-search{color:#b2b2b2;font-size:14px}.weui-icon-delete.weui-icon_gallery-delete{color:#fff;font-size:22px}.weui-icon_msg{font-size:93px}.weui-icon_msg.weui-icon-warn{color:#f76260}.weui-icon_msg-primary{font-size:93px}.weui-icon_msg-primary.weui-icon-warn{color:#ffbe00}.weui-msg{padding-top:36px;text-align:center}.weui-msg__icon-area{margin-bottom:30px}.weui-msg__text-area{margin-bottom:25px;padding:0 20px}.weui-msg__text-area a{color:#586c94}.weui-msg__title{margin-bottom:5px;font-weight:400;font-size:20px}.weui-msg__desc{font-size:14px;color:#999}.weui-msg__opr-area{margin-bottom:25px}.weui-msg__extra-area{margin-bottom:15px;font-size:14px;color:#999}.weui-msg__extra-area a{color:#586c94}@media screen and (min-height:438px){.weui-msg__extra-area{position:fixed;left:0;bottom:0;width:100%;text-align:center}}.weui-btn{position:relative;display:block;margin-left:auto;margin-right:auto;padding-left:14px;padding-right:14px;box-sizing:border-box;font-size:18px;text-align:center;text-decoration:none;color:#fff;line-height:2.33333333;border-radius:5px;-webkit-tap-highlight-color:rgba(0,0,0,0);overflow:hidden}.weui-btn:after{content:" ";width:200%;height:200%;position:absolute;top:0;left:0;border:1px solid rgba(0,0,0,.2);-webkit-transform:scale(.5);transform:scale(.5);-webkit-transform-origin:0 0;transform-origin:0 0;box-sizing:border-box;border-radius:10px}.weui-btn_inline{display:inline-block}.weui-btn_default{color:#000;background-color:#f8f8f8}.weui-btn_default:not(.weui-btn_disabled):visited{color:#000}.weui-btn_default:not(.weui-btn_disabled):active{color:rgba(0,0,0,.6);background-color:#dedede}.weui-btn_primary{background-color:#1aad19}.weui-btn_primary:not(.weui-btn_disabled):visited{color:#fff}.weui-btn_primary:not(.weui-btn_disabled):active{color:hsla(0,0%,100%,.6);background-color:#179b16}.weui-btn_warn{background-color:#e64340}.weui-btn_warn:not(.weui-btn_disabled):visited{color:#fff}.weui-btn_warn:not(.weui-btn_disabled):active{color:hsla(0,0%,100%,.6);background-color:#ce3c39}.weui-btn_disabled{color:hsla(0,0%,100%,.6)}.weui-btn_disabled.weui-btn_default{color:rgba(0,0,0,.3);background-color:#f7f7f7}.weui-btn_disabled.weui-btn_primary{background-color:#9ed99d}.weui-btn_disabled.weui-btn_warn{background-color:#ec8b89}.weui-btn_loading .weui-loading{margin:-.2em .34em 0 0}.weui-btn_loading.weui-btn_primary,.weui-btn_loading.weui-btn_warn{color:hsla(0,0%,100%,.6)}.weui-btn_loading.weui-btn_primary .weui-loading,.weui-btn_loading.weui-btn_warn .weui-loading{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMjAnIGhlaWdodD0nMTIwJyB2aWV3Qm94PScwIDAgMTAwIDEwMCc+PHBhdGggZmlsbD0nbm9uZScgZD0nTTAgMGgxMDB2MTAwSDB6Jy8+PHJlY3QgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjU2KScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3RyYW5zbGF0ZSgwIC0zMCknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjUpJyByeD0nNScgcnk9JzUnIHRyYW5zZm9ybT0ncm90YXRlKDMwIDEwNS45OCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjQzKScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSg2MCA3NS45OCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjM4KScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSg5MCA2NSA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjMyKScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSgxMjAgNTguNjYgNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4yOCknIHJ4PSc1JyByeT0nNScgdHJhbnNmb3JtPSdyb3RhdGUoMTUwIDU0LjAyIDY1KScvPjxyZWN0IHdpZHRoPSc3JyBoZWlnaHQ9JzIwJyB4PSc0Ni41JyB5PSc0MCcgZmlsbD0ncmdiYSgyNTUsMjU1LDI1NSwuMjUpJyByeD0nNScgcnk9JzUnIHRyYW5zZm9ybT0ncm90YXRlKDE4MCA1MCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjIpJyByeD0nNScgcnk9JzUnIHRyYW5zZm9ybT0ncm90YXRlKC0xNTAgNDUuOTggNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4xNyknIHJ4PSc1JyByeT0nNScgdHJhbnNmb3JtPSdyb3RhdGUoLTEyMCA0MS4zNCA2NSknLz48cmVjdCB3aWR0aD0nNycgaGVpZ2h0PScyMCcgeD0nNDYuNScgeT0nNDAnIGZpbGw9J3JnYmEoMjU1LDI1NSwyNTUsLjE0KScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSgtOTAgMzUgNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4xKScgcng9JzUnIHJ5PSc1JyB0cmFuc2Zvcm09J3JvdGF0ZSgtNjAgMjQuMDIgNjUpJy8+PHJlY3Qgd2lkdGg9JzcnIGhlaWdodD0nMjAnIHg9JzQ2LjUnIHk9JzQwJyBmaWxsPSdyZ2JhKDI1NSwyNTUsMjU1LC4wMyknIHJ4PSc1JyByeT0nNScgdHJhbnNmb3JtPSdyb3RhdGUoLTMwIC01Ljk4IDY1KScvPjwvc3ZnPg==")}.weui-btn_loading.weui-btn_primary{background-color:#179b16}.weui-btn_loading.weui-btn_warn{background-color:#ce3c39}.weui-btn_plain-primary{color:#1aad19;border:1px solid #1aad19}.weui-btn_plain-primary:not(.weui-btn_plain-disabled):active{color:rgba(26,173,25,.6);border-color:rgba(26,173,25,.6);background-color:transparent}.weui-btn_plain-primary:after{border-width:0}.weui-btn_plain-default{color:#353535;border:1px solid #353535}.weui-btn_plain-default:not(.weui-btn_plain-disabled):active{color:rgba(53,53,53,.6);border-color:rgba(53,53,53,.6)}.weui-btn_plain-default:after{border-width:0}button.weui-btn.weui-btn_plain-warn,input.weui-btn.weui-btn_plain-warn{border-width:1px;background-color:transparent}.weui-btn_plain-warn{color:#ce3c39;border:1px solid #ce3c39;background:transparent}.weui-btn_plain-warn:not(.weui-btn_plain-disabled):active{color:rgba(206,60,57,.6);border-color:rgba(206,60,57,.6)}.weui-btn_plain-warn:after{border-width:0}.weui-btn_plain-disabled{color:rgba(0,0,0,.2);border-color:rgba(0,0,0,.2)}button.weui-btn,input.weui-btn{width:100%;border-width:0;outline:0;-webkit-appearance:none}button.weui-btn:focus,input.weui-btn:focus{outline:0}button.weui-btn_inline,button.weui-btn_mini,input.weui-btn_inline,input.weui-btn_mini{width:auto}button.weui-btn_plain-default,button.weui-btn_plain-primary,input.weui-btn_plain-default,input.weui-btn_plain-primary{border-width:1px;background-color:transparent}.weui-btn_mini{display:inline-block;padding:0 1.32em;line-height:2.3;font-size:13px}.weui-btn+.weui-btn{margin-top:15px}.weui-btn.weui-btn_inline+.weui-btn.weui-btn_inline{margin-top:auto;margin-left:15px}.weui-btn-area{margin:1.17647059em 15px .3em}.weui-btn-area_inline{display:-webkit-box;display:-webkit-flex;display:flex}.weui-btn-area_inline .weui-btn{margin-top:auto;margin-right:15px;width:100%;-webkit-box-flex:1;-webkit-flex:1;flex:1}.weui-btn-area_inline .weui-btn:last-child{margin-right:0}.vux-modal-open{overflow:hidden;position:fixed;width:100%}.vux-modal-open-for-container{overflow:hidden!important}.vux-fade-enter-active,.vux-fade-leave-active{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.vux-fade-enter,.vux-fade-leave-to{opacity:0}.vux-dialog-enter-active{-webkit-animation:vux-dialog-in .5s;animation:vux-dialog-in .5s}.vux-dialog-leave-active{-webkit-animation:vux-dialog-out .3s;animation:vux-dialog-out .3s}@-webkit-keyframes vux-dialog-in{0%{-webkit-transform:scale(1.185);transform:scale(1.185);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes vux-dialog-in{0%{-webkit-transform:scale(1.185);transform:scale(1.185);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@-webkit-keyframes vux-dialog-out{0%{-webkit-transform:scale(1);transform:scale(1);opacity:1}to{-webkit-transform:scale(.85);transform:scale(.85);opacity:0}}@keyframes vux-dialog-out{0%{-webkit-transform:scale(1);transform:scale(1);opacity:1}to{-webkit-transform:scale(.85);transform:scale(.85);opacity:0}}.vux-mask-enter,.vux-mask-leave-active{opacity:0}.vux-mask-enter-active,.vux-mask-leave-active{-webkit-transition:opacity .3s;transition:opacity .3s}.weui-mask{background:rgba(0,0,0,.6)}.weui-mask,.weui-mask_transparent{position:fixed;z-index:1000;top:0;right:0;left:0;bottom:0}.weui-dialog{position:fixed;display:table;z-index:5000;width:80%;max-width:300px;top:0;right:0;bottom:0;left:0;margin:auto;background-color:#fff;text-align:center;border-radius:3px;overflow:hidden}.weui-dialog__hd{padding:1.3em 1.6em .5em}.weui-dialog__hd.with-no-content{padding:1.7em 1.6em}.weui-dialog__title{font-weight:400;font-size:18px}.weui-dialog__bd{padding:0 1.6em .8em;min-height:40px;font-size:15px;line-height:1.3;word-wrap:break-word;word-break:break-all;color:#999}.weui-dialog__bd:first-child{padding:2.7em 20px 1.7em;color:#353535}.weui-dialog__ft{position:relative;line-height:48px;font-size:18px;display:-webkit-box;display:-webkit-flex;display:flex}.weui-dialog__ft:after{content:" ";position:absolute;left:0;top:0;right:0;height:1px;border-top:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.weui-dialog__btn{display:block;-webkit-box-flex:1;-webkit-flex:1;flex:1;color:#3cc51f;text-decoration:none;-webkit-tap-highlight-color:rgba(0,0,0,0);position:relative}.weui-dialog__btn:active{background-color:#eee}.weui-dialog__btn:after{content:" ";position:absolute;left:0;top:0;width:1px;bottom:0;border-left:1px solid #d5d5d6;color:#d5d5d6;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.5);transform:scaleX(.5)}.weui-dialog__btn:first-child:after{display:none}.weui-dialog__btn_default{color:#353535}.weui-dialog__btn_primary{color:#0bb20c}.weui-dialog__btn_warn{color:#e64340}.weui-skin_android .weui-dialog{text-align:left;box-shadow:0 6px 30px 0 rgba(0,0,0,.1)}.weui-skin_android .weui-dialog__title{font-size:21px}.weui-skin_android .weui-dialog__hd{text-align:left}.weui-skin_android .weui-dialog__bd{color:#999;padding:.25em 1.6em 2em;font-size:17px;text-align:left}.weui-skin_android .weui-dialog__bd:first-child{padding:1.6em 1.6em 2em;color:#353535}.weui-skin_android .weui-dialog__ft{display:block;text-align:right;line-height:42px;font-size:16px;padding:0 1.6em .7em}.weui-skin_android .weui-dialog__ft:after{display:none}.weui-skin_android .weui-dialog__btn{display:inline-block;vertical-align:top;padding:0 .8em}.weui-skin_android .weui-dialog__btn:after{display:none}.weui-skin_android .weui-dialog__btn:active,.weui-skin_android .weui-dialog__btn:visited{background-color:rgba(0,0,0,.06)}.weui-skin_android .weui-dialog__btn:last-child{margin-right:-.8em}.weui-skin_android .weui-dialog__btn_default{color:gray}@media screen and (min-width:1024px){.weui-dialog{width:35%}}.vux-x-dialog-absolute .weui-dialog{position:absolute}.container[data-v-5dd443d4]{-webkit-box-align:center;-webkit-align-items:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;height:100%;width:100%}.center[data-v-5dd443d4]{text-align:center;padding-top:20px;color:#fff;font-size:18px}.center img[data-v-5dd443d4]{width:150px;height:150px;border-radius:50%;border:4px solid #ececec}.box[data-v-5dd443d4]{//:url(https://odoo.net.cn/uploads/profile/6861-profileimg.jpg);border-radius:5px;font-family:sans-serif;text-align:center;line-height:1;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);max-width:100%;max-height:100%;padding:20px 40px}.b-lazy,.vux-x-img{-webkit-transition:opacity .5s ease-in-out;transition:opacity .5s ease-in-out;max-width:100%}.b-lazy{opacity:0}.b-lazy.b-loaded{opacity:1}.vux-bg-blur{z-index:-2;opacity:0;position:absolute;min-height:100%;display:block;top:0;max-height:none;left:-20%;top:-20%;width:140%;height:140%;-webkit-transition:opacity .8s linear;transition:opacity .8s linear}.vux-bg-blur-overlay{z-index:-1;position:absolute;width:100%;height:100%;background:-webkit-linear-gradient(top,rgba(0,0,0,.15),#000);background:-webkit-linear-gradient(top,rgba(0,0,0,.15) 0,#000);background:linear-gradient(180deg,rgba(0,0,0,.15) 0,#000)}.container[data-v-e84b15da]{-webkit-box-align:center;-webkit-align-items:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;height:100%;width:100%}.center[data-v-e84b15da]{text-align:center;padding-top:20px;color:#fff;font-size:18px}.center img[data-v-e84b15da]{width:150px;height:150px;border-radius:50%;border:4px solid #ececec}.box[data-v-e84b15da]{background-image:url(https://odoo.net.cn/uploads/profile/6861-profileimg.jpg);border-radius:5px;font-family:sans-serif;text-align:center;line-height:1;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);max-width:100%;max-height:100%;padding:20px 40px} -------------------------------------------------------------------------------- /mobile/static/html/images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbert-yuan/odoo_mobile/a2ed286a9b3000832ca363f273dac59515eae2de/mobile/static/html/images/default.png -------------------------------------------------------------------------------- /mobile/static/html/js/registerSw.8b75daa54b1bf5dbf84b.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(t){if(n[t])return n[t].exports;var o=n[t]={i:t,l:!1,exports:{}};return e[t].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var n={};r.m=e,r.c=n,r.d=function(e,n,t){r.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:t})},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},r.p="/",r(r.s="c5VX")}({c5VX:function(e,r){!function(){"serviceWorker"in navigator&&navigator.serviceWorker.register("sw.js",{scope:"/"}).then(function(){console.log("Service Worker Registered")})}()}}); -------------------------------------------------------------------------------- /mobile/static/html/json/offline.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbert-yuan/odoo_mobile/a2ed286a9b3000832ca363f273dac59515eae2de/mobile/static/html/json/offline.json -------------------------------------------------------------------------------- /mobile/static/html/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbert-yuan/odoo_mobile/a2ed286a9b3000832ca363f273dac59515eae2de/mobile/static/html/logo.png -------------------------------------------------------------------------------- /mobile/static/html/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "scope": "/", 3 | "name": "运维平台", 4 | "short_name": "运维平台", 5 | "start_url": "/", 6 | "display": "standalone", 7 | "description": "Gomo运维平台", 8 | "orientation": "portrait", 9 | "theme_color": "#3f51b5", 10 | "background_color": "#fff", 11 | "icons": [{ 12 | "src": "./vue_logo.png", 13 | "sizes": "32x32", 14 | "type": "image/png" 15 | }, 16 | { 17 | "src": "./logo.png", 18 | "sizes": "144x144", 19 | "type": "image/png" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /mobile/static/html/vux_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbert-yuan/odoo_mobile/a2ed286a9b3000832ca363f273dac59515eae2de/mobile/static/html/vux_logo.png -------------------------------------------------------------------------------- /mobile/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | odoo_vue 5 | 6 |
7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /mobile/static/service-worker.js: -------------------------------------------------------------------------------- 1 | "use strict";var precacheConfig=[["index.html","4e0f7deaa524b8aeab37f4db7d7ed9e6"],["static/css/app.5914b78bd7790e9371ccc0f4cfc5093c.css","2fda86ffa6c5682d44f632bf7f741b10"],["static/js/app.45632234eddc404cf63d.js","fbc1df12b941c8acdd0aeaeaa08d98ef"],["static/js/registerSw.8b75daa54b1bf5dbf84b.js","a91d32fd92edb9ea0474cc2a767821c7"],["sw.js","cd7fbdeef2b780dc15415b19cf031f2c"]],cacheName="sw-precache-v3-odoo-app-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(e){return e.redirected?("body"in e?Promise.resolve(e.body):e.blob()).then(function(t){return new Response(t,{headers:e.headers,status:e.status,statusText:e.statusText})}):Promise.resolve(e)},createCacheKey=function(e,t,n,r){var a=new URL(e);return r&&a.pathname.match(r)||(a.search+=(a.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),a.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,t){var n=new URL(e);return n.hash="",n.search=n.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),n.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],r=new URL(t,self.location),a=createCacheKey(r,hashParamName,n,!1);return[r.toString(),a]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(n){if(!t.has(n)){var r=new Request(n,{credentials:"same-origin"});return fetch(r).then(function(t){if(!t.ok)throw new Error("Request for "+n+" returned a response with status "+t.status);return cleanResponse(t).then(function(t){return e.put(n,t)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(n){return Promise.all(n.map(function(n){if(!t.has(n.url))return e.delete(n)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,n=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);(t=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,"index.html"),t=urlsToCacheKeys.has(n));0,t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}); -------------------------------------------------------------------------------- /mobile/static/sw.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const version = 'xinwen_v1.4' 3 | const offlineResources = [ 4 | '/', 5 | './static/images/default.png', 6 | './static/json/offline.json' 7 | ] 8 | // 过滤需要加入缓存的api 9 | const addApiCache = [ 10 | /https?:\/\/www.easy-mock.com\// 11 | ] 12 | // 需要缓存的请求 13 | const shouldAlwaysFetch = (request) => { 14 | return true //addApiCache.some(regex => request.url.match(regex)) 15 | } 16 | 17 | /** 18 | * common function 19 | */ 20 | function cacheKey () { 21 | return [version, ...arguments].join(':') 22 | } 23 | 24 | function log () { 25 | console.log('SW:', ...arguments) 26 | } 27 | 28 | // 缓存 html 页面 29 | function shouldFetchAndCache (request) { 30 | return (/text\/html/i).test(request.headers.get('Accept')) 31 | } 32 | /** 33 | * onClickNotify 34 | */ 35 | 36 | function onClickNotify (event) { 37 | var action = event.action 38 | console.log(`action tag: ${event.notification.tag}`, `action: ${action}`) 39 | 40 | switch (action) { 41 | case 'show-book': 42 | console.log('show-book') 43 | break 44 | case 'contact-me': 45 | console.log('contact-me') 46 | break 47 | default: 48 | console.log(`未处理的action: ${event.action}`) 49 | action = 'default' 50 | break 51 | } 52 | event.notification.close() 53 | 54 | event.waitUntil( 55 | // event.waitUntil(async function() { 56 | // 获取所有clients 57 | self.clients.matchAll().then(function (clients) { 58 | // debugger 59 | if (!clients || clients.length === 0) { 60 | return 61 | } 62 | clients.forEach(function (client) { 63 | // 使用postMessage进行通信 64 | client.postMessage(action) 65 | }) 66 | }) 67 | ) 68 | 69 | } 70 | 71 | /** 72 | * Install 安装 73 | */ 74 | 75 | function onInstall (event) { 76 | log('install event in progress.') 77 | event.waitUntil( 78 | caches.open(cacheKey('offline')) 79 | .then(cache => cache.addAll(offlineResources)) 80 | .then(() => log('installation complete! version: ' + version)) 81 | .then(() => self.skipWaiting()) 82 | ) 83 | } 84 | 85 | /** 86 | * Fetch 87 | */ 88 | 89 | // 当网络离线或请求发生了错误,使用离线资源替代 request 请求 90 | function offlineResponse (request) { 91 | // debugger 92 | log('(offline)', request.method, request.url) 93 | if (request.url.match(/\.(jpg|png|gif|svg|jpeg)(\?.*)?$/)) { 94 | return caches.match('/static/images/default.png') 95 | } else { 96 | // return caches.match('/offline.html') 97 | return caches.match('./static/json/offline.json') 98 | } 99 | } 100 | 101 | // 从网络请求,并将请求成功的资源缓存 102 | function networkedAndCache (request) { 103 | return fetch(request) 104 | .then(response => { 105 | const copy = response.clone() 106 | 107 | caches.open(cacheKey('resources')) 108 | .then(cache => { 109 | cache.put(request, copy) 110 | }) 111 | log('(network: cache write)', request.method, request.url) 112 | return response 113 | }) 114 | } 115 | 116 | // 优先从 cache 读取,读取失败则从网络请求并缓存。网络请求也失败,则使用离线资源替代 117 | function cachedOrNetworked (request) { 118 | return caches.match(request) 119 | .then((response) => { 120 | log(response ? '(cached)' : '(network: cache miss)', request.method, request.url) 121 | return response || 122 | networkedAndCache(request) 123 | .catch(() => offlineResponse(request)) 124 | }) 125 | } 126 | // 离线断网读取缓存:优先从 cache 读取,读取失败则使用离线资源替代 127 | function cachedOroffline (request) { 128 | return caches.match(request) 129 | .then((response) => { 130 | // debugger 131 | log(response ? '(cached)' : '(network: cache miss)', request.method, request.url) 132 | return response || offlineResponse(request) 133 | }) 134 | // .catch(() => offlineResponse(request)) 135 | } 136 | // 优先从网络请求,请求成功则加入缓存,请求失败则用缓存,再失败则使用离线资源替代 137 | function networkedOrcachedOrOffline (request) { 138 | return fetch(request) 139 | .then(response => { 140 | const copy = response.clone() 141 | caches.open(cacheKey('resources')) 142 | .then(cache => { 143 | cache.put(request, copy) 144 | }) 145 | log('(network)', request.method, request.url) 146 | return response 147 | }) 148 | .catch(() => cachedOroffline(request)) 149 | } 150 | 151 | function onFetch (event) { 152 | const request = event.request 153 | // 优先从网络请求,请求失败则用缓存,再失败则使用离线资源替代 154 | log(shouldAlwaysFetch(request)) 155 | if (shouldAlwaysFetch(request)) { 156 | log('AlwaysFetch request: ', event.request.url) 157 | event.respondWith(networkedOrcachedOrOffline(request)) 158 | return 159 | } 160 | // 应当从网络请求并缓存的资源 161 | // 如果请求失败,则尝试从缓存读取,读取失败则使用离线资源替代 162 | // // debugger 163 | log(shouldFetchAndCache(request)) 164 | if (shouldFetchAndCache(request)) { 165 | event.respondWith( 166 | networkedAndCache(request).catch(() => cachedOrOffline(request)) 167 | ) 168 | return 169 | } 170 | // 优先从 cache 读取,读取失败则从网络请求并缓存。网络请求也失败,则使用离线资源替代 171 | event.respondWith(cachedOrNetworked(request)) 172 | } 173 | 174 | /** 175 | * Activate 176 | */ 177 | function removeOldCache () { 178 | return caches 179 | .keys() 180 | .then(keys => 181 | Promise.all( // 等待所有旧的资源都清理完成 182 | keys 183 | .filter(key => !key.startsWith(version)) // 过滤不需要删除的资源 184 | .map(key => caches.delete(key)) // 删除旧版本资源,返回为 Promise 对象 185 | ) 186 | ) 187 | .then(() => { 188 | log('removeOldCache completed.') 189 | }) 190 | } 191 | 192 | function onActivate (event) { 193 | log('activate event in progress.') 194 | event.waitUntil(Promise.all([ 195 | // 更新客户端 196 | self.clients.claim(), 197 | removeOldCache() 198 | ])) 199 | } 200 | 201 | log('Hello from ServiceWorker land!', version) 202 | self.addEventListener('install', onInstall) 203 | self.addEventListener('fetch', onFetch) 204 | self.addEventListener('activate', onActivate) 205 | // self.addEventListener('push', onPush) 206 | // self.addEventListener('sync', onSync) 207 | // self.addEventListener('message', onMessage) 208 | // self.addEventListener('offline', offline) 209 | self.addEventListener('notificationclick', onClickNotify) --------------------------------------------------------------------------------