全端设置pages.json里pages页面的背景色

第一时间想到的肯定是全局设置:

但是遗憾的是,全局背景色只有在小程序中才生效。接下来,看看能不能在页面中单独配置:

果然找到了以上配置,但是通过真机调试发现,这个配置只有在苹果手机上才能生效,安卓手机不生效,并且需要在APP.vue中将page的背景色设为透明。看来,通过配置文件实现这条路已经走不通了,那就只能通过代码实现了。以下是两种实现方式:

1.全局样式

// APP.vue
page {
  background: #fff; // 窗体自定义背景色
}

2.页面窗体

// my-page.vue
<template>
  <view class="my-page"></view>
</template>

<style lang="scss">
  page {
    background-color: #eff3f7; // 窗体自定义背景色
  }
  .my-page {}
</style>

内置表单组件picker

1.使用picker实现省市区级联选择

<view class="vertical-center info-item">
  <text class="info-label">所在地</text>
  <picker
    class="flex-auto"
    mode="multiSelector"
    :range="regionList"
    :value="regionIndexs"
    range-key="name"
    @change="regionChange"
    @columnchange="regionColumnchange"
  >
    <view class="uni-flex">
      <view class="flex-auto" :class="{'holder-text': !userInfo.region}">
        {{ userInfo.region || '请选择' }}
      </view>
      <uni-icons type="forward" size="18" color="#506f8c"></uni-icons>
    </view>
  </picker>
</view>
import { reactive } from 'vue'
import { useStore } from 'vuex'
import provinceData from '@/static/js/area.js'

/**
 * 所在地业务
 */
const store = useStore() // 该方法用于返回store实例
const userInfo = computed(() => store.state.userInfo)
const regionIndexs = reactive([0, 0, 0])
const regionList = reactive([provinceData, provinceData[0].city, provinceData[0].city[0].area]) // 当前省市区级联选项列表

// 省市区三级级联选择
const regionColumnchange = e => {
  const { column, value } = e.detail
  switch (column) {
    case 0: // 选中省
      regionList[1] = provinceData[value].city
      regionList[2] = provinceData[value].city[0].area
      regionIndexs[0] = value
      break
    case 1: // 选中市
      regionList[2] = provinceData[regionIndexs[0]].city[value].area
      regionIndexs[1] = value
      break
    case 2: // 选中区县
      regionIndexs[2] = value
      break
    default:
      break
  }
}

// 选中所在地
const regionChange = e => {
  const [provinceIndex, cityIndex, districtIndex] = e.detail.value
  const province = provinceData[provinceIndex]
  const place = province.name + (provice.city[cityIndex].name === provice.name ? '' : provice.city[cityIndex].name) + province.city[cityIndex].area[districtIndex]
  request({
    url: '',
    method: 'POST',
    data: {
      place
    }
  }).then(({body}) => {
    toast('所在地修改成功')
    userInfo.value.region = place
  }).catch(() => {
    toast('所在地修改失败')
  })
}
.vertical-center {
  display: flex;
  align-items: center;
}

.uni-flex {
  display: flex;
}

.flex-auto {
  flex: auto;
}

.info-item {
  padding: 40rpx 0;
  font-size: 32rpx;
  box-shadow: inset 0 -1px 0 0 #ebf2fb;

  .info-label {
    width: 160rpx;
    color: #506f8c;
  }
}

.holder-text {
  color: #b6c5d3;
}
// area.js
export default [{"name": "北京","city": [{"name": "北京","area": ["东城区", "西城区", "崇文区", "宣武区", "朝阳区", "丰台区", "石景山区", "海淀区", "门头沟区", "房山区", "通州区", "顺义区", "昌平区", "大兴区","平谷区","怀柔区", "密云县", "延庆县"]}]},{"name": "天津","city": [{"name": "天津","area": ["和平区", "河东区", "河西区", "南开区", "河北区", "红桥区", "塘沽区", "汉沽区", "大港区", "东丽区", "西青区", "津南区", "北辰区", "武清区","宝坻区","宁河县", "静海县", "蓟  县"]}]},{"name": "河北","city": [{"name": "石家庄","area": ["长安区", "桥东区", "桥西区", "新华区", "郊  区", "井陉矿区", "井陉县", "正定县", "栾城县", "行唐县", "灵寿县", "高邑县", "深泽县", "赞皇县","无极县","平山县", "元氏县", "赵  县", "辛集市", "藁城区", "晋州市", "新乐市", "鹿泉市"]},{"name": "唐山","area": ["路南区", "路北区", "古冶区", "开平区", "新  区", "丰润县", "滦  县", "滦南县", "乐亭县", "迁西县", "玉田县", "唐海县", "遵化市", "丰南市","迁安市"]},{"name": "秦皇岛","area": ["海港区", "山海关区", "北戴河区", "青龙满族自治县", "昌黎县", "抚宁县", "卢龙县"]},{"name": "邯郸","area": ["邯山区", "丛台区", "复兴区", "峰峰矿区", "邯郸县", "临漳县", "成安县", "大名县", "涉  县", "磁  县", "肥乡县", "永年县", "邱  县","鸡泽县","广平县", "馆陶县", "魏  县", "曲周县", "武安市"]},{"name": "邢台","area": ["桥东区", "桥西区", "邢台县", "临城县", "内丘县", "柏乡县", "隆尧县", "任  县", "南和县", "宁晋县", "巨鹿县", "新河县", "广宗县", "平乡县","威  县","清河县", "临西县", "南宫市", "沙河市"]},{"name": "保定","area": ["新市区", "北市区", "南市区", "满城县", "清苑县", "涞水县", "阜平县", "徐水县", "定兴县", "唐  县", "高阳县", "容城县", "涞源县", "望都县","安新县","易  县", "曲阳县", "蠡  县", "顺平县", "博野", "雄县", "涿州市", "定州市", "安国市", "高碑店市"]},{"name": "张家口","area": ["桥东区", "桥西区", "宣化区", "下花园区", "宣化县", "张北县", "康保县", "沽源县", "尚义县", "蔚  县", "阳原县", "怀安县", "万全县", "怀来县","涿鹿县","赤城县", "崇礼县"]},{"name": "承德","area": ["双桥区", "双滦区", "鹰手营子矿区", "承德县", "兴隆县", "平泉县", "滦平县", "隆化县", "丰宁满族自治县", "宽城满族自治县", "围场满族蒙古族自治县"]},{"name": "沧州","area": ["新华区", "运河区", "沧  县", "青  县", "东光县", "海兴县", "盐山县", "肃宁县", "南皮县", "吴桥县", "献  县", "孟村回族自治县", "泊头市","任丘市","黄骅市", "河间市"]},{"name": "廊坊","area": ["安次区", "固安县", "永清县", "香河县", "大城县", "文安县", "大厂回族自治县", "霸州市", "三河市"]},{"name": "衡水","area": ["桃城区", "枣强县", "武邑县", "武强县", "饶阳县", "安平县", "故城县", "景  县", "阜城县", "冀州市", "深州市"]}]},{"name": "山西","city": [{"name": "太原","area": ["小店区", "迎泽区", "杏花岭区", "尖草坪区", "万柏林区", "晋源区", "清徐县", "阳曲县", "娄烦县", "古交市"]},{"name": "大同","area": ["城  区", "矿  区", "南郊区", "新荣区", "阳高县", "天镇县", "广灵县", "灵丘县", "浑源县", "左云县", "大同县"]},{"name": "阳泉","area": ["城  区", "矿  区", "郊  区", "平定县", "盂  县"]},{"name": "长治","area": ["城  区", "郊  区", "长治县", "襄垣县", "屯留县", "平顺县", "黎城县", "壶关县", "长子县", "武乡县", "沁  县", "沁源县", "潞城市"]},{"name": "晋城","area": ["城  区", "沁水县", "阳城县", "陵川县", "泽州县", "高平市"]},{"name": "朔州","area": ["朔城区", "平鲁区", "山阴县", "应  县", "右玉县", "怀仁县"]},{"name": "忻州","area": ["忻府区", "原平市", "定襄县", "五台县", "代  县", "繁峙县", "宁武县", "静乐县", "神池县", "五寨县", "岢岚县", "河曲县", "保德县", "偏关县"]},{"name": "吕梁","area": ["离石区", "孝义市", "汾阳市", "文水县", "交城县", "兴  县", "临  县", "柳林县", "石楼县", "岚  县", "方山县", "中阳县", "交口县"]},{"name": "晋中","area": ["榆次市", "介休市", "榆社县", "左权县", "和顺县", "昔阳县", "寿阳县", "太谷县", "祁  县", "平遥县", "灵石县"]},{"name": "临汾","area": ["临汾市", "侯马市", "霍州市", "曲沃县", "翼城县", "襄汾县", "洪洞县", "古  县", "安泽县", "浮山县", "吉  县", "乡宁县", "蒲  县","大宁县","永和县", "隰  县", "汾西县"]},{"name": "运城","area": ["运城市", "永济市", "河津市", "芮城县", "临猗县", "万荣县", "新绛县", "稷山县", "闻喜县", "夏  县", "绛  县", "平陆县", "垣曲县"]}]},{"name": "内蒙古","city": [{"name": "呼和浩特","area": ["新城区", "回民区", "玉泉区", "郊  区", "土默特左旗", "托克托县", "和林格尔县", "清水河县", "武川县"]},{"name": "包头","area": ["东河区", "昆都伦区", "青山区", "石拐矿区", "白云矿区", "郊  区", "土默特右旗", "固阳县", "达尔罕茂明安联合旗"]},{"name": "乌海","area": ["海勃湾区", "海南区", "乌达区"]},{"name": "赤峰","area": ["红山区", "元宝山区", "松山区", "阿鲁科尔沁旗", "巴林左旗", "巴林右旗", "林西县", "克什克腾旗", "翁牛特旗", "喀喇沁旗", "宁城县", "敖汉旗"]},{"name": "呼伦贝尔","area": ["海拉尔市", "满洲里市", "扎兰屯市", "牙克石市", "根河市", "额尔古纳市", "阿荣旗", "莫力达瓦达斡尔族自治旗", "鄂伦春自治旗", "鄂温克族自治旗","新巴尔虎右旗","新巴尔虎左旗", "陈巴尔虎旗"]},{"name": "兴安盟","area": ["乌兰浩特市", "阿尔山市", "科尔沁右翼前旗", "科尔沁右翼中旗", "扎赉特旗", "突泉县"]},{"name": "通辽","area": ["科尔沁区", "霍林郭勒市", "科尔沁左翼中旗", "科尔沁左翼后旗", "开鲁县", "库伦旗", "奈曼旗", "扎鲁特旗"]},{"name": "锡林郭勒盟","area": ["二连浩特市", "锡林浩特市", "阿巴嘎旗", "苏尼特左旗", "苏尼特右旗", "东乌珠穆沁旗", "西乌珠穆沁旗", "太仆寺旗", "镶黄旗", "正镶白旗", "正蓝旗","多伦县"]},{"name": "乌兰察布盟","area": ["集宁市", "丰镇市", "卓资县", "化德县", "商都县", "兴和县", "凉城县", "察哈尔右翼前旗", "察哈尔右翼中旗", "察哈尔右翼后旗", "四子王旗"]},{"name": "伊克昭盟","area": ["东胜市", "达拉特旗", "准格尔旗", "鄂托克前旗", "鄂托克旗", "杭锦旗", "乌审旗", "伊金霍洛旗"]},{"name": "巴彦淖尔盟","area": ["临河市", "五原县", "磴口县", "乌拉特前旗", "乌拉特中旗", "乌拉特后旗", "杭锦后旗"]},{"name": "阿拉善盟","area": ["阿拉善左旗", "阿拉善右旗", "额济纳旗"]}]},{"name": "辽宁","city": [{"name": "沈阳","area": ["沈河区", "皇姑区", "和平区", "大东区", "铁西区", "苏家屯区", "东陵区", "于洪区", "新民市", "法库县", "辽中县", "康平县", "新城子区", "其他"]},{"name": "大连","area": ["西岗区", "中山区", "沙河口区", "甘井子区", "旅顺口区", "金州区", "瓦房店市", "普兰店市", "庄河市", "长海县", "其他"]},{"name": "鞍山","area": ["铁东区", "铁西区", "立山区", "千山区", "海城市", "台安县", "岫岩满族自治县", "其他"]},{"name": "抚顺","area": ["顺城区", "新抚区", "东洲区", "望花区", "抚顺县", "清原满族自治县", "新宾满族自治县", "其他"]},{"name": "本溪","area": ["平山区", "明山区", "溪湖区", "南芬区", "本溪满族自治县", "桓仁满族自治县", "其他"]},{"name": "丹东","area": ["振兴区", "元宝区", "振安区", "东港市", "凤城市", "宽甸满族自治县", "其他"]},{"name": "锦州","area": ["太和区", "古塔区", "凌河区", "凌海市", "黑山县", "义县", "北宁市", "其他"]},{"name": "营口","area": ["站前区", "西市区", "鲅鱼圈区", "老边区", "大石桥市", "盖州市", "其他"]},{"name": "阜新","area": ["海州区", "新邱区", "太平区", "清河门区", "细河区", "彰武县", "阜新蒙古族自治县", "其他"]},{"name": "辽阳","area": ["白塔区", "文圣区", "宏伟区", "太子河区", "弓长岭区", "灯塔市", "辽阳县", "其他"]},{"name": "盘锦","area": ["双台子区", "兴隆台区", "盘山县", "大洼县", "其他"]},{"name": "铁岭","area": ["银州区", "清河区", "调兵山市", "开原市", "铁岭县", "昌图县", "西丰县", "其他"]},{"name": "朝阳","area": ["双塔区", "龙城区", "凌源市", "北票市", "朝阳县", "建平县", "喀喇沁左翼蒙古族自治县", "其他"]},{"name": "葫芦岛","area": ["龙港区", "南票区", "连山区", "兴城市", "绥中县", "建昌县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "吉林","city": [{"name": "长春","area": ["朝阳区", "宽城区", "二道区", "南关区", "绿园区", "双阳区", "九台市", "榆树市", "德惠市", "农安县", "其他"]},{"name": "吉林","area": ["船营区", "昌邑区", "龙潭区", "丰满区", "舒兰市", "桦甸市", "蛟河市", "磐石市", "永吉县", "其他"]},{"name": "四平","area": ["铁西区", "铁东区", "公主岭市", "双辽市", "梨树县", "伊通满族自治县", "其他"]},{"name": "辽源","area": ["龙山区", "西安区", "东辽县", "东丰县", "其他"]},{"name": "通化","area": ["东昌区", "二道江区", "梅河口市", "集安市", "通化县", "辉南县", "柳河县", "其他"]},{"name": "白山","area": ["八道江区", "江源区", "临江市", "靖宇县", "抚松县", "长白朝鲜族自治县", "其他"]},{"name": "松原","area": ["宁江区", "乾安县", "长岭县", "扶余县", "前郭尔罗斯蒙古族自治县", "其他"]},{"name": "白城","area": ["洮北区", "大安市", "洮南市", "镇赉县", "通榆县", "其他"]},{"name": "延边朝鲜族自治州","area": ["延吉市", "图们市", "敦化市", "龙井市", "珲春市", "和龙市", "安图县", "汪清县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "黑龙江","city": [{"name": "哈尔滨","area": ["松北区", "道里区", "南岗区", "平房区", "香坊区", "道外区", "呼兰区", "阿城区", "双城市", "尚志市", "五常市", "宾县", "方正县", "通河县","巴彦县","延寿县", "木兰县", "依兰县", "其他"]},{"name": "齐齐哈尔","area": ["龙沙区", "昂昂溪区", "铁锋区", "建华区", "富拉尔基区", "碾子山区", "梅里斯达斡尔族区", "讷河市", "富裕县", "拜泉县", "甘南县", "依安县", "克山县","泰来县","克东县", "龙江县", "其他"]},{"name": "鹤岗","area": ["兴山区", "工农区", "南山区", "兴安区", "向阳区", "东山区", "萝北县", "绥滨县", "其他"]},{"name": "双鸭山","area": ["尖山区", "岭东区", "四方台区", "宝山区", "集贤县", "宝清县", "友谊县", "饶河县", "其他"]},{"name": "鸡西","area": ["鸡冠区", "恒山区", "城子河区", "滴道区", "梨树区", "麻山区", "密山市", "虎林市", "鸡东县", "其他"]},{"name": "大庆","area": ["萨尔图区", "红岗区", "龙凤区", "让胡路区", "大同区", "林甸县", "肇州县", "肇源县", "杜尔伯特蒙古族自治县", "其他"]},{"name": "伊春","area": ["伊春区", "带岭区", "南岔区", "金山屯区", "西林区", "美溪区", "乌马河区", "翠峦区", "友好区", "上甘岭区", "五营区", "红星区", "新青区","汤旺河区","乌伊岭区", "铁力市", "嘉荫县", "其他"]},{"name": "牡丹江","area": ["爱民区", "东安区", "阳明区", "西安区", "绥芬河市", "宁安市", "海林市", "穆棱市", "林口县", "东宁县", "其他"]},{"name": "佳木斯","area": ["向阳区", "前进区", "东风区", "郊区", "同江市", "富锦市", "桦川县", "抚远县", "桦南县", "汤原县", "其他"]},{"name": "七台河","area": ["桃山区", "新兴区", "茄子河区", "勃利县", "其他"]},{"name": "黑河","area": ["爱辉区", "北安市", "五大连池市", "逊克县", "嫩江县", "孙吴县", "其他"]},{"name": "绥化","area": ["北林区", "安达市", "肇东市", "海伦市", "绥棱县", "兰西县", "明水县", "青冈县", "庆安县", "望奎县", "其他"]},{"name": "大兴安岭地区","area": ["呼玛县", "塔河县", "漠河县", "大兴安岭辖区", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "上海","city": [{"name": "上海","area": ["黄浦区", "卢湾区", "徐汇区", "长宁区", "静安区", "普陀区", "闸北区", "虹口区", "杨浦区", "宝山区", "闵行区", "嘉定区", "松江区", "金山区","青浦区","南汇区", "奉贤区", "浦东新区", "崇明县", "其他"]}]},{"name": "江苏","city": [{"name": "南京","area": ["玄武区", "白下区", "秦淮区", "建邺区", "鼓楼区", "下关区", "栖霞区", "雨花台区", "浦口区", "江宁区", "六合区", "溧水县", "高淳县", "其他"]},{"name": "苏州","area": ["金阊区", "平江区", "沧浪区", "虎丘区", "吴中区", "相城区", "常熟市", "张家港市", "昆山市", "吴江市", "太仓市", "其他"]},{"name": "无锡","area": ["崇安区", "南长区", "北塘区", "滨湖区", "锡山区", "惠山区", "江阴市", "宜兴市", "其他"]},{"name": "常州","area": ["钟楼区", "天宁区", "戚墅堰区", "新北区", "武进区", "金坛市", "溧阳市", "其他"]},{"name": "镇江","area": ["京口区", "润州区", "丹徒区", "丹阳市", "扬中市", "句容市", "其他"]},{"name": "南通","area": ["崇川区", "港闸区", "通州市", "如皋市", "海门市", "启东市", "海安县", "如东县", "其他"]},{"name": "泰州","area": ["海陵区", "高港区", "姜堰市", "泰兴市", "靖江市", "兴化市", "其他"]},{"name": "扬州","area": ["广陵区", "维扬区", "邗江区", "江都市", "仪征市", "高邮市", "宝应县", "其他"]},{"name": "盐城","area": ["亭湖区", "盐都区", "大丰市", "东台市", "建湖县", "射阳县", "阜宁县", "滨海县", "响水县", "其他"]},{"name": "连云港","area": ["新浦区", "海州区", "连云区", "东海县", "灌云县", "赣榆县", "灌南县", "其他"]},{"name": "徐州","area": ["云龙区", "鼓楼区", "九里区", "泉山区", "贾汪区", "邳州市", "新沂市", "铜山县", "睢宁县", "沛县", "丰县", "其他"]},{"name": "淮安","area": ["清河区", "清浦区", "楚州区", "淮阴区", "涟水县", "洪泽县", "金湖县", "盱眙县", "其他"]},{"name": "宿迁","area": ["宿城区", "宿豫区", "沭阳县", "泗阳县", "泗洪县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "浙江","city": [{"name": "杭州","area": ["拱墅区", "西湖区", "上城区", "下城区", "江干区", "滨江区", "余杭区", "萧山区", "建德市", "富阳市", "临安市", "桐庐县", "淳安县", "其他"]},{"name": "宁波","area": ["海曙区", "江东区", "江北区", "镇海区", "北仑区", "鄞州区", "余姚市", "慈溪市", "奉化市", "宁海县", "象山县", "其他"]},{"name": "温州","area": ["鹿城区", "龙湾区", "瓯海区", "瑞安市", "乐清市", "永嘉县", "洞头县", "平阳县", "苍南县", "文成县", "泰顺县", "其他"]},{"name": "嘉兴","area": ["秀城区", "秀洲区", "海宁市", "平湖市", "桐乡市", "嘉善县", "海盐县", "其他"]},{"name": "湖州","area": ["吴兴区", "南浔区", "长兴县", "德清县", "安吉县", "其他"]},{"name": "绍兴","area": ["越城区", "诸暨市", "上虞市", "嵊州市", "绍兴县", "新昌县", "其他"]},{"name": "金华","area": ["婺城区", "金东区", "兰溪市", "义乌市", "东阳市", "永康市", "武义县", "浦江县", "磐安县", "其他"]},{"name": "衢州","area": ["柯城区", "衢江区", "江山市", "龙游县", "常山县", "开化县", "其他"]},{"name": "舟山","area": ["定海区", "普陀区", "岱山县", "嵊泗县", "其他"]},{"name": "台州","area": ["椒江区", "黄岩区", "路桥区", "临海市", "温岭市", "玉环县", "天台县", "仙居县", "三门县", "其他"]},{"name": "丽水","area": ["莲都区", "龙泉市", "缙云县", "青田县", "云和县", "遂昌县", "松阳县", "庆元县", "景宁畲族自治县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "安徽","city": [{"name": "合肥","area": ["庐阳区", "瑶海区", "蜀山区", "包河区", "长丰县", "肥东县", "肥西县", "其他"]},{"name": "芜湖","area": ["镜湖区", "弋江区", "鸠江区", "三山区", "芜湖县", "南陵县", "繁昌县", "其他"]},{"name": "蚌埠","area": ["蚌山区", "龙子湖区", "禹会区", "淮上区", "怀远县", "固镇县", "五河县", "其他"]},{"name": "淮南","area": ["田家庵区", "大通区", "谢家集区", "八公山区", "潘集区", "凤台县", "其他"]},{"name": "马鞍山","area": ["雨山区", "花山区", "金家庄区", "当涂县", "其他"]},{"name": "淮北","area": ["相山区", "杜集区", "烈山区", "濉溪县", "其他"]},{"name": "铜陵","area": ["铜官山区", "狮子山区", "郊区", "铜陵县", "其他"]},{"name": "安庆","area": ["迎江区", "大观区", "宜秀区", "桐城市", "宿松县", "枞阳县", "太湖县", "怀宁县", "岳西县", "望江县", "潜山县", "其他"]},{"name": "黄山","area": ["屯溪区", "黄山区", "徽州区", "休宁县", "歙县", "祁门县", "黟县", "其他"]},{"name": "滁州","area": ["琅琊区", "南谯区", "天长市", "明光市", "全椒县", "来安县", "定远县", "凤阳县", "其他"]},{"name": "阜阳","area": ["颍州区", "颍东区", "颍泉区", "界首市", "临泉县", "颍上县", "阜南县", "太和县", "其他"]},{"name": "宿州","area": ["埇桥区", "萧县", "泗县", "砀山县", "灵璧县", "其他"]},{"name": "巢湖","area": ["居巢区", "含山县", "无为县", "庐江县", "和县", "其他"]},{"name": "六安","area": ["金安区", "裕安区", "寿县", "霍山县", "霍邱县", "舒城县", "金寨县", "其他"]},{"name": "亳州","area": ["谯城区", "利辛县", "涡阳县", "蒙城县", "其他"]},{"name": "池州","area": ["贵池区", "东至县", "石台县", "青阳县", "其他"]},{"name": "宣城","area": ["宣州区", "宁国市", "广德县", "郎溪县", "泾县", "旌德县", "绩溪县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "福建","city": [{"name": "福州","area": ["鼓楼区", "台江区", "仓山区", "马尾区", "晋安区", "福清市", "长乐市", "闽侯县", "闽清县", "永泰县", "连江县", "罗源县", "平潭县", "其他"]},{"name": "厦门","area": ["思明区", "海沧区", "湖里区", "集美区", "同安区", "翔安区", "其他"]},{"name": "莆田","area": ["城厢区", "涵江区", "荔城区", "秀屿区", "仙游县", "其他"]},{"name": "三明","area": ["梅列区", "三元区", "永安市", "明溪县", "将乐县", "大田县", "宁化县", "建宁县", "沙县", "尤溪县", "清流县", "泰宁县", "其他"]},{"name": "泉州","area": ["鲤城区", "丰泽区", "洛江区", "泉港区", "石狮市", "晋江市", "南安市", "惠安县", "永春县", "安溪县", "德化县", "金门县", "其他"]},{"name": "漳州","area": ["芗城区", "龙文区", "龙海市", "平和县", "南靖县", "诏安县", "漳浦县", "华安县", "东山县", "长泰县", "云霄县", "其他"]},{"name": "南平","area": ["延平区", "建瓯市", "邵武市", "武夷山市", "建阳市", "松溪县", "光泽县", "顺昌县", "浦城县", "政和县", "其他"]},{"name": "龙岩","area": ["新罗区", "漳平市", "长汀县", "武平县", "上杭县", "永定县", "连城县", "其他"]},{"name": "宁德","area": ["蕉城区", "福安市", "福鼎市", "寿宁县", "霞浦县", "柘荣县", "屏南县", "古田县", "周宁县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "江西","city": [{"name": "南昌","area": ["东湖区", "西湖区", "青云谱区", "湾里区", "青山湖区", "新建县", "南昌县", "进贤县", "安义县", "其他"]},{"name": "景德镇","area": ["珠山区", "昌江区", "乐平市", "浮梁县", "其他"]},{"name": "萍乡","area": ["安源区", "湘东区", "莲花县", "上栗县", "芦溪县", "其他"]},{"name": "九江","area": ["浔阳区", "庐山区", "瑞昌市", "九江县", "星子县", "武宁县", "彭泽县", "永修县", "修水县", "湖口县", "德安县", "都昌县", "其他"]},{"name": "新余","area": ["渝水区", "分宜县", "其他"]},{"name": "鹰潭","area": ["月湖区", "贵溪市", "余江县", "其他"]},{"name": "赣州","area": ["章贡区", "瑞金市", "南康市", "石城县", "安远县", "赣县", "宁都县", "寻乌县", "兴国县", "定南县", "上犹县", "于都县", "龙南县", "崇义县","信丰县","全南县", "大余县", "会昌县", "其他"]},{"name": "吉安","area": ["吉州区", "青原区", "井冈山市", "吉安县", "永丰县", "永新县", "新干县", "泰和县", "峡江县", "遂川县", "安福县", "吉水县", "万安县", "其他"]},{"name": "宜春","area": ["袁州区", "丰城市", "樟树市", "高安市", "铜鼓县", "靖安县", "宜丰县", "奉新县", "万载县", "上高县", "其他"]},{"name": "抚州","area": ["临川区", "南丰县", "乐安县", "金溪县", "南城县", "东乡县", "资溪县", "宜黄县", "广昌县", "黎川县", "崇仁县", "其他"]},{"name": "上饶","area": ["信州区", "德兴市", "上饶县", "广丰县", "鄱阳县", "婺源县", "铅山县", "余干县", "横峰县", "弋阳县", "玉山县", "万年县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "山东","city": [{"name": "济南","area": ["市中区", "历下区", "天桥区", "槐荫区", "历城区", "长清区", "章丘市", "平阴县", "济阳县", "商河县", "其他"]},{"name": "青岛","area": ["市南区", "市北区", "城阳区", "四方区", "李沧区", "黄岛区", "崂山区", "胶南市", "胶州市", "平度市", "莱西市", "即墨市", "其他"]},{"name": "淄博","area": ["张店区", "临淄区", "淄川区", "博山区", "周村区", "桓台县", "高青县", "沂源县", "其他"]},{"name": "枣庄","area": ["市中区", "山亭区", "峄城区", "台儿庄区", "薛城区", "滕州市", "其他"]},{"name": "东营","area": ["东营区", "河口区", "垦利县", "广饶县", "利津县", "其他"]},{"name": "烟台","area": ["芝罘区", "福山区", "牟平区", "莱山区", "龙口市", "莱阳市", "莱州市", "招远市", "蓬莱市", "栖霞市", "海阳市", "长岛县", "其他"]},{"name": "潍坊","area": ["潍城区", "寒亭区", "坊子区", "奎文区", "青州市", "诸城市", "寿光市", "安丘市", "高密市", "昌邑市", "昌乐县", "临朐县", "其他"]},{"name": "济宁","area": ["市中区", "任城区", "曲阜市", "兖州市", "邹城市", "鱼台县", "金乡县", "嘉祥县", "微山县", "汶上县", "泗水县", "梁山县", "其他"]},{"name": "泰安","area": ["泰山区", "岱岳区", "新泰市", "肥城市", "宁阳县", "东平县", "其他"]},{"name": "威海","area": ["环翠区", "乳山市", "文登市", "荣成市", "其他"]},{"name": "日照","area": ["东港区", "岚山区", "五莲县", "莒县", "其他"]},{"name": "莱芜","area": ["莱城区", "钢城区", "其他"]},{"name": "临沂","area": ["兰山区", "罗庄区", "河东区", "沂南县", "郯城县", "沂水县", "苍山县", "费县", "平邑县", "莒南县", "蒙阴县", "临沭县", "其他"]},{"name": "德州","area": ["德城区", "乐陵市", "禹城市", "陵县", "宁津县", "齐河县", "武城县", "庆云县", "平原县", "夏津县", "临邑县", "其他"]},{"name": "聊城","area": ["东昌府区", "临清市", "高唐县", "阳谷县", "茌平县", "莘县", "东阿县", "冠县", "其他"]},{"name": "滨州","area": ["滨城区", "邹平县", "沾化县", "惠民县", "博兴县", "阳信县", "无棣县", "其他"]},{"name": "菏泽","area": ["牡丹区", "鄄城县", "单县", "郓城县", "曹县", "定陶县", "巨野县", "东明县", "成武县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "河南","city": [{"name": "郑州","area": ["中原区", "金水区", "二七区", "管城回族区", "上街区", "惠济区", "巩义市", "新郑市", "新密市", "登封市", "荥阳市", "中牟县", "其他"]},{"name": "开封","area": ["鼓楼区", "龙亭区", "顺河回族区", "禹王台区", "金明区", "开封县", "尉氏县", "兰考县", "杞县", "通许县", "其他"]},{"name": "洛阳","area": ["西工区", "老城区", "涧西区", "瀍河回族区", "洛龙区", "吉利区", "偃师市", "孟津县", "汝阳县", "伊川县", "洛宁县", "嵩县", "宜阳县", "新安县","栾川县","其他"]},{"name": "平顶山","area": ["新华区", "卫东区", "湛河区", "石龙区", "汝州市", "舞钢市", "宝丰县", "叶县", "郏县", "鲁山县", "其他"]},{"name": "安阳","area": ["北关区", "文峰区", "殷都区", "龙安区", "林州市", "安阳县", "滑县", "内黄县", "汤阴县", "其他"]},{"name": "鹤壁","area": ["淇滨区", "山城区", "鹤山区", "浚县", "淇县", "其他"]},{"name": "新乡","area": ["卫滨区", "红旗区", "凤泉区", "牧野区", "卫辉市", "辉县市", "新乡县", "获嘉县", "原阳县", "长垣县", "封丘县", "延津县", "其他"]},{"name": "焦作","area": ["解放区", "中站区", "马村区", "山阳区", "沁阳市", "孟州市", "修武县", "温县", "武陟县", "博爱县", "其他"]},{"name": "濮阳","area": ["华龙区", "濮阳县", "南乐县", "台前县", "清丰县", "范县", "其他"]},{"name": "许昌","area": ["魏都区", "禹州市", "长葛市", "许昌县", "鄢陵县", "襄城县", "其他"]},{"name": "漯河","area": ["源汇区", "郾城区", "召陵区", "临颍县", "舞阳县", "其他"]},{"name": "三门峡","area": ["湖滨区", "义马市", "灵宝市", "渑池县", "卢氏县", "陕县", "其他"]},{"name": "南阳","area": ["卧龙区", "宛城区", "邓州市", "桐柏县", "方城县", "淅川县", "镇平县", "唐河县", "南召县", "内乡县", "新野县", "社旗县", "西峡县", "其他"]},{"name": "商丘","area": ["梁园区", "睢阳区", "永城市", "宁陵县", "虞城县", "民权县", "夏邑县", "柘城县", "睢县", "其他"]},{"name": "信阳","area": ["浉河区", "平桥区", "潢川县", "淮滨县", "息县", "新县", "商城县", "固始县", "罗山县", "光山县", "其他"]},{"name": "周口","area": ["川汇区", "项城市", "商水县", "淮阳县", "太康县", "鹿邑县", "西华县", "扶沟县", "沈丘县", "郸城县", "其他"]},{"name": "驻马店","area": ["驿城区", "确山县", "新蔡县", "上蔡县", "西平县", "泌阳县", "平舆县", "汝南县", "遂平县", "正阳县", "其他"]},{"name": "焦作","area": ["济源市", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "湖北","city": [{"name": "武汉","area": ["江岸区", "武昌区", "江汉区", "硚口区", "汉阳区", "青山区", "洪山区", "东西湖区", "汉南区", "蔡甸区", "江夏区", "黄陂区", "新洲区", "其他"]},{"name": "黄石","area": ["黄石港区", "西塞山区", "下陆区", "铁山区", "大冶市", "阳新县", "其他"]},{"name": "十堰","area": ["张湾区", "茅箭区", "丹江口市", "郧县", "竹山县", "房县", "郧西县", "竹溪县", "其他"]},{"name": "荆州","area": ["沙市区", "荆州区", "洪湖市", "石首市", "松滋市", "监利县", "公安县", "江陵县", "其他"]},{"name": "宜昌","area": ["西陵区", "伍家岗区", "点军区", "猇亭区", "夷陵区", "宜都市", "当阳市", "枝江市", "秭归县", "远安县", "兴山县", "五峰土家族自治县","长阳土家族自治县","其他"]},{"name": "襄樊","area": ["襄城区", "樊城区", "襄阳区", "老河口市", "枣阳市", "宜城市", "南漳县", "谷城县", "保康县", "其他"]},{"name": "鄂州","area": ["鄂城区", "华容区", "梁子湖区", "其他"]},{"name": "荆门","area": ["东宝区", "掇刀区", "钟祥市", "京山县", "沙洋县", "其他"]},{"name": "孝感","area": ["孝南区", "应城市", "安陆市", "汉川市", "云梦县", "大悟县", "孝昌县", "其他"]},{"name": "黄冈","area": ["黄州区", "麻城市", "武穴市", "红安县", "罗田县", "浠水县", "蕲春县", "黄梅县", "英山县", "团风县", "其他"]},{"name": "咸宁","area": ["咸安区", "赤壁市", "嘉鱼县", "通山县", "崇阳县", "通城县", "其他"]},{"name": "随州","area": ["曾都区", "广水市", "其他"]},{"name": "恩施土家族苗族自治州","area": ["恩施市", "利川市", "建始县", "来凤县", "巴东县", "鹤峰县", "宣恩县", "咸丰县", "其他"]},{"name": "仙桃","area": ["仙桃"]},{"name": "天门","area": ["天门"]},{"name": "潜江","area": ["潜江"]},{"name": "神农架林区","area": ["神农架林区"]},{"name": "其他","area": ["其他"]}]},{"name": "湖南","city": [{"name": "长沙","area": ["岳麓区", "芙蓉区", "天心区", "开福区", "雨花区", "浏阳市", "长沙县", "望城县", "宁乡县", "其他"]},{"name": "株洲","area": ["天元区", "荷塘区", "芦淞区", "石峰区", "醴陵市", "株洲县", "炎陵县", "茶陵县", "攸县", "其他"]},{"name": "湘潭","area": ["岳塘区", "雨湖区", "湘乡市", "韶山市", "湘潭县", "其他"]},{"name": "衡阳","area": ["雁峰区", "珠晖区", "石鼓区", "蒸湘区", "南岳区", "耒阳市", "常宁市", "衡阳县", "衡东县", "衡山县", "衡南县", "祁东县", "其他"]},{"name": "邵阳","area": ["双清区", "大祥区", "北塔区", "武冈市", "邵东县", "洞口县", "新邵县", "绥宁县", "新宁县", "邵阳县", "隆回县", "城步苗族自治县", "其他"]},{"name": "岳阳","area": ["岳阳楼区", "云溪区", "君山区", "临湘市", "汨罗市", "岳阳县", "湘阴县", "平江县", "华容县", "其他"]},{"name": "常德","area": ["武陵区", "鼎城区", "津市市", "澧县", "临澧县", "桃源县", "汉寿县", "安乡县", "石门县", "其他"]},{"name": "张家界","area": ["永定区", "武陵源区", "慈利县", "桑植县", "其他"]},{"name": "益阳","area": ["赫山区", "资阳区", "沅江市", "桃江县", "南县", "安化县", "其他"]},{"name": "郴州","area": ["北湖区", "苏仙区", "资兴市", "宜章县", "汝城县", "安仁县", "嘉禾县", "临武县", "桂东县", "永兴县", "桂阳县", "其他"]},{"name": "永州","area": ["冷水滩区", "零陵区", "祁阳县", "蓝山县", "宁远县", "新田县", "东安县", "江永县", "道县", "双牌县", "江华瑶族自治县", "其他"]},{"name": "怀化","area": ["鹤城区", "洪江市", "会同县", "沅陵县", "辰溪县", "溆浦县", "中方县", "新晃侗族自治县", "芷江侗族自治县", "通道侗族自治县", "靖州苗族侗族自治县","麻阳苗族自治县","其他"]},{"name": "娄底","area": ["娄星区", "冷水江市", "涟源市", "新化县", "双峰县", "其他"]},{"name": "湘西土家族苗族自治州","area": ["吉首市", "古丈县", "龙山县", "永顺县", "凤凰县", "泸溪县", "保靖县", "花垣县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "广东","city": [{"name": "广州","area": ["越秀区", "荔湾区", "海珠区", "天河区", "白云区", "黄埔区", "番禺区", "花都区", "南沙区", "萝岗区", "增城市", "从化市", "其他"]},{"name": "深圳","area": ["福田区", "罗湖区", "南山区", "宝安区", "龙岗区", "盐田区", "其他"]},{"name": "东莞","area": ["莞城", "常平", "塘厦", "塘厦", "塘厦", "其他"]},{"name": "中山","area": ["中山"]},{"name": "潮州","area": ["湘桥区", "潮安县", "饶平县", "其他"]},{"name": "揭阳","area": ["榕城区", "揭东县", "揭西县", "惠来县", "普宁市", "其他"]},{"name": "云浮","area": ["云城区", "新兴县", "郁南县", "云安县", "罗定市", "其他"]},{"name": "珠海","area": ["香洲区", "斗门区", "金湾区", "其他"]},{"name": "汕头","area": ["金平区", "濠江区", "龙湖区", "潮阳区", "潮南区", "澄海区", "南澳县", "其他"]},{"name": "韶关","area": ["浈江区", "武江区", "曲江区", "乐昌市", "南雄市", "始兴县", "仁化县", "翁源县", "新丰县", "乳源瑶族自治县", "其他"]},{"name": "佛山","area": ["禅城区", "南海区", "顺德区", "三水区", "高明区", "其他"]},{"name": "江门","area": ["蓬江区", "江海区", "新会区", "恩平市", "台山市", "开平市", "鹤山市", "其他"]},{"name": "湛江","area": ["赤坎区", "霞山区", "坡头区", "麻章区", "吴川市", "廉江市", "雷州市", "遂溪县", "徐闻县", "其他"]},{"name": "茂名","area": ["茂南区", "茂港区", "化州市", "信宜市", "高州市", "电白县", "其他"]},{"name": "肇庆","area": ["端州区", "鼎湖区", "高要市", "四会市", "广宁县", "怀集县", "封开县", "德庆县", "其他"]},{"name": "惠州","area": ["惠城区", "惠阳区", "博罗县", "惠东县", "龙门县", "其他"]},{"name": "梅州","area": ["梅江区", "兴宁市", "梅县", "大埔县", "丰顺县", "五华县", "平远县", "蕉岭县", "其他"]},{"name": "汕尾","area": ["城区", "陆丰市", "海丰县", "陆河县", "其他"]},{"name": "河源","area": ["源城区", "紫金县", "龙川县", "连平县", "和平县", "东源县", "其他"]},{"name": "阳江","area": ["江城区", "阳春市", "阳西县", "阳东县", "其他"]},{"name": "清远","area": ["清城区", "英德市", "连州市", "佛冈县", "阳山县", "清新县", "连山壮族瑶族自治县", "连南瑶族自治县", "其他"]}]},{"name": "广西","city": [{"name": "南宁","area": ["青秀区", "兴宁区", "西乡塘区", "良庆区", "江南区", "邕宁区", "武鸣县", "隆安县", "马山县", "上林县", "宾阳县", "横县", "其他"]},{"name": "柳州","area": ["城中区", "鱼峰区", "柳北区", "柳南区", "柳江县", "柳城县", "鹿寨县", "融安县", "融水苗族自治县", "三江侗族自治县", "其他"]},{"name": "桂林","area": ["象山区", "秀峰区", "叠彩区", "七星区", "雁山区", "阳朔县", "临桂县", "灵川县", "全州县", "平乐县", "兴安县", "灌阳县", "荔浦县", "资源县","永福县","龙胜各族自治县", "恭城瑶族自治县", "其他"]},{"name": "梧州","area": ["万秀区", "蝶山区", "长洲区", "岑溪市", "苍梧县", "藤县", "蒙山县", "其他"]},{"name": "北海","area": ["海城区", "银海区", "铁山港区", "合浦县", "其他"]},{"name": "防城港","area": ["港口区", "防城区", "东兴市", "上思县", "其他"]},{"name": "钦州","area": ["钦南区", "钦北区", "灵山县", "浦北县", "其他"]},{"name": "贵港","area": ["港北区", "港南区", "覃塘区", "桂平市", "平南县", "其他"]},{"name": "玉林","area": ["玉州区", "北流市", "容县", "陆川县", "博白县", "兴业县", "其他"]},{"name": "百色","area": ["右江区", "凌云县", "平果县", "西林县", "乐业县", "德保县", "田林县", "田阳县", "靖西县", "田东县", "那坡县", "隆林各族自治县", "其他"]},{"name": "贺州","area": ["八步区", "钟山县", "昭平县", "富川瑶族自治县", "其他"]},{"name": "河池","area": ["金城江区", "宜州市", "天峨县", "凤山县", "南丹县", "东兰县", "都安瑶族自治县", "罗城仫佬族自治县", "巴马瑶族自治县", "环江毛南族自治县", "大化瑶族自治县","其他"]},{"name": "来宾","area": ["兴宾区", "合山市", "象州县", "武宣县", "忻城县", "金秀瑶族自治县", "其他"]},{"name": "崇左","area": ["江州区", "凭祥市", "宁明县", "扶绥县", "龙州县", "大新县", "天等县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "海南","city": [{"name": "海口","area": ["龙华区", "秀英区", "琼山区", "美兰区", "其他"]},{"name": "三亚","area": ["三亚市", "其他"]},{"name": "五指山","area": ["五指山"]},{"name": "琼海","area": ["琼海"]},{"name": "儋州","area": ["儋州"]},{"name": "文昌","area": ["文昌"]},{"name": "万宁","area": ["万宁"]},{"name": "东方","area": ["东方"]},{"name": "澄迈县","area": ["澄迈县"]},{"name": "定安县","area": ["定安县"]},{"name": "屯昌县","area": ["屯昌县"]},{"name": "临高县","area": ["临高县"]},{"name": "白沙黎族自治县","area": ["白沙黎族自治县"]},{"name": "昌江黎族自治县","area": ["昌江黎族自治县"]},{"name": "乐东黎族自治县","area": ["乐东黎族自治县"]},{"name": "陵水黎族自治县","area": ["陵水黎族自治县"]},{"name": "保亭黎族苗族自治县","area": ["保亭黎族苗族自治县"]},{"name": "琼中黎族苗族自治县","area": ["琼中黎族苗族自治县"]},{"name": "其他","area": ["其他"]}]},{"name": "重庆","city": [{"name": "重庆","area": ["渝中区", "大渡口区", "江北区", "南岸区", "北碚区", "渝北区", "巴南区", "长寿区", "双桥区", "沙坪坝区", "万盛区", "万州区", "涪陵区", "黔江区","永川区","合川区", "江津区", "九龙坡区", "南川区", "綦江县", "潼南县", "荣昌县", "璧山县", "大足县", "铜梁县", "梁平县", "开县", "忠县", "城口县", "垫江县","武隆县","丰都县", "奉节县", "云阳县", "巫溪县", "巫山县", "石柱土家族自治县", "秀山土家族苗族自治县", "酉阳土家族苗族自治县", "彭水苗族土家族自治县", "其他"]}]},{"name": "四川","city": [{"name": "成都","area": ["青羊区", "锦江区", "金牛区", "武侯区", "成华区", "龙泉驿区", "青白江区", "新都区", "温江区", "都江堰市", "彭州市", "邛崃市", "崇州市","金堂县","郫县","新津县", "双流县", "蒲江县", "大邑县", "其他"]},{"name": "自贡","area": ["大安区", "自流井区", "贡井区", "沿滩区", "荣县", "富顺县", "其他"]},{"name": "攀枝花","area": ["仁和区", "米易县", "盐边县", "东区", "西区", "其他"]},{"name": "泸州","area": ["江阳区", "纳溪区", "龙马潭区", "泸县", "合江县", "叙永县", "古蔺县", "其他"]},{"name": "德阳","area": ["旌阳区", "广汉市", "什邡市", "绵竹市", "罗江县", "中江县", "其他"]},{"name": "绵阳","area": ["涪城区", "游仙区", "江油市", "盐亭县", "三台县", "平武县", "安县", "梓潼县", "北川羌族自治县", "其他"]},{"name": "广元","area": ["元坝区", "朝天区", "青川县", "旺苍县", "剑阁县", "苍溪县", "市中区", "其他"]},{"name": "遂宁","area": ["船山区", "安居区", "射洪县", "蓬溪县", "大英县", "其他"]},{"name": "内江","area": ["市中区", "东兴区", "资中县", "隆昌县", "威远县", "其他"]},{"name": "乐山","area": ["市中区", "五通桥区", "沙湾区", "金口河区", "峨眉山市", "夹江县", "井研县", "犍为县", "沐川县", "马边彝族自治县", "峨边彝族自治县", "其他"]},{"name": "南充","area": ["顺庆区", "高坪区", "嘉陵区", "阆中市", "营山县", "蓬安县", "仪陇县", "南部县", "西充县", "其他"]},{"name": "眉山","area": ["东坡区", "仁寿县", "彭山县", "洪雅县", "丹棱县", "青神县", "其他"]},{"name": "宜宾","area": ["翠屏区", "宜宾县", "兴文县", "南溪县", "珙县", "长宁县", "高县", "江安县", "筠连县", "屏山县", "其他"]},{"name": "广安","area": ["广安区", "华蓥市", "岳池县", "邻水县", "武胜县", "其他"]},{"name": "达州","area": ["通川区", "万源市", "达县", "渠县", "宣汉县", "开江县", "大竹县", "其他"]},{"name": "雅安","area": ["雨城区", "芦山县", "石棉县", "名山县", "天全县", "荥经县", "宝兴县", "汉源县", "其他"]},{"name": "巴中","area": ["巴州区", "南江县", "平昌县", "通江县", "其他"]},{"name": "资阳","area": ["雁江区", "简阳市", "安岳县", "乐至县", "其他"]},{"name": "阿坝藏族羌族自治州","area": ["马尔康县", "九寨沟县", "红原县", "汶川县", "阿坝县", "理县", "若尔盖县", "小金县", "黑水县", "金川县", "松潘县", "壤塘县", "茂县", "其他"]},{"name": "甘孜藏族自治州","area": ["康定县", "丹巴县", "炉霍县", "九龙县", "甘孜县", "雅江县", "新龙县", "道孚县", "白玉县", "理塘县", "德格县", "乡城县", "石渠县", "稻城县","色达县","巴塘县", "泸定县", "得荣县", "其他"]},{"name": "凉山彝族自治州","area": ["西昌市", "美姑县", "昭觉县", "金阳县", "甘洛县", "布拖县", "雷波县", "普格县", "宁南县", "喜德县", "会东县", "越西县", "会理县", "盐源县","德昌县","冕宁县", "木里藏族自治县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "贵州","city": [{"name": "贵阳","area": ["南明区", "云岩区", "花溪区", "乌当区", "白云区", "小河区", "清镇市", "开阳县", "修文县", "息烽县", "其他"]},{"name": "六盘水","area": ["钟山区", "水城县", "盘县", "六枝特区", "其他"]},{"name": "遵义","area": ["红花岗区", "汇川区", "赤水市", "仁怀市", "遵义县", "绥阳县", "桐梓县", "习水县", "凤冈县", "正安县", "余庆县", "湄潭县", "道真仡佬族苗族自治县","务川仡佬族苗族自治县", "其他"]},{"name": "安顺","area": ["西秀区", "普定县", "平坝县", "镇宁布依族苗族自治县", "紫云苗族布依族自治县", "关岭布依族苗族自治县", "其他"]},{"name": "铜仁地区","area": ["铜仁市", "德江县", "江口县", "思南县", "石阡县", "玉屏侗族自治县", "松桃苗族自治县", "印江土家族苗族自治县", "沿河土家族自治县", "万山特区", "其他"]},{"name": "毕节地区","area": ["毕节市", "黔西县", "大方县", "织金县", "金沙县", "赫章县", "纳雍县", "威宁彝族回族苗族自治县", "其他"]},{"name": "黔西南布依族苗族自治州","area": ["兴义市", "望谟县", "兴仁县", "普安县", "册亨县", "晴隆县", "贞丰县", "安龙县", "其他"]},{"name": "黔东南苗族侗族自治州","area": ["凯里市", "施秉县", "从江县", "锦屏县", "镇远县", "麻江县", "台江县", "天柱县", "黄平县", "榕江县", "剑河县", "三穗县", "雷山县", "黎平县","岑巩县","丹寨县", "其他"]},{"name": "黔南布依族苗族自治州","area": ["都匀市", "福泉市", "贵定县", "惠水县", "罗甸县", "瓮安县", "荔波县", "龙里县", "平塘县", "长顺县", "独山县", "三都水族自治县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "云南","city": [{"name": "昆明","area": ["盘龙区", "五华区", "官渡区", "西山区", "东川区", "安宁市", "呈贡县", "晋宁县", "富民县", "宜良县", "嵩明县", "石林彝族自治县","禄劝彝族苗族自治县","寻甸回族彝族自治县", "其他"]},{"name": "曲靖","area": ["麒麟区", "宣威市", "马龙县", "沾益县", "富源县", "罗平县", "师宗县", "陆良县", "会泽县", "其他"]},{"name": "玉溪","area": ["红塔区", "江川县", "澄江县", "通海县", "华宁县", "易门县", "峨山彝族自治县", "新平彝族傣族自治县", "元江哈尼族彝族傣族自治县", "其他"]},{"name": "保山","area": ["隆阳区", "施甸县", "腾冲县", "龙陵县", "昌宁县", "其他"]},{"name": "昭通","area": ["昭阳区", "鲁甸县", "巧家县", "盐津县", "大关县", "永善县", "绥江县", "镇雄县", "彝良县", "威信县", "水富县", "其他"]},{"name": "丽江","area": ["古城区", "永胜县", "华坪县", "玉龙纳西族自治县", "宁蒗彝族自治县", "其他"]},{"name": "普洱","area": ["思茅区", "普洱哈尼族彝族自治县", "墨江哈尼族自治县", "景东彝族自治县", "景谷傣族彝族自治县", "镇沅彝族哈尼族拉祜族自治县", "江城哈尼族彝族自治县","孟连傣族拉祜族佤族自治县","澜沧拉祜族自治县", "西盟佤族自治县", "其他"]},{"name": "临沧","area": ["临翔区", "凤庆县", "云县", "永德县", "镇康县", "双江拉祜族佤族布朗族傣族自治县", "耿马傣族佤族自治县", "沧源佤族自治县", "其他"]},{"name": "德宏傣族景颇族自治州","area": ["潞西市", "瑞丽市", "梁河县", "盈江县", "陇川县", "其他"]},{"name": "怒江傈僳族自治州","area": ["泸水县", "福贡县", "贡山独龙族怒族自治县", "兰坪白族普米族自治县", "其他"]},{"name": "迪庆藏族自治州","area": ["香格里拉县", "德钦县", "维西傈僳族自治县", "其他"]},{"name": "大理白族自治州","area": ["大理市", "祥云县", "宾川县", "弥渡县", "永平县", "云龙县", "洱源县", "剑川县", "鹤庆县", "漾濞彝族自治县", "南涧彝族自治县", "巍山彝族回族自治县","其他"]},{"name": "楚雄彝族自治州","area": ["楚雄市", "双柏县", "牟定县", "南华县", "姚安县", "大姚县", "永仁县", "元谋县", "武定县", "禄丰县", "其他"]},{"name": "红河哈尼族彝族自治州","area": ["蒙自县", "个旧市", "开远市", "绿春县", "建水县", "石屏县", "弥勒县", "泸西县", "元阳县", "红河县", "金平苗族瑶族傣族自治县", "河口瑶族自治县","屏边苗族自治县","其他"]},{"name": "文山壮族苗族自治州","area": ["文山县", "砚山县", "西畴县", "麻栗坡县", "马关县", "丘北县", "广南县", "富宁县", "其他"]},{"name": "西双版纳傣族自治州","area": ["景洪市", "勐海县", "勐腊县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "西藏","city": [{"name": "拉萨","area": ["城关区", "林周县", "当雄县", "尼木县", "曲水县", "堆龙德庆县", "达孜县", "墨竹工卡县", "其他"]},{"name": "那曲地区","area": ["那曲县", "嘉黎县", "比如县", "聂荣县", "安多县", "申扎县", "索县", "班戈县", "巴青县", "尼玛县", "其他"]},{"name": "昌都地区","area": ["昌都县", "江达县", "贡觉县", "类乌齐县", "丁青县", "察雅县", "八宿县", "左贡县", "芒康县", "洛隆县", "边坝县", "其他"]},{"name": "林芝地区","area": ["林芝县", "工布江达县", "米林县", "墨脱县", "波密县", "察隅县", "朗县", "其他"]},{"name": "山南地区","area": ["乃东县", "扎囊县", "贡嘎县", "桑日县", "琼结县", "曲松县", "措美县", "洛扎县", "加查县", "隆子县", "错那县", "浪卡子县", "其他"]},{"name": "日喀则地区","area": ["日喀则市", "南木林县", "江孜县", "定日县", "萨迦县", "拉孜县", "昂仁县", "谢通门县", "白朗县", "仁布县", "康马县", "定结县", "仲巴县","亚东县","吉隆县", "聂拉木县", "萨嘎县", "岗巴县", "其他"]},{"name": "阿里地区","area": ["噶尔县", "普兰县", "札达县", "日土县", "革吉县", "改则县", "措勤县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "陕西","city": [{"name": "西安","area": ["莲湖区", "新城区", "碑林区", "雁塔区", "灞桥区", "未央区", "阎良区", "临潼区", "长安区", "高陵县", "蓝田县", "户县", "周至县", "其他"]},{"name": "铜川","area": ["耀州区", "王益区", "印台区", "宜君县", "其他"]},{"name": "宝鸡","area": ["渭滨区", "金台区", "陈仓区", "岐山县", "凤翔县", "陇县", "太白县", "麟游县", "扶风县", "千阳县", "眉县", "凤县", "其他"]},{"name": "咸阳","area": ["秦都区", "渭城区", "杨陵区", "兴平市", "礼泉县", "泾阳县", "永寿县", "三原县", "彬县", "旬邑县", "长武县", "乾县", "武功县", "淳化县","其他"]},{"name": "渭南","area": ["临渭区", "韩城市", "华阴市", "蒲城县", "潼关县", "白水县", "澄城县", "华县", "合阳县", "富平县", "大荔县", "其他"]},{"name": "延安","area": ["宝塔区", "安塞县", "洛川县", "子长县", "黄陵县", "延川县", "富县", "延长县", "甘泉县", "宜川县", "志丹县", "黄龙县", "吴起县", "其他"]},{"name": "汉中","area": ["汉台区", "留坝县", "镇巴县", "城固县", "南郑县", "洋县", "宁强县", "佛坪县", "勉县", "西乡县", "略阳县", "其他"]},{"name": "榆林","area": ["榆阳区", "清涧县", "绥德县", "神木县", "佳县", "府谷县", "子洲县", "靖边县", "横山县", "米脂县", "吴堡县", "定边县", "其他"]},{"name": "安康","area": ["汉滨区", "紫阳县", "岚皋县", "旬阳县", "镇坪县", "平利县", "石泉县", "宁陕县", "白河县", "汉阴县", "其他"]},{"name": "商洛","area": ["商州区", "镇安县", "山阳县", "洛南县", "商南县", "丹凤县", "柞水县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "甘肃","city": [{"name": "兰州","area": ["城关区", "七里河区", "西固区", "安宁区", "红古区", "永登县", "皋兰县", "榆中县", "其他"]},{"name": "嘉峪关","area": ["嘉峪关市", "其他"]},{"name": "金昌","area": ["金川区", "永昌县", "其他"]},{"name": "白银","area": ["白银区", "平川区", "靖远县", "会宁县", "景泰县", "其他"]},{"name": "天水","area": ["清水县", "秦安县", "甘谷县", "武山县", "张家川回族自治县", "北道区", "秦城区", "其他"]},{"name": "武威","area": ["凉州区", "民勤县", "古浪县", "天祝藏族自治县", "其他"]},{"name": "酒泉","area": ["肃州区", "玉门市", "敦煌市", "金塔县", "肃北蒙古族自治县", "阿克塞哈萨克族自治县", "安西县", "其他"]},{"name": "张掖","area": ["甘州区", "民乐县", "临泽县", "高台县", "山丹县", "肃南裕固族自治县", "其他"]},{"name": "庆阳","area": ["西峰区", "庆城县", "环县", "华池县", "合水县", "正宁县", "宁县", "镇原县", "其他"]},{"name": "平凉","area": ["崆峒区", "泾川县", "灵台县", "崇信县", "华亭县", "庄浪县", "静宁县", "其他"]},{"name": "定西","area": ["安定区", "通渭县", "临洮县", "漳县", "岷县", "渭源县", "陇西县", "其他"]},{"name": "陇南","area": ["武都区", "成县", "宕昌县", "康县", "文县", "西和县", "礼县", "两当县", "徽县", "其他"]},{"name": "临夏回族自治州","area": ["临夏市", "临夏县", "康乐县", "永靖县", "广河县", "和政县", "东乡族自治县", "积石山保安族东乡族撒拉族自治县", "其他"]},{"name": "甘南藏族自治州","area": ["合作市", "临潭县", "卓尼县", "舟曲县", "迭部县", "玛曲县", "碌曲县", "夏河县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "青海","city": [{"name": "西宁","area": ["城中区", "城东区", "城西区", "城北区", "湟源县", "湟中县", "大通回族土族自治县", "其他"]},{"name": "海东地区","area": ["平安县", "乐都县", "民和回族土族自治县", "互助土族自治县", "化隆回族自治县", "循化撒拉族自治县", "其他"]},{"name": "海北藏族自治州","area": ["海晏县", "祁连县", "刚察县", "门源回族自治县", "其他"]},{"name": "海南藏族自治州","area": ["共和县", "同德县", "贵德县", "兴海县", "贵南县", "其他"]},{"name": "黄南藏族自治州","area": ["同仁县", "尖扎县", "泽库县", "河南蒙古族自治县", "其他"]},{"name": "果洛藏族自治州","area": ["玛沁县", "班玛县", "甘德县", "达日县", "久治县", "玛多县", "其他"]},{"name": "玉树藏族自治州","area": ["玉树县", "杂多县", "称多县", "治多县", "囊谦县", "曲麻莱县", "其他"]},{"name": "海西蒙古族藏族自治州","area": ["德令哈市", "格尔木市", "乌兰县", "都兰县", "天峻县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "宁夏","city": [{"name": "银川","area": ["兴庆区", "西夏区", "金凤区", "灵武市", "永宁县", "贺兰县", "其他"]},{"name": "石嘴山","area": ["大武口区", "惠农区", "平罗县", "其他"]},{"name": "吴忠","area": ["利通区", "青铜峡市", "盐池县", "同心县", "其他"]},{"name": "固原","area": ["原州区", "西吉县", "隆德县", "泾源县", "彭阳县", "其他"]},{"name": "中卫","area": ["沙坡头区", "中宁县", "海原县", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "新疆","city": [{"name": "乌鲁木齐","area": ["天山区", "沙依巴克区", "新市区", "水磨沟区", "头屯河区", "达坂城区", "东山区", "乌鲁木齐县", "其他"]},{"name": "克拉玛依","area": ["克拉玛依区", "独山子区", "白碱滩区", "乌尔禾区", "其他"]},{"name": "吐鲁番地区","area": ["吐鲁番市", "托克逊县", "鄯善县", "其他"]},{"name": "哈密地区","area": ["哈密市", "伊吾县", "巴里坤哈萨克自治县", "其他"]},{"name": "和田地区","area": ["和田市", "和田县", "洛浦县", "民丰县", "皮山县", "策勒县", "于田县", "墨玉县", "其他"]},{"name": "阿克苏地区","area": ["阿克苏市", "温宿县", "沙雅县", "拜城县", "阿瓦提县", "库车县", "柯坪县", "新和县", "乌什县", "其他"]},{"name": "喀什地区","area": ["喀什市", "巴楚县", "泽普县", "伽师县", "叶城县", "岳普湖县", "疏勒县", "麦盖提县", "英吉沙县", "莎车县", "疏附县", "塔什库尔干塔吉克自治县","其他"]},{"name": "克孜勒苏柯尔克孜自治州","area": ["阿图什市", "阿合奇县", "乌恰县", "阿克陶县", "其他"]},{"name": "巴音郭楞蒙古自治州","area": ["库尔勒市", "和静县", "尉犁县", "和硕县", "且末县", "博湖县", "轮台县", "若羌县", "焉耆回族自治县", "其他"]},{"name": "昌吉回族自治州","area": ["昌吉市", "阜康市", "奇台县", "玛纳斯县", "吉木萨尔县", "呼图壁县", "木垒哈萨克自治县", "米泉市", "其他"]},{"name": "博尔塔拉蒙古自治州","area": ["博乐市", "精河县", "温泉县", "其他"]},{"name": "石河子","area": ["石河子"]},{"name": "阿拉尔","area": ["阿拉尔"]},{"name": "图木舒克","area": ["图木舒克"]},{"name": "五家渠","area": ["五家渠"]},{"name": "伊犁哈萨克自治州","area": ["伊宁市", "奎屯市", "伊宁县", "特克斯县", "尼勒克县", "昭苏县", "新源县", "霍城县", "巩留县", "察布查尔锡伯自治县", "塔城地区", "阿勒泰地区","其他"]},{"name": "其他","area": ["其他"]}]},{"name": "台湾","city": [{"name": "台湾","area": ["台北市", "高雄市", "台北县", "桃园县", "新竹县", "苗栗县", "台中县", "彰化县", "南投县", "云林县", "嘉义县", "台南县", "高雄县", "屏东县","宜兰县","花莲县", "台东县", "澎湖县", "基隆市", "新竹市", "台中市", "嘉义市", "台南市", "其他"]},{"name": "其他","area": ["其他"]}]},{"name": "澳门","city": [{"name": "澳门","area": ["花地玛堂区", "圣安多尼堂区", "大堂区", "望德堂区", "风顺堂区", "嘉模堂区", "圣方济各堂区", "路凼", "其他"]}]},{"name": "香港","city": [{"name": "香港","area": ["中西区", "湾仔区", "东区", "南区", "深水埗区", "油尖旺区", "九龙城区", "黄大仙区", "观塘区", "北区", "大埔区", "沙田区", "西贡区", "元朗区","屯门区","荃湾区", "葵青区", "离岛区", "其他"]}]},{"name": "钓鱼岛","city": [{"name": "钓鱼岛","area": ["钓鱼岛"]}]}]

解决Vue3的H5端使用onShow加载数据报错的问题

错误信息:

Cannot destructure property 'firstElementChild' of 'rootRef.value' as it is null.

解决:

使用setTimeout延迟加载数据,代码如下:

onShow(() => {
  setTimeout(() => { // 解决h5端返回首页加载关注列表报错的问题
    getFollowDevices()
  }, 10)
})

uni-datetime-picker

1.vue3项目中设置输入框当前值要使用:model-value,不能使用:value。

2.实现点击某日期选中一整周(需要修改组件源码)

<view class="vertical-center">
  <uni-datetime-picker
    :ref="getWeekPickerRef"
    type="daterange"
    date-separator="."
    :start="min"
    :end="Date.now()"
    :clear-icon="false"
    :border="false"
    v-model="weekRange"
    @click="handleClick"
    @change="weekChange"
  />
  &nbsp;<uni-icons type="bottom" size="16" color="#091622" @click="openWeekPicer"></uni-icons>
</view>

import { ref, watch } from 'vue'
import util from '@/utils/util.js'

/**
 * 接收父组件传参
 */
const props = defineProps({
  // 开始
  modelValue: {
    type: [String, Number],
    default: ''
  },
  // 结束
  end: {
    type: [String, Number],
    default: ''
  },
  // 最小日期
  min: {
    type: String,
    default: '2019-01-01'
  }
})

/**
 * 按周业务
 */
const weekRange = ref([props.modelValue, props.end])
const weekPicker = ref(null)

const getWeekPickerRef = e => weekPicker.value = e

const openWeekPicer = () => weekPicker.value.show()

watch(() => [props.modelValue, props.end], () => weekRange.value = [props.modelValue, props.end])

const handleClick = date => {
  if (typeof date === 'string') { // 解决点击事件重复触发的问题
    const weekStart = util.getWeekFirst({format: 'yyyy-MM-dd', date: new Date(date)})
    const weekEnd = util.getWeekLast({format: 'yyyy-MM-dd', date: new Date(date)})
    weekRange.value = [weekStart, weekEnd]
  }
}

/**
 * 事件处理
 */
const emit = defineEmits(['update:modelValue', 'update:end', 'change'])

const toast = (title, duration = 1500) => {
  if (!title) {
    return
  }
  uni.showToast({
    title,
    icon: 'none',
    duration
  })
}

const weekChange = ([weekStart, weekEnd]) => {
  emit('update:modelValue', weekStart)
  emit('update:end', weekEnd)
  emit('change', { start: weekStart, end: weekEnd })
}

// util.js
export default {
  // 日期格式化
  formatDate({date = new Date(), format = 'yyyy/MM/dd hh:mm:ss'} = {}) {
    if (date !== 'Invalid Date') {
      const o = {
        'M+': date.getMonth() + 1, // month
        'd+': date.getDate(), // day
        'h+': date.getHours(), // hour
        'm+': date.getMinutes(), // minute
        's+': date.getSeconds(), // second
        'q+': Math.floor((date.getMonth() + 3) / 3), // quarter
        'S': date.getMilliseconds() // millisecond
      }
      if (/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
      }
      for (let k in o) {
        if (new RegExp('(' + k + ')').test(format)) {
          format = format.replace(RegExp.$1,RegExp.$1.length == 1 ? o[k] :('00' + o[k]).substr(('' + o[k]).length))
        }
      }
      return format
    }
    return ''
  },
  // 获取指定日期所在周的周一日期
  getWeekFirst({date = new Date(), format = 'yyyy/MM/dd hh:mm:ss'} = {}) {
    let day = date.getDay()
    if (day === 1) { // 若是周一直接返回格式化日期
      return this.formatDate({date, format})
    }
    if (!day) {
      day = 7
    }
    const millisecondDiff = (day - 1) * 24 * 60 * 60 * 1000 // 周一距离当前日期的毫秒数
    return this.formatDate({date: new Date(date.getTime() - millisecondDiff), format})
  },
  // 获取指定日期所在周的周日日期
  getWeekLast({date = new Date(), format = 'yyyy/MM/dd hh:mm:ss'} = {}) {
    const day = date.getDay()
    if (day === 7) { // 若是周日直接返回格式化日期
      return this.formatDate({date, format})
    }
    const millisecondDiff = (7 - day) * 24 * 60 * 60 * 1000 // 周日距离当前日期的毫秒数
    return this.formatDate({date: new Date(date.getTime() + millisecondDiff), format})
  }
}

/* 修改组件默认样式 */
:deep(.uni-date__x-input),
:deep(.range-separator) {
  height: auto;
  font-size: 32rpx;
  color: #091622;
  line-height: 1.1;
}
:deep(.uni-date),
:deep(.uni-date__x-input) {
  flex: 0 1 58%;
}
:deep(.uni-date-x) {
  justify-content: flex-start;
}
:deep(.icon-calendar) {
  display: none;
}
:deep(.uni-calendar-item__weeks-box .uni-calendar-item--checked) {
  border: none;
  background-color: #f6f7fc;
  .uni-calendar-item--checked-text {
    color: #333;
  }
}

修改组件源码:

// uni_modules\uni-datetime-picker\components\uni-datetime-picker\calendar.vue
// 找到change函数,添加一行代码
/**
 * 变化触发
 */
change() {
  this.setEmit('date-click') // 添加的代码
  if (!this.insert) return
  this.setEmit('change')
},

<!-- uni_modules\uni-datetime-picker\components\uni-datetime-picker\uni-datetime-picker.vue -->
<!-- 找到displayRangeValue.startDate,将该行代码修改如下: -->
<view class="uni-date__x-input text-center">
  {{ dateSeparator && displayRangeValue.startDate ? displayRangeValue.startDate.replace(/-/g, dateSeparator) : (displayRangeValue.startDate || startPlaceholderText) }}
</view>

<!-- 找到displayRangeValue.endDate,将该行代码修改如下: -->
<view class="uni-date__x-input text-center">
  {{ dateSeparator && displayRangeValue.endDate ? displayRangeValue.endDate.replace(/-/g, dateSeparator) : (displayRangeValue.endDate || endPlaceholderText) }}
</view>

<!-- 找到ref="mobile"对应的Calendar组件,增加date-click事件监听: -->
@date-click="handleClick"

// uni_modules\uni-datetime-picker\components\uni-datetime-picker\uni-datetime-picker.vue
// props增加一个属性:
dateSeparator: {
  type: String,
  default: ''
},

// methods中增加一个函数:
handleClick(e) {
  if (this.type === 'daterange' && e.fulldate) {
    this.$emit('click', e.fulldate)
  }
},

微信分享

1.实现分享位置信息到微信后,用户点击分享链接可以打开高德地图显示位置及导航的功能

<uni-popup ref="sharePopup" type="bottom">
  <view class="share-popup">
    <view class="both-center medium-font share-title">分享位置至</view>
    <view class="uni-flex share-list">
      <view class="share-list-item" v-for="item in shareList" :key="item.id" @tap="share(item.id)">
        <view class="both-center list-item-icon" :style="{background: item.bgc}">
          <view :class="item.prefix + ' ' + item.icon" v-if="item.prefix === 't-icon'"></view>
          <uni-icons :custom-prefix="item.prefix" :type="item.icon" size="24" :color="item.color" v-else></uni-icons>
        </view>
        <text class="list-item-label">{{ item.name }}</text>
      </view>
    </view>
  </view>
</uni-popup>
/* 微信分享 */
const sharePopup = ref(null)
const shareList = [
  {
    name: '微信好友',
    id: 'WXSceneSession',
    prefix: '',
    icon: 'weixin',
    color: '#fff',
    bgc: '#50b674'
  },
  {
    name: '朋友圈',
    id: 'WXSceneTimeline',
    prefix: 't-icon',
    icon: 't-icon-friends',
    bgc: '#fff'
  }
]

// 显示分享弹窗
const handleShare = () => sharePopup.value.open()

// 分享
const share = scene => uni.share({
  provider: 'weixin',
  scene,
  type: 0,
  href: `https://uri.amap.com/marker?position=${gpsInfo.value.lngenc},${gpsInfo.value.latenc}`, // 调用高德URI API实现设备位置信息展示
  title: props.data.vincode,
  summary: gpsInfo.value.location,
  imageUrl: vehicleImage.getVehicleImage(props.data.productname),
  success: res => toast('分享成功'),
  fail: err => toast('分享失败')
})

解决APP启动失败的问题

1.安卓自定义基座包真机调试启动后在启动界面停留几秒后自动退出

原因:启动图使用的图片格式或大小不符合要求。

解决:更换启动图图片,一定要是.png格式,强烈推荐使用.9.png图片(Android平台启动图使用.9.png图片 - DCloud问答),并在保证清晰度的基础上图片尽量小一些。

composable封装

1.useRequest.js 接口请求组合式函数

// 接口请求组合式函数
export default () => {
  // #ifdef APP-PLUS
  const interfaceUrl = 'http://xx.xx.xx.xx:8080/' // 正式服务
  // #endif
  // #ifdef H5
  const interfaceUrl = '/' // 正式服务 // 用于本地nginx
  // #endif
  const uploadPath = interfaceUrl + 'upload/file'
  const prefix = 'lk-'

  const toast = (title, duration = 1500) => {
    if (!title) {
      return
    }
    uni.showToast({
      title,
      icon: 'none',
      duration
    })
  }
  
  const setToken = token => uni.setStorageSync(prefix + 'token', token)
  
  const getToken = () => uni.getStorageSync(prefix + 'token')
  
  // 清除缓存
  const clearCache = () => {
    uni.removeStorageSync(prefix + 'token')
    uni.removeStorageSync(prefix + 'user')
  }

  const request = ({
    url,
    data = null,
    method = 'GET',
    loading = false,
    type = false,
    needToken = true,
    responseType = null,
    loadText = '请稍候...'
  }) => {
    if (loading) {
      uni.showLoading({
        mask: true,
        title: loadText
      })
    }
    return new Promise((resolve, reject) => uni.request({
      url: url.indexOf('http') >= 0 ? url : interfaceUrl + url,
      data,
      header: {
        'content-type': type ? 'application/x-www-form-urlencoded' : 'application/json',
        token: needToken ? getToken() : '' // 使用token
      },
      method, // 请求方式
      dataType: 'json',
      responseType,
      success: res => {
        loading && uni.hideLoading()
        const d = res.data
        if (typeof d === 'boolean' || (d.errorCode == -1 && d.success) || Object.prototype.toString.call(d) === '[object ArrayBuffer]') {
          resolve(d)
        } else if (d.code == 401) {
          reject(d)
          toast(d.msg)
          setTimeout(() => {
            uni.navigateTo({
              url: '/pages/login/login'
            })
          }, 500)
        } else {
          reject(d)
          if (d.msg) {
            toast(d.msg === 'Bad credentials' ? '用户名或密码错误' : d.msg, 2500)
          }
        }
      },
      fail: err => {
        if (loading) {
          uni.hideLoading()
          toast('网络不给力,请稍后再试')
        }
        reject(err)
      }
    }))
  }

  return {
    interfaceUrl,
    uploadPath,
    setToken,
    getToken,
    clearCache,
    request,
    toast
  }
}

使用:

import useRequest from '@/composables/useRequest.js' // 接口请求工具

const { request, toast } = useRequest()

// 取消关注
const handleFollow = id => request({
  url: 'cancelFollow',
  method: 'POST',
  data: {
    starStatus: 0,
    id
  }
}).then(() => {
  toast('取消关注成功')
})

2.useDict.js 字典项处理组合式函数

import { ref } from 'vue'

// 字典项处理组合式函数
export default opts => {
  const {
    request, // 请求函数
    form = {}, // 表单对象
    dicList = [] // 字典项字段列表
  } = opts

  const dictionary = ref({ // 字典项
    role: [
      {
        label: '机主',
        value: 0
      },
      {
        label: '机手',
        value: 1
      },
      {
        label: '设备管理',
        value: 2
      }
    ]
  })

  // 获取服务器字典项数据并与本地字典项数据合并
  const getRemoteDics = () => {
    if (!dicList || !dicList.length) {
      return
    }
    const len = dicList.length
    const promiseList = new Array(len)
    for (let i = 0; i < len; i++) {
      promiseList[i] = request({
        url: 'sys/dict/getDictValueByType',
        data: {
          type: dicList[i]
        }
      })
    }
    Promise.all(promiseList).then(resList => {
      for (let i = 0; i < resList.length; i++) {
        dictionary.value[dicList[i]] = []
        const dicInfo = resList[i].body.list
        for (let key in dicInfo) {
          dictionary.value[dicList[i]].push({
            label: dicInfo[key],
            value: +key
          })
        }
      }
    }).catch(err => {
      console.log(err)
      handleError()
    })
  }

  const handleError = () => {
    for (let i = 0; i < dicList.length; i++) {
      dictionary.value[dicList[i]] = []
    }
  }

  // 根据字典的value显示label
  const findByvalue = (dic, value) => {
    let result = ''
    if (!dic) return value
    if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
      let index = 0
      index = findArray(dic, value)
      result = index !== -1 ? dic[index].label : ''
    } else if (value instanceof Array) {
      result = []
      let index = 0
      value.forEach(ele => {
        index = findArray(dic, ele)
        result.push(index !== -1 ? dic[index].label : '')
      })
      result = result.toString()
    }
    return result
  }

  // 选中字典项
  const dictionaryChange = (index, formKey, dicKey = formKey) => {
    if (typeof formKey === 'string') {
      form[formKey] = dictionary.value[dicKey][index].value
    } else {
      formKey(dictionary.value[dicKey][index].value)
    }
  }

  // 据字典的value查找对应的index
  const findArray = (dic, value) => {
    for (let i = 0; i < dic.length; i++) {
      if (dic[i].value == value) {
        return i
      }
    }
    return -1
  }

  return {
    dictionary,
    findByvalue,
    dictionaryChange,
    getRemoteDics
  }
}

使用:

<picker
  range-key="label"
  :range="dictionary[dictKey]"
  @change="e => {dictionaryChange(e.detail.value, 'feedbackType', dictKey)}"
>
  <view class="between-center form-item">
    <view class="no-shrink item-lable">反馈类型</view>
    <view class="vertical-center flex-auto" :class="{'holder-text': form.feedbackType == null}">
      {{ findByvalue(dictionary[dictKey], form.feedbackType) || '请选择' }}
    </view>
    <uni-icons type="forward" size="20" color="#506f8c"></uni-icons>
  </view>
</picker>
import useRequest from '@/composables/useRequest.js' // 接口请求工具
import useDict from '@/composables/useDict.js' // 字典项工具

/**
 * 字典项业务
 */
const { request, toast } = useRequest()
const dictKey = 'feedback_type'
const { dictionary, findByvalue, dictionaryChange, getRemoteDics } = useDict({form, request, dicList: [dictKey]})

getRemoteDics()

3.useGeocoder.js 逆地理解析组合式函数

/**
 * 逆地理解析组合式函数
 */
export default () => {
  // 解析单条数据
  const analysis = async (lng, lat) => {
    if (lng > 0 && lat > 0) {
      let location = ''
      // #ifdef APP-PLUS
      location = await reverseGeoApp(lng, lat)
      // #endif
      // #ifdef H5
      location = await reverseGeoH5(lng, lat)
      // #endif
      return location
    }
    return ''
  }

  // 解析列表数据
  const analysisList = async ({list, lng = 'lng', lat = 'lat', lngFun, latFun}) => {
    for (let i = 0; i < list.length; i++) {
      const item = list[i]
      if (item.location && item.location !== '地理位置解析失败') {
        continue
      }
      const longitude = lngFun ? +lngFun(item) : +item[lng]
      const latitude = latFun ? +latFun(item) : +item[lat]
      if ((!longitude || !latitude) && !item.location) {
        item.location = '地理位置解析失败'
        continue
      }
      // #ifdef APP-PLUS
      item.location = await reverseGeoApp(longitude, latitude)
      // #endif
      // #ifdef H5
      item.location = await reverseGeoH5(longitude, latitude)
      // #endif
    }
  }

  // APP-VUE逆地理解析
  const reverseGeoApp = (longitude, latitude) => {
    const point = new plus.maps.Point(longitude, latitude)
    return new Promise(resolve => {
      plus.maps.Map.reverseGeocode(point, {}, res => resolve(res.address), () => resolve('地理位置解析失败'))
    })
  }

  // H5逆地理解析
  const reverseGeoH5 = (lng, lat) => new Promise(resolve => {
    uni.request({
      url: 'https://restapi.amap.com/v3/geocode/regeo',
      data: {
        key: '高德key',
        location: lng + ',' + lat
      },
      dataType: 'json',
      method: 'GET',
      success: result => {
        const res = result.data;
        if (res.status == 1) {
          const address = res.regeocode.formatted_address
          resolve(address && address.length ? address : '地理位置解析失败')
        } else {
          resolve('地理位置解析失败')
        }
      },
      fail: () => resolve('地理位置解析失败')
    })
  })

  return {
    analysis,
    analysisList,
    reverseGeoH5
  }
}

使用:

import useGeocoder from '@/composables/useGeocoder.js' // 逆地理解析工具

/* 逆地理解析 */
const { reverseGeoH5 } = useGeocoder()
const location = ref('')

reverseGeoH5(lng, lat).then(res => {
  location.value = res
})

4.usePage.js 列表页面分页查询处理组合式函数

// 列表页面分页查询处理组合式函数
import { ref } from 'vue'
import { onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'

export default opts => {
  let {
    url,
    request,
    params = {},
    pageSize = 10,
    loading = false,
    method = 'get',
    listKey = 'list', // 数据列表字段名
    totalKey = 'count', // 数据总数字段名
    onRefresh = true,
    refreshFun, // 刷新函数,一般用于重置筛选条件
    resolveResource, // 处理数据源函数
    afterFun // 处理请求后的数据函数,一般用于异步数据处理
  } = opts

  let pageNo = 1
  const list = ref([])
  const status = ref('loading')

  // 分页查询
  const loadData = () => request({
    url,
    data: {
      pageSize,
      pageNo,
      ...params
    },
    method,
    loading
  }).then(({body}) => {
    const res = resolveResource ? resolveResource(body) : body[listKey]
    if (res.length) {
      list.value = [...list.value, ...res]
      if (afterFun) {
        afterFun(list.value)
      }
      if (list.value.length >= body[totalKey]) {
        status.value = 'noMore'
      } else {
        pageNo++
        status.value = 'more'
      }
    } else {
      status.value = 'noMore'
    }
  }).catch(err => {
    console.error(err)
    status.value = 'more'
  })

  // 更新查询接口
  const updateUrl = newUrl => url = newUrl

  const refresh = () => {
    status.value = 'loading'
    pageNo = 1
    list.value = []
    if (refreshFun) {
      refreshFun()
    }
    loadData()
  }

  onPullDownRefresh(() => {
    if (!onRefresh) {
      return
    }
    refresh()
    setTimeout(() => {
      uni.stopPullDownRefresh()
    }, 1000)
  })

  onReachBottom(() => {
    if (status.value === 'more') {
      status.value = 'loading'
      loadData()
    }
  })

  return {
    loadData,
    list,
    refresh,
    status,
    updateUrl
  }
}

使用:

import { onLoad } from '@dcloudio/uni-app'
import useRequest from '@/composables/useRequest.js' // 接口请求工具
import usePage from '@/composables/usePage.js' // 分页查询工具

/**
 * 获取页面传参业务
 */
let lastList = [] // 上次选中的设备编号列表
let from = '' // 页面跳转标识,用于返回选中后返回上一页面的业务处理
const params = {}

onLoad(param => {
  lastList = param.list || []
  from = param.from
  params.detailStatus = param.detailStatus
  if (param.detailStatus) {
    params.pageSize = 1000
  } else {
    params.deptId = param.deptId
  }
  if (param.url) {
    updateUrl(param.url) // 更新查询接口
  }
  loadData()
})

/**
 * 查询业务
 */
const { request, toast } = useRequest()

const {
  loadData,
  status,
  list,
  updateUrl
} = usePage({
  url: 'getList',
  request,
  resolveResource: ({list}) => { // 默认选中上次选中的设备
    uni.showLoading({
      mask: true,
      title: '请稍候...'
    })
    selectList.value = []
    for (let i = 0; i < list.length; i++) {
      if (lastList.includes(list[i].dbdVehicle.vincode)) {
        selectList.value.push(list[i])
      }
    }
    uni.hideLoading()
    return list
  },
  params
})

5.useTabPage.js 标签栏页面业务处理组合式函数

// 标签栏页面业务处理组合式函数
import { computed, ref, reactive, nextTick } from 'vue'
import { onPullDownRefresh, onReachBottom, onPageScroll } from '@dcloudio/uni-app'

export default opts => {
  const {
    tabs,
    loadData,
    status,
    isRefresh = true // 是否开启刷新
  } = opts

  const tabList = reactive(tabs.map(tab => {
    tab.getRef = e => pageRefs.includes(e) || pageRefs.push(e)
    tab.scrollTop = 0
    return tab
  }))
  const tabName = ref(tabList[0].name)
  const components = ref([tabList[0]])
  const tabIndex = computed(() => {
    for (let i = 0; i < tabList.length; i++) {
      if (tabList[i].name === tabName.value) {
        return i
      }
    }
    return 0
  })

  const tabChange = tab => {
    if (tab.name === tabName.value) {
      return
    }
    tabName.value = tab.name
    if (!components.value.includes(tab)) {
      components.value.push(tab)
    }
    nextTick(() => uni.pageScrollTo({
      scrollTop: tabList[tabIndex.value].scrollTop,
      duration: 0
    }))
  }

  /**
   * 下拉刷新业务
   */
  const pageRefs = []

  const refresh = () => {
    for (let i = 0; i < pageRefs.length; i++) {
      if (pageRefs[i].name === tabName.value) {
        if (pageRefs[i].refresh) {
          pageRefs[i].refresh()
        }
        break
      }
    }
  }

  onPullDownRefresh(() => {
    if (!isRefresh) {
      return
    }
    refresh()
    setTimeout(() => {
      uni.stopPullDownRefresh()
    }, 1000)
  })

  /**
   * 开启上拉加载
   */
  onReachBottom(() => {})

  /**
   * 页面滚动业务
   */
  onPageScroll(e => tabList[tabIndex.value].scrollTop = e.scrollTop)

  return {
    tabList,
    tabName,
    components,
    refresh,
    tabChange
  }
}

使用:

<view class="both-center tab-box">
  <lk-tab-list :tab-list="tabList" :model-value="tabName" @change="({tab}) => tabChange(tab)"></lk-tab-list>
</view>
<!-- 标签页-->
<component
  :ref="page.getRef"
  v-for="page in components"
  :key="page.name"
  :is="page.component"
  v-show="page.name === tabName"
/>
import { markRaw } from 'vue'
import useTabPage from '@/composables/useTabPage.js' // 标签栏页面业务处理工具
import currentAlarm from './current.vue'
import historyAlarm from './history.vue'

/**
 * tab页业务
 */
const tabs = [
  {
    name: '当前',
    component: markRaw(currentAlarm)
  },
  {
    name: '历史',
    component: markRaw(historyAlarm)
  }
]

const { tabList, tabName, components, tabChange, refresh } = useTabPage({ tabs, isRefresh: false })

6.useVersion.js 版本更新业务处理

import { ref } from 'vue'

/**
 * 版本更新业务处理
 * @description 接收一个 opts 参数,返回列表所需数据
 * @param {String} opts.updateUrl - 查询最新版本信息接口
 */
export default opts => {
  const { request, toast, updateUrl } = opts
  const isAndroid = plus.os.name === 'Android'
  const version = ref({})
  const currrentVersion = ref('')
  const isLastVersion = ref(true)

  // 检测新版本
  const getNewVersion = showModal => request({ url: updateUrl, deviceType: isAndroid ? 1 : 2 }).then(({ body }) => {
    const res = body.data
    plus.runtime.getProperty(plus.runtime.appid, wgtinfo => {
      const wgtVersion = wgtinfo.version
      currrentVersion.value = wgtVersion
      version.value = res
      if (wgtVersion === res.version) {
        if (latestVersionTip) {
          toast('已是最新版本')
        }
        return
      }
      let hasNewVersion = false
      const localVersion = wgtVersion.split('.') // 当前版本号
      const serviceVersion = res.version.split('.') // 最新版本号
      for (let i = 0; i < serviceVersion.length; i++) { // 比较每个版本号大小,只要不相等就一定会比较出结果
        if (+serviceVersion[i] > +localVersion[i]) {
          hasNewVersion = true
          break
        } else if (+serviceVersion[i] < +localVersion[i]) {
          hasNewVersion = false
          break
        }
      }
      if (hasNewVersion) {
        isLastVersion.value = false
        if (!showModal) {
          return
        }
        uni.showModal({
          title: '系统检测到有新版本发布,是否更新?',
          confirmText: '确定更新',
          content: res.remark,
          success: result => {
            if (result.confirm) {
              if (isAndroid) { // 安卓系统下载新版本安装包
                confirmDownload(res.url)
              } else { // iOS系统打开AppStore对应页面
                plus.runtime.openURL(encodeURI(res.url), () => toast('自动跳转AppStore失败,请手动打开AppStore更新版本', 3000))
              }
            } else if (result.cancel && res.isForceUpdates == 1) { // 强制更新
              if (isAndroid) {
                plus.runtime.quit() // 退出应用
              } else { // iOS只能通过手机物理键退出应用,无法通过代码退出应用,所以只能跳转登录页面
                uni.redirectTo({
                  url: '/pages/login/login'
                })
              }
            }
          }
        })
      } else {
        if (latestVersionTip) {
          toast('已是最新版本')
        }
      }
    })
  })

  // 版本更新
  const confirmDownload = url => {
    uni.showLoading({
      mask: true,
      title: '更新中...'
    })
    const dtask = plus.downloader.createDownload(url, {
      method: 'GET',
      filename: '_doc/update/xcmg-zhulu.apk'
    }, (downloadResult, status) => {
      uni.hideLoading()
      if (status === 200) {
        plus.runtime.install(downloadResult.filename, {
          force: false
        }, () => {
          plus.downloader.clear() // 清除下载任务
          if (downloadResult.filename.indexOf('.wgt') > 0) {
            plus.runtime.restart()
          } else {
            plus.runtime.quit()
          }
        }, () => {
          toast('安装失败')
          plus.downloader.clear() // 清除下载任务
        })  
      } else {
        toast('下载失败')
        plus.downloader.clear() // 清除下载任务
      }
    })
    dtask.start()
  }

  return {
    getNewVersion,
    version,
    currrentVersion,
    isLastVersion
  }
}

使用:

// #ifdef APP-PLUS
import useRequest from '@/composables/useRequest.js' // 接口请求工具
import useVersion from '@/composables/useVersion.js' // 版本更新工具

const { request, toast } = useRequest()
const { getNewVersion } = useVersion({ request, toast, updateUrl: 'APPInfo' })

getNewVersion()
// #endif

7.useImage.js 图片处理组合式函数

import { ref } from 'vue'
// #ifdef APP-PLUS
import permision from '@/utils/permission.js'
// #endif
import { pathToBase64 } from '@/js_sdk/mmmm-image-tools/index.js' // 图片路径与base64互转工具,可以在DCloud插件市场找到

/**
 * 图片处理组合式函数
 * defaultImg: String 默认图片路径
 * limit: Number 图片数量上限
 * changeFun: Function 图片选择成功后的回调函数
 * crop: Object 图片裁剪参数
 */
export default opts => {
  const {
    defaultImg = '/static/img/error/img-default.png',
    limit = 12,
    changeFun,
    crop
  } = opts || {}

  /**
   * 图片加载失败业务
   */
  // 图片加载失败时显示默认图片
  const handleImgError = (item, key, img) => item[key] = img || defaultImg

  /**
   * 图片上传业务
   */
  const imageList = ref([]) // 图片列表

  // 从相册中选择图片或拍照并压缩后转base64
  const chooseToBase64 = () => uni.chooseImage({
    sizeType: ['compressed'], // original 原图,compressed 压缩图(压缩50%左右),默认二者都有
    count: limit,
    crop,
    success: ({tempFilePaths}) => {
      uni.showLoading({
        mask: true,
        title: '请稍候...'
      })
      const promiseList = []
      for (let i = 0; i < tempFilePaths.length; i++) {
        promiseList.push(new Promise(resolve => uni.getImageInfo({ // 获取图片的本地存储路径
          src: tempFilePaths[i],
          success: result => {
            pathToBase64(result.path).then(base64 => {
              resolve(base64)
            })
          }
        })))
      }
      Promise.all(promiseList).then(resList => {
        uni.hideLoading()
        if (changeFun) {
          changeFun(resList)
        }
        imageList.value = resList
      }).catch(errMsg => {
        uni.hideLoading()
        console.error(errMsg)
      })
    },
    fail: err => {
      console.error(err)
      // #ifdef APP-PLUS
      if (err.code && err.code !== 0) {
        checkPermission(err.code)
      }
      // #endif
    }
  })

  // 检查权限,并引导开启浏览相册权限和相机
  const checkPermission = async code => {
    const type = code ? code - 1 : 2
    let status = null
    if (permision.isIOS) {
      status = permision.judgeIosPermissionCamera() && permision.judgeIosPermissionPhotoLibrary()
    } else {
      status =  await permision.requestAndroidPermission(type === 0 ? 'android.permission.CAMERA' :'android.permission.READ_EXTERNAL_STORAGE')
    }
    if (status === null) {
      return 1;
    } else if (status != 1) {
      uni.showModal({
        content: '当前操作需要您的授权',
        confirmText: '是否去设置?',
        success: res => {
          if (res.confirm) {
            permision.gotoAppSetting()
          }
        }
      });
    }
    return status
  }

  return {
    defaultImg,
    handleImgError,
    chooseToBase64,
    imageList
  }
}
/**
 * permission.js
 * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
 */
let isIos
// #ifdef APP-PLUS
isIos = (plus.os.name == "iOS")
// #endif

// 判断推送权限是否开启
function judgeIosPermissionPush() {
  var result = false;
  var UIApplication = plus.ios.import("UIApplication");
  var app = UIApplication.sharedApplication();
  var enabledTypes = 0;
  if (app.currentUserNotificationSettings) {
    var settings = app.currentUserNotificationSettings();
    enabledTypes = settings.plusGetAttribute("types");
    console.log("enabledTypes1:" + enabledTypes);
    if (enabledTypes == 0) {
      console.log("推送权限没有开启");
    } else {
      result = true;
      console.log("已经开启推送功能!")
    }
    plus.ios.deleteObject(settings);
  } else {
    enabledTypes = app.enabledRemoteNotificationTypes();
    if (enabledTypes == 0) {
      console.log("推送权限没有开启!");
    } else {
      result = true;
      console.log("已经开启推送功能!")
    }
    console.log("enabledTypes2:" + enabledTypes);
  }
  plus.ios.deleteObject(app);
  plus.ios.deleteObject(UIApplication);
  return result;
}

// 判断定位权限是否开启
function judgeIosPermissionLocation() {
  var result = false;
  var cllocationManger = plus.ios.import("CLLocationManager");
  var status = cllocationManger.authorizationStatus();
  result = (status != 2)
  console.log("定位权限开启:" + result);
  // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
  /* var enable = cllocationManger.locationServicesEnabled();
  var status = cllocationManger.authorizationStatus();
  console.log("enable:" + enable);
  console.log("status:" + status);
  if (enable && status != 2) {
  	result = true;
  	console.log("手机定位服务已开启且已授予定位权限");
  } else {
  	console.log("手机系统的定位没有打开或未给予定位权限");
  } */
  plus.ios.deleteObject(cllocationManger);
  return result;
}

// 判断麦克风权限是否开启
function judgeIosPermissionRecord() {
  var result = false;
  var avaudiosession = plus.ios.import("AVAudioSession");
  var avaudio = avaudiosession.sharedInstance();
  var permissionStatus = avaudio.recordPermission();
  console.log("permissionStatus:" + permissionStatus);
  if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
    console.log("麦克风权限没有开启");
  } else {
    result = true;
    console.log("麦克风权限已经开启");
  }
  plus.ios.deleteObject(avaudiosession);
  return result;
}

// 判断相机权限是否开启
function judgeIosPermissionCamera() {
  var result = false;
  var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
  var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
  if (authStatus == 3) { // 相机权限已经开启
    result = true;
  }
  plus.ios.deleteObject(AVCaptureDevice);
  return result; // 相机权限没有开启
}

// ios判断相册权限是否开启
function judgeIosPermissionPhotoLibrary() {
  var result = false;
  var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
  var authStatus = PHPhotoLibrary.authorizationStatus();
  if (authStatus == 3) { // 相册权限已经开启
    result = true;
  }
  plus.ios.deleteObject(PHPhotoLibrary);
  return result; // 相册权限没有开启
}

// 判断通讯录权限是否开启
function judgeIosPermissionContact() {
  var result = false;
  var CNContactStore = plus.ios.import("CNContactStore");
  var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
  if (cnAuthStatus == 3) {
    result = true;
    console.log("通讯录权限已经开启");
  } else {
    console.log("通讯录权限没有开启");
  }
  plus.ios.deleteObject(CNContactStore);
  return result;
}

// 判断日历权限是否开启
function judgeIosPermissionCalendar() {
  var result = false;
  var EKEventStore = plus.ios.import("EKEventStore");
  var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
  if (ekAuthStatus == 3) {
    result = true;
    console.log("日历权限已经开启");
  } else {
    console.log("日历权限没有开启");
  }
  plus.ios.deleteObject(EKEventStore);
  return result;
}

// 判断备忘录权限是否开启
function judgeIosPermissionMemo() {
  var result = false;
  var EKEventStore = plus.ios.import("EKEventStore");
  var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
  if (ekAuthStatus == 3) {
    result = true;
    console.log("备忘录权限已经开启");
  } else {
    console.log("备忘录权限没有开启");
  }
  plus.ios.deleteObject(EKEventStore);
  return result;
}

// Android权限查询
function requestAndroidPermission(permissionID) {
  return new Promise((resolve, reject) => {
    plus.android.requestPermissions(
      [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
      function(resultObj) {
        var result = 0;
        for (var i = 0; i < resultObj.granted.length; i++) {
          var grantedPermission = resultObj.granted[i];
          console.log('已获取的权限:' + grantedPermission);
          result = 1
        }
        for (var i = 0; i < resultObj.deniedPresent.length; i++) {
          var deniedPresentPermission = resultObj.deniedPresent[i];
          console.log('拒绝本次申请的权限:' + deniedPresentPermission);
          result = 0
        }
        for (var i = 0; i < resultObj.deniedAlways.length; i++) {
          var deniedAlwaysPermission = resultObj.deniedAlways[i];
          console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
          result = -1
        }
        resolve(result);
        // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
        // if (result != 1) {
        // gotoAppPermissionSetting()
        // }
      },
      function(error) {
        console.log('申请权限错误:' + error.code + " = " + error.message);
        resolve({
          code: error.code,
          message: error.message
        });
      }
    );
  });
}

// 使用一个方法,根据参数判断权限
function judgeIosPermission(permissionID) {
  if (permissionID == "location") {
    return judgeIosPermissionLocation()
  } else if (permissionID == "camera") {
    return judgeIosPermissionCamera()
  } else if (permissionID == "photoLibrary") {
    return judgeIosPermissionPhotoLibrary()
  } else if (permissionID == "record") {
    return judgeIosPermissionRecord()
  } else if (permissionID == "push") {
    return judgeIosPermissionPush()
  } else if (permissionID == "contact") {
    return judgeIosPermissionContact()
  } else if (permissionID == "calendar") {
    return judgeIosPermissionCalendar()
  } else if (permissionID == "memo") {
    return judgeIosPermissionMemo()
  }
  return false;
}

// 跳转到**应用**的权限页面
function gotoAppPermissionSetting() {
  if (isIos) {
    var UIApplication = plus.ios.import("UIApplication");
    var application2 = UIApplication.sharedApplication();
    var NSURL2 = plus.ios.import("NSURL");
    // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");		
    var setting2 = NSURL2.URLWithString("app-settings:");
    application2.openURL(setting2);

    plus.ios.deleteObject(setting2);
    plus.ios.deleteObject(NSURL2);
    plus.ios.deleteObject(application2);
  } else {
    // console.log(plus.device.vendor);
    var Intent = plus.android.importClass("android.content.Intent");
    var Settings = plus.android.importClass("android.provider.Settings");
    var Uri = plus.android.importClass("android.net.Uri");
    var mainActivity = plus.android.runtimeMainActivity();
    var intent = new Intent();
    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
    intent.setData(uri);
    mainActivity.startActivity(intent);
  }
}

// 检查系统的设备服务是否开启
// var checkSystemEnableLocation = async function () {
function checkSystemEnableLocation() {
  if (isIos) {
    var result = false;
    var cllocationManger = plus.ios.import("CLLocationManager");
    var result = cllocationManger.locationServicesEnabled();
    console.log("系统定位开启:" + result);
    plus.ios.deleteObject(cllocationManger);
    return result;
  } else {
    var context = plus.android.importClass("android.content.Context");
    var locationManager = plus.android.importClass("android.location.LocationManager");
    var main = plus.android.runtimeMainActivity();
    var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
    var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
    console.log("系统定位开启:" + result);
    return result
  }
}

export default {
  judgeIosPermission: judgeIosPermission,
  requestAndroidPermission: requestAndroidPermission,
  checkSystemEnableLocation: checkSystemEnableLocation,
  gotoAppPermissionSetting: gotoAppPermissionSetting
}

使用:

<text class="info-label header-label">头像</text>
<image class="user-header" :src="photo || defaultImg" mode="aspectFit" @error="handleImgError" @click="chooseToBase64"></image>
import useImage from '@/composables/useImage.js' // 图片处理工具
import useRequest from '@/composables/useRequest.js' // 接口请求工具

/**
 * 修改头像业务
 */
const { request, toast } = useRequest()

// 修改头像
const userHeaderChange = images => {
  form.photo = images[0]
  // 调用修改头像接口
  request({
    url,
    method: 'POST',
    data
  }).then(({body}) => {
    toast('头像修改成功')
    userInfo.value.photo = images[0]
    store.commit('saveUserInfo', userInfo.value) // 缓存用户信息
  }).catch(() => {
    toast('头像修改失败')
  })
}

const { defaultImg, handleImgError, chooseToBase64 } = useImage({ limit: 1, changeFun: userHeaderChange })

顶部导航栏搜索框

// pages.json
{
  "path": "pages/vehcile/vehcile",
  "style": {
    "navigationBarTitleText": "设备",
    "enablePullDownRefresh": true,
    "pullToRefresh": {
      "style": "circle"
    },
    "app-plus": {
      "bounce": "none",
      "scrollIndicator": "none",
      "titleNView": {
        "paddingLeft": 12,
        "searchInput": {
          "borderRadius": "6px", // 输入框圆角
          "align": "left",
          "backgroundColor": "#ffffff",
          "placeholder": "搜索关键字"
        },
        "buttons": [ // 原生标题栏按钮配置
          {
            "fontSrc": "/static/font/iconfont/iconfont.ttf",
            "text": "\ue604", // 原生标题栏矢量图标按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
            "fontSize": "24px",
            "color": "#0070ff",
            "width": "60px"
          }
        ]
      }
    }
  }
}
/**
 * 搜索业务
 */
let searchKey = ''

onNavigationBarSearchInputConfirmed(({text}) => {
  searchKey = text.trim()
  refresh()
})

/**
 * 新增业务
 */
onNavigationBarButtonTap(() => uni.navigateTo({
  url: './bind/bind'
}))

// 重置筛选条件
const reset = () => {
  // #ifdef APP-PLUS
  const pages = getCurrentPages() // 得到所有页面对象
  const page = pages[pages.length - 1] // 获取当前页面对象
  const webview = page.$getAppWebview() // 获取当前页面webview对象
  webview.setTitleNViewSearchInputText('') // 清空导航栏搜索框
  // #endif
  // #ifdef H5
  document.querySelector('.uni-input-input').value = ''
  // #endif
  searchKey = ''
}

uni-calendar

1.使用作用域插槽展示每日的数据(需要修改组件源码)

修改源码:

<!-- uni-calendar.vue 中找到uni-calendar__weeks类名元素 -->
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
  <view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
    <calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate">
      <template #extraInfo="{info}">
        <slot name="extraInfo" :info="info"></slot>
      </template>
    </calendar-item>
  </view>
</view>
<!-- uni-calendar-item.vue 组件中搜索weeks.extraInfo.info字段,将所有包含有weeks.extraInfo.info字段的代码替换成以下代码 -->
<view
  class="uni-calendar-item__weeks-lunar-text"
  :class="{
    'uni-calendar-item--extra':weeks.extraInfo.info,
    'uni-calendar-item--isDay-text':weeks.isDay,
    'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
    'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
    'uni-calendar-item--before-checked':weeks.beforeMultiple,
    'uni-calendar-item--multiple': weeks.multiple,
    'uni-calendar-item--after-checked':weeks.afterMultiple,
    'uni-calendar-item--disable':weeks.disable,
  }"
  v-if="weeks.extraInfo && weeks.extraInfo.info"
>
  <text v-if="typeof weeks.extraInfo.info === 'string'">{{ weeks.extraInfo.info }}</text>
  <slot name="extraInfo" :info="weeks.extraInfo.info"></slot>
</view>

通过uni-calendar-item__weeks-box-item类名可以设置单元格高度。

使用:

<uni-calendar insert :selected="attendanceList" :show-month="false" @monthSwitch="calendarChange">
  <template #extraInfo="{info}">
    <view class="is-info-bg calendar-value calendar-work-time">
      <view class="calendar-value-inner">
        {{ info.worktime }}H
      </view>
    </view>
    <view class="is-warn-bg calendar-value">
      <view class="calendar-value-inner">
        {{ info.fuelconsum }}L
      </view>
    </view>
  </template>
</uni-calendar>
/*
 * 日历业务
 */
const attendanceList = ref([])
const thisDate = new Date()
let startDate = util.getMonthFirst(thisDate)
let endDate = util.getMonthLast(thisDate)

const calendarChange = ({year, month}) => {
  const changeDate = new Date(year, month - 1, 1)
  startDate = util.getMonthFirst(changeDate)
  endDate = util.getMonthLast(changeDate)
  loadCalendar()
}

const loadCalendar = () => {
  let url = '' // 数据查询接口
  let data = { // 数据查询参数
  }
  request({
    url,
    data,
    method: 'get'
  }).then(({body}) => {
    attendanceList.value = body.data.map(item => ({
      date: item.datetime,
      info: {
        worktime: item.worktime,
        fuelconsum: item.fuelconsum
      }
    }))
  })
}
.is-info-bg {
  color: $uni-bg-color;
  background: #0070ff;
}
.is-warn-bg {
  color: $uni-bg-color;
  background: #ff9300;
}
.calendar-value {
  padding: 2px 0;
  text-align: center;
  .calendar-value-inner {
    transform: scale(0.75);
  }
}
.calendar-work-time {
  margin-bottom: 8rpx;
}
:deep(.uni-calendar) {
  .uni-calendar__backtoday,
  .uni-calendar-item__weeks-box-circle {
    display: none;
  }
  .uni-calendar-item__weeks-box-text {
    font-weight: 600;
  }
  .uni-calendar-item--isDay {
    background-color: transparent;
    opacity: 1;
    color: #0070ff;
  }
  .uni-calendar-item--extra {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    width: 100%;
    font-size: 24rpx;
    color: $uni-text-color-inverse;
  }
}

Logo

前往低代码交流专区

更多推荐