Commit 249b839498114354466d683e1cb030b93997b896

Authored by xp.Huang
2 parents 2f6bd6e7 9f612429

Merge branch 'dev-ft' into 'main'

预览打包小程序完成

See merge request huang/thingskit-app!22
Showing 68 changed files with 1114 additions and 5794 deletions
@@ -71,16 +71,11 @@ @@ -71,16 +71,11 @@
71 <view v-if="list.status !== 'CLEARED_ACK'" style="width: 500rpx;margin-left: 80rpx;margin-top: 44rpx;"> 71 <view v-if="list.status !== 'CLEARED_ACK'" style="width: 500rpx;margin-left: 80rpx;margin-top: 44rpx;">
72 <u-button @click="handleSubmit" type="primary" shape="circle" text="处理"></u-button> 72 <u-button @click="handleSubmit" type="primary" shape="circle" text="处理"></u-button>
73 </view> 73 </view>
74 - <f-tabbar></f-tabbar>  
75 </view> 74 </view>
76 </template> 75 </template>
77 76
78 <script> 77 <script>
79 -import fTabbar from '@/components/module/f-tabbar/f-tabbar';  
80 export default { 78 export default {
81 - components: {  
82 - fTabbar  
83 - },  
84 data() { 79 data() {
85 return { 80 return {
86 formModel: { 81 formModel: {
alarmSubPage/alarmDetailPage/static/alarmDetail.scss renamed from pages/alarm/static/alarmDetail.scss
1 import store from '@/store'; 1 import store from '@/store';
2 import base from "@/config/baseUrl"; 2 import base from "@/config/baseUrl";
3 -import QQMapWX from '@/plugins/qqmap-wx-jssdk.js'; 3 +// import QQMapWX from '@/plugins/qqmap-wx-jssdk.js';
4 import { 4 import {
5 getAppLatLon 5 getAppLatLon
6 } from '@/plugins/utils'; 6 } from '@/plugins/utils';
1 import base from "@/config/baseUrl"; 1 import base from "@/config/baseUrl";
2 -import store from '@/store';  
3 -import {  
4 - judgeLogin  
5 -} from '@/config/login'; 2 +import store from "@/store";
  3 +import { judgeLogin } from "@/config/login";
6 4
7 // 初始化请求配置 5 // 初始化请求配置
8 uni.$u.http.setConfig((config) => { 6 uni.$u.http.setConfig((config) => {
9 - const token = store.state.userInfo.isToken || (uni.getStorageSync('userInfo').isToken || undefined)  
10 - // #ifdef H5  
11 - window.sessionStorage.getItem('userInfo').isToken;  
12 - // #endif  
13 - /* config 为默认全局配置*/  
14 - config.baseURL = base.baseUrl; /* 根域名 */  
15 - config.header = {  
16 - 'Content-Type': 'application/json',  
17 - 'Authorization': 'Bearer ' + token  
18 - }  
19 - config.custom = {  
20 - load: true, //是否显示加载动画  
21 - isFactory: true, //true:返回的数据成功只返回data false:返回response  
22 - catch: true, //默认数据返回不成功进入catch返回  
23 - auth: true, //token  
24 - }  
25 - return config  
26 -}) 7 + const token =
  8 + store.state.userInfo.isToken ||
  9 + uni.getStorageSync("userInfo").isToken ||
  10 + undefined;
  11 + // #ifdef H5
  12 + window.sessionStorage.getItem("userInfo").isToken;
  13 + // #endif
  14 + /* config 为默认全局配置*/
  15 + config.baseURL = base.baseUrl; /* 根域名 */
  16 + config.header = {
  17 + "Content-Type": "application/json",
  18 + Authorization: "Bearer " + token,
  19 + };
  20 + config.custom = {
  21 + load: true, //是否显示加载动画
  22 + isFactory: true, //true:返回的数据成功只返回data false:返回response
  23 + catch: true, //默认数据返回不成功进入catch返回
  24 + auth: true, //token
  25 + };
  26 + return config;
  27 +});
27 28
28 // 请求拦截 29 // 请求拦截
29 -uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作  
30 - // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}  
31 - config.data = config.data || {}  
32 - // 根据custom参数中配置的是否需要token,添加对应的请求头  
33 - if (config?.custom?.auth) {  
34 - config.header.Authorization = 'Bearer ' + store.state.userInfo.isToken || (uni.getStorageSync(  
35 - 'userInfo').isToken || undefined)  
36 - }  
37 - console.log("请求开始", config);  
38 - if (config?.custom?.load) {  
39 - //打开加载动画  
40 - store.commit("setLoadingShow", true);  
41 - } 30 +uni.$u.http.interceptors.request.use(
  31 + (config) => {
  32 + // 可使用async await 做异步操作
  33 + // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
  34 + config.data = config.data || {};
  35 + // 根据custom参数中配置的是否需要token,添加对应的请求头
  36 + if (config?.custom?.auth) {
  37 + config.header.Authorization =
  38 + "Bearer " + store.state.userInfo.isToken ||
  39 + uni.getStorageSync("userInfo").isToken ||
  40 + undefined;
  41 + }
  42 + console.log("请求开始", config);
  43 + if (config?.custom?.load) {
  44 + //打开加载动画
  45 + store.commit("setLoadingShow", true);
  46 + }
42 47
43 - return config  
44 -}, config => { // 可使用async await 做异步操作  
45 - return Promise.reject(config)  
46 -}) 48 + return config;
  49 + },
  50 + (config) => {
  51 + // 可使用async await 做异步操作
  52 + return Promise.reject(config);
  53 + }
  54 +);
47 55
48 // 响应拦截 56 // 响应拦截
49 -uni.$u.http.interceptors.response.use((response) => {  
50 - /* 对响应成功做点什么 可使用async await 做异步操作*/  
51 - // 关闭加载动画  
52 - store.commit("setLoadingShow", false);  
53 - const data = response.data  
54 - // 自定义参数  
55 - const custom = response.config?.custom  
56 - // code: 200、请求成功 其他,没有更多参数 401、被迫下线重新登录、  
57 - if (response.statusCode == 200) {  
58 - return Promise.resolve(data)  
59 - // if (!custom.isFactory) {  
60 - // return Promise.reject(response.data)  
61 - // } else {  
62 - // return data.data === undefined ? {} : Promise.reject(response.data)  
63 - // }  
64 - } else if (response.statusCode == 401) { //被迫下线重新登录  
65 - // 清空登录信息  
66 - store.commit("emptyUserInfo");  
67 - // 20秒节流,弹窗登录  
68 - uni.$u.throttle(judgeLogin(), 20000)  
69 - return new Promise(() => {})  
70 - } else {  
71 - // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示  
72 - if (custom.toast !== false) {  
73 - uni.$u.toast(data.message || data.msg)  
74 - }  
75 - // 如果需要catch返回,则进行reject  
76 - if (custom?.catch) {  
77 - return Promise.reject(data)  
78 - } else {  
79 - // 否则返回一个pending中的promise,请求不会进入catch中  
80 - return new Promise(() => {})  
81 - }  
82 - }  
83 -}, (response) => {  
84 - // 关闭加载动画  
85 - store.commit("setLoadingShow", false);  
86 - // 对响应错误做点什么 (statusCode !== 200)  
87 - let errorData = '请检查网络或服务器'  
88 - let message = response.data?.message || response?.errMsg  
89 - if (message == "request:fail url not in domain list") {  
90 - errorData = '检查请求域名是否添加了域名白名单'  
91 - } else if (message == 'request:fail timeout') {  
92 - errorData = '请求超时:请检查网络'  
93 - } else if (message == 'Token has expired') {  
94 - errorData = 'Token失效,请重新登录'  
95 - uni.reLaunch({  
96 - url: '/pages/public/login'  
97 - })  
98 - store.commit('emptyUserInfo')  
99 - } else if (message == 'Invalid username or password') {  
100 - errorData = '用户名或者密码无效'  
101 - uni.reLaunch({  
102 - url: '/pages/public/login'  
103 - })  
104 - store.commit('emptyUserInfo')  
105 - } else {  
106 - errorData = message || '请检查网络或服务器'  
107 - }  
108 - uni.$u.toast(errorData)  
109 - return Promise.reject(response)  
110 -}) 57 +uni.$u.http.interceptors.response.use(
  58 + (response) => {
  59 + /* 对响应成功做点什么 可使用async await 做异步操作*/
  60 + // 关闭加载动画
  61 + store.commit("setLoadingShow", false);
  62 + const data = response.data;
  63 + // 自定义参数
  64 + const custom = response.config?.custom;
  65 + // code: 200、请求成功 其他,没有更多参数 401、被迫下线重新登录、
  66 + if (response.statusCode == 200) {
  67 + return Promise.resolve(data);
  68 + // if (!custom.isFactory) {
  69 + // return Promise.reject(response.data)
  70 + // } else {
  71 + // return data.data === undefined ? {} : Promise.reject(response.data)
  72 + // }
  73 + } else if (response.statusCode == 401) {
  74 + //被迫下线重新登录
  75 + // 清空登录信息
  76 + store.commit("emptyUserInfo");
  77 + // 20秒节流,弹窗登录
  78 + uni.$u.throttle(judgeLogin(), 20000);
  79 + return new Promise(() => {});
  80 + } else {
  81 + // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
  82 + if (custom.toast !== false) {
  83 + uni.$u.toast(data.message || data.msg);
  84 + }
  85 + // 如果需要catch返回,则进行reject
  86 + if (custom?.catch) {
  87 + return Promise.reject(data);
  88 + } else {
  89 + // 否则返回一个pending中的promise,请求不会进入catch中
  90 + return new Promise(() => {});
  91 + }
  92 + }
  93 + },
  94 + (response) => {
  95 + // 关闭加载动画
  96 + store.commit("setLoadingShow", false);
  97 + // 对响应错误做点什么 (statusCode !== 200)
  98 + let errorData = "请检查网络或服务器";
  99 + let message = response.data?.message || response?.errMsg;
  100 + if (message == "request:fail url not in domain list") {
  101 + errorData = "检查请求域名是否添加了域名白名单";
  102 + } else if (message == "request:fail timeout") {
  103 + errorData = "请求超时:请检查网络";
  104 + } else if (message == "Token has expired") {
  105 + errorData = "Token失效,请重新登录";
  106 + uni.reLaunch({
  107 + url: "/publicLoginSubPage/public/login",
  108 + });
  109 + store.commit("emptyUserInfo");
  110 + } else if (message == "Invalid username or password") {
  111 + errorData = "用户名或者密码无效";
  112 + uni.reLaunch({
  113 + url: "/publicLoginSubPage/public/login",
  114 + });
  115 + store.commit("emptyUserInfo");
  116 + } else {
  117 + errorData = message || "请检查网络或服务器";
  118 + }
  119 + uni.$u.toast(errorData);
  120 + return Promise.reject(response);
  121 + }
  122 +);
1 -<template>  
2 - <view class="device-detail-page">  
3 - <!-- 公共组件-每个页面必须引入 -->  
4 - <public-module></public-module>  
5 - <u-sticky bgColor="#fff"><u-tabs :list="list" :current="currentTab" @click="handleTabClick"></u-tabs></u-sticky>  
6 - <view style="margin-top:30rpx;">  
7 - <basicInfo v-if="currentTab == 0" :deviceDetail="deviceDetail" />  
8 - <realTimeData v-if="currentTab === 1" />  
9 - <historyData v-if="currentTab === 2" :keys="keys" />  
10 - <alarmHistory v-if="currentTab === 3" />  
11 - <commondRecord v-if="currentTab === 4" />  
12 - </view>  
13 - <f-tabbar></f-tabbar>  
14 - </view>  
15 -</template>  
16 -  
17 -<script>  
18 -import fTabbar from '@/components/module/f-tabbar/f-tabbar';  
19 -import basicInfo from './tabDetail/basicInfo.vue';  
20 -import realTimeData from './tabDetail/realtimeData.vue';  
21 -import alarmHistory from './tabDetail/alarmHistory.vue';  
22 -import historyData from './tabDetail/historyData.vue';  
23 -import commondRecord from './tabDetail/commondRecord.vue';  
24 -import { getDeviceKeys } from './api/index.js';  
25 -export default {  
26 - components: {  
27 - fTabbar,  
28 - basicInfo,  
29 - realTimeData,  
30 - alarmHistory,  
31 - historyData,  
32 - commondRecord  
33 - },  
34 - data() {  
35 - return {  
36 - list: [{ name: '基础信息' }, { name: '实时数据' }, { name: '历史数据' }, { name: '告警记录' }, { name: '命令记录' }],  
37 - currentTab: 0,  
38 - id: '',  
39 - deviceDetail: {},  
40 - keys:[]  
41 - };  
42 - },  
43 - async onLoad(options) {  
44 - const { id, alarmStatus, lastOnlineTime, tbDeviceId } = options;  
45 - const res = await uni.$u.http.get(`/yt/device/${id}`);  
46 - this.deviceDetail = { ...res, alarmStatus, lastOnlineTime };  
47 -  
48 - // var socketTask = uni.connectSocket({  
49 - // url: 'wss://dev.thingskit.com:8080/api/ws/plugins/telemetry?token=' + uni.getStorageSync('userInfo').isToken, //仅为示例,并非真实接口地址。  
50 - // complete: ()=> {}  
51 - // });  
52 - // uni.onSocketOpen((header)=>{  
53 - // console.log('连接成功',header)  
54 - // })  
55 - // // socketTask.onMessage(function(data) {  
56 - // // console.log('收到消息了', data);  
57 - // // });  
58 - // socketTask.send({  
59 - // data: JSON.stringify({  
60 - // attrSubCmds: [],  
61 - // tsSubCmds: [  
62 - // {  
63 - // entityType: 'DEVICE',  
64 - // entityId: id,  
65 - // scope: 'LATEST_TELEMETRY',  
66 - // cmdId: 1  
67 - // }  
68 - // ],  
69 - // historyCmds: [],  
70 - // entityDataCmds: [],  
71 - // entityDataUnsubscribeCmds: [],  
72 - // alarmDataCmds: [],  
73 - // alarmDataUnsubscribeCmds: [],  
74 - // entityCountCmds: [],  
75 - // entityCountUnsubscribeCmds: []  
76 - // }),  
77 - // success() {  
78 - // console.log('发送成功了');  
79 - // }  
80 - // });  
81 -  
82 -  
83 - const keys = await getDeviceKeys(tbDeviceId);  
84 - // 隐藏原生的tabbar'  
85 - this.keys = [keys]  
86 - uni.hideTabBar();  
87 - },  
88 - methods: {  
89 - handleTabClick({ index }) {  
90 - this.currentTab = index;  
91 - }  
92 - }  
93 -}; 1 +<template>
  2 + <view class="device-detail-page">
  3 + <!-- 公共组件-每个页面必须引入 -->
  4 + <public-module></public-module>
  5 + <u-sticky bgColor="#fff"><u-tabs :list="list" :current="currentTab" @click="handleTabClick"></u-tabs></u-sticky>
  6 + <view style="margin-top:30rpx;">
  7 + <basicInfo v-if="currentTab == 0" :deviceDetail="deviceDetail" />
  8 + <realTimeData v-if="currentTab === 1" />
  9 + <historyData v-if="currentTab === 2" :keys="keys" />
  10 + <alarmHistory v-if="currentTab === 3" />
  11 + <commondRecord v-if="currentTab === 4" />
  12 + </view>
  13 + <f-tabbar></f-tabbar>
  14 + </view>
  15 +</template>
  16 +
  17 +<script>
  18 +import fTabbar from '@/components/module/f-tabbar/f-tabbar';
  19 +import basicInfo from './tabDetail/basicInfo.vue';
  20 +import realTimeData from './tabDetail/realtimeData.vue';
  21 +import alarmHistory from './tabDetail/alarmHistory.vue';
  22 +import historyData from './tabDetail/historyData.vue';
  23 +import commondRecord from './tabDetail/commondRecord.vue';
  24 +import { getDeviceKeys } from '../../pages/device/api/index';
  25 +export default {
  26 + components: {
  27 + fTabbar,
  28 + basicInfo,
  29 + realTimeData,
  30 + alarmHistory,
  31 + historyData,
  32 + commondRecord
  33 + },
  34 + data() {
  35 + return {
  36 + list: [{ name: '基础信息' }, { name: '实时数据' }, { name: '历史数据' }, { name: '告警记录' }, { name: '命令记录' }],
  37 + currentTab: 0,
  38 + id: '',
  39 + deviceDetail: {},
  40 + keys:[]
  41 + };
  42 + },
  43 + async onLoad(options) {
  44 + const { id, alarmStatus, lastOnlineTime, tbDeviceId } = options;
  45 + const res = await uni.$u.http.get(`/yt/device/${id}`);
  46 + this.deviceDetail = { ...res, alarmStatus, lastOnlineTime };
  47 +
  48 + // var socketTask = uni.connectSocket({
  49 + // url: 'wss://dev.thingskit.com:8080/api/ws/plugins/telemetry?token=' + uni.getStorageSync('userInfo').isToken, //仅为示例,并非真实接口地址。
  50 + // complete: ()=> {}
  51 + // });
  52 + // uni.onSocketOpen((header)=>{
  53 + // console.log('连接成功',header)
  54 + // })
  55 + // // socketTask.onMessage(function(data) {
  56 + // // console.log('收到消息了', data);
  57 + // // });
  58 + // socketTask.send({
  59 + // data: JSON.stringify({
  60 + // attrSubCmds: [],
  61 + // tsSubCmds: [
  62 + // {
  63 + // entityType: 'DEVICE',
  64 + // entityId: id,
  65 + // scope: 'LATEST_TELEMETRY',
  66 + // cmdId: 1
  67 + // }
  68 + // ],
  69 + // historyCmds: [],
  70 + // entityDataCmds: [],
  71 + // entityDataUnsubscribeCmds: [],
  72 + // alarmDataCmds: [],
  73 + // alarmDataUnsubscribeCmds: [],
  74 + // entityCountCmds: [],
  75 + // entityCountUnsubscribeCmds: []
  76 + // }),
  77 + // success() {
  78 + // console.log('发送成功了');
  79 + // }
  80 + // });
  81 +
  82 +
  83 + const keys = await getDeviceKeys(tbDeviceId);
  84 + // 隐藏原生的tabbar'
  85 + this.keys = [keys]
  86 + uni.hideTabBar();
  87 + },
  88 + methods: {
  89 + handleTabClick({ index }) {
  90 + this.currentTab = index;
  91 + }
  92 + }
  93 +};
94 </script> 94 </script>
deviceSubPage/deviceDetailPage/tabDetail/alarmHistory.vue renamed from pages/device/tabDetail/alarmHistory.vue
1 -<template>  
2 - <view class="alert-page">  
3 - <!-- 公共组件-每个页面必须引入 -->  
4 - <public-module></public-module>  
5 - <view style="width: 192rpx;margin: 19rpx;"><u-button @click="openSearchDialog" shape="circle" type="info" icon="search" text="筛选"></u-button></view>  
6 - <view class="device-list">  
7 - <view @click="openDeviceDetail(item.id)" class="list-item" v-for="(item, index) in list" :key="index">  
8 - <view class="u-flex item" style="justify-content: flex-start;flex-direction: column;align-items: center;">  
9 - <view style="width: 400rpx;text-align: left;">  
10 - <text style="color:#333;font-size: 15px;">{{ item.name1 }}</text>  
11 - </view>  
12 - <view style="width: 400rpx;text-align: left;">  
13 - <text style="color:#666;font-size: 15px;">{{ item.name2 }}</text>  
14 - </view>  
15 - <view style="width: 400rpx;text-align: left;">  
16 - <text style="color:#666;font-size: 15px;">{{ item.name3 }}</text>  
17 - </view>  
18 - <view style="width: 400rpx;text-align: left;">  
19 - <text style="color:#999;font-size: 15px;">{{ item.time }}</text>  
20 - </view>  
21 - </view>  
22 - <view class="item">  
23 - <view class="u-flex" style="margin-top: -6rpx;">  
24 - <image style="width: 30rpx;height: 30rpx;margin-top: 5rpx;margin-right: 5rpx;" :src="item.name4" mode=""></image>  
25 - <view>  
26 - <text style="color: #377DFF;font-size: 13px;margin-left: 5rpx;margin-top: 20rpx;">{{ item.name5 }}</text>  
27 - </view>  
28 - </view>  
29 - </view>  
30 - </view>  
31 - </view>  
32 - <view style="height: 30rpx;"></view>  
33 - <!-- 告警筛选 -->  
34 - <u-popup @close="close" closeable bgColor="transparent" :overlay="true" :show="show" mode="bottom">  
35 - <view style="height: 1100rpx;background:#fff;border-radius: 20rpx;overflow-y: scroll;">  
36 - <view style="text-align: center;position: relative;top: 68rpx;margin-top: -40rpx;"><text style="font-size: 16px;color: #333333;">筛选条件</text></view>  
37 - <view style="margin-top: 97rpx;margin-left: 43rpx;">  
38 - <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333333;font-size: 14px;">告警状态</text></view>  
39 - <view  
40 - class="u-flex"  
41 - style="margin-top: 15rpx;width:650rpx;height: 60rpx;  
42 - flex-wrap: wrap;justify-content: space-between; align-content: space-between;"  
43 - >  
44 - <view  
45 - v-for="(item, index) in alertStatus"  
46 - :key="index"  
47 - style="margin: 10rpx;line-height: 50rpx;text-align: center;  
48 - width:180rpx;height: 60rpx;  
49 - background-color:#F6F6F6;border-radius:32px"  
50 - >  
51 - <text style="color:#333333;font-size: 13px;">{{ item.name }}</text>  
52 - </view>  
53 - </view>  
54 - </view>  
55 - <view style="margin-top: 145rpx;margin-left: 43rpx;">  
56 - <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333333;font-size: 14px;">设备类型</text></view>  
57 - <view  
58 - class="u-flex"  
59 - style="margin-top: 15rpx;width:650rpx;height: 60rpx;  
60 - flex-wrap: wrap;justify-content: space-between; align-content: space-between;"  
61 - >  
62 - <view  
63 - v-for="(item, index) in deviceType"  
64 - :key="index"  
65 - style="margin: 10rpx;line-height: 50rpx;text-align: center;  
66 - width:180rpx;height: 60rpx;  
67 - background-color:#F6F6F6;border-radius:32px"  
68 - >  
69 - <text style="color:#333;font-size: 13px;">{{ item.name }}</text>  
70 - </view>  
71 - </view>  
72 - </view>  
73 - <view style="margin-top: 136rpx;margin-left: 43rpx;">  
74 - <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333;font-size: 14px;">告警等级</text></view>  
75 - <view  
76 - class="u-flex"  
77 - style="margin-top: 15rpx;width:650rpx;height: 60rpx;  
78 - flex-wrap: wrap;justify-content: space-between; align-content: space-between;"  
79 - >  
80 - <view  
81 - v-for="(item, index) in alertLevel"  
82 - :key="index"  
83 - style="margin: 10rpx;line-height: 50rpx;text-align: center;  
84 - width:180rpx;height: 60rpx;  
85 - background-color:#F6F6F6;border-radius:32px"  
86 - >  
87 - <text style="color:#333333;font-size: 13px;">{{ item.name }}</text>  
88 - </view>  
89 - </view>  
90 - </view>  
91 - <view style="margin-top: 136rpx;margin-left: 43rpx;">  
92 - <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333333;font-size: 14px;">选择时间</text></view>  
93 - <view  
94 - class="u-flex"  
95 - style="margin-top: 15rpx;width:650rpx;height: 60rpx;  
96 - flex-wrap: wrap;justify-content: space-between; align-content: space-between;"  
97 - >  
98 - <view  
99 - v-for="(item, index) in timeArea"  
100 - :key="index"  
101 - style="margin: 10rpx;line-height: 50rpx;text-align: center;  
102 - width:180rpx;height: 60rpx;  
103 - background-color:#F6F6F6;border-radius:32px"  
104 - >  
105 - <text style="color:#333333;font-size: 13px;">{{ item.name }}</text>  
106 - </view>  
107 - </view>  
108 - </view>  
109 - <view style="margin-top: 136rpx;margin-left: 43rpx;">  
110 - <view class="u-flex" style="margin-left: 10rpx;margin-top: 15rpx;width:750rpx;height: 60rpx;">  
111 - <u--form labelPosition="left" :model="timeData" :rules="rules" ref="form1" style="padding-left: 26rpx;width: 617rpx!important;">  
112 - <u-form-item  
113 - style="font-size: 14px;"  
114 - label="选择日期"  
115 - prop="selectTime"  
116 - labelWidth="80"  
117 - borderBottom  
118 - @click="  
119 - showCalendar = true;  
120 - hideKeyboard();  
121 - "  
122 - >  
123 - <u--input v-model="timeData.selectTime" placeholder="请选择日期" border="none"></u--input>  
124 - </u-form-item>  
125 - </u--form>  
126 - </view>  
127 - </view>  
128 - <view class="u-flex" style="margin-top: 128rpx;margin-left: 55rpx;">  
129 - <view style="width: 300rpx"><u-button type="info" shape="circle" text="重置"></u-button></view>  
130 - <view style="width: 300rpx;margin-left:46rpx ;"><u-button type="primary" shape="circle" text="确认"></u-button></view>  
131 - </view>  
132 - <view style="height: 30rpx;"></view>  
133 - </view>  
134 - </u-popup>  
135 - <u-calendar  
136 - :show="showCalendar"  
137 - mode="range"  
138 - @confirm="calendarConfirm"  
139 - @close="calendarClose"  
140 - startText="开始时间"  
141 - endText="结束时间"  
142 - confirmDisabledText="请选择日期"  
143 - :formatter="formatter"  
144 - ></u-calendar>  
145 - <f-tabbar :isFillHeight="false"></f-tabbar>  
146 - </view>  
147 -</template>  
148 -  
149 -<script>  
150 -import fTabbar from '@/components/module/f-tabbar/f-tabbar';  
151 -export default {  
152 - components: {  
153 - fTabbar  
154 - },  
155 - data() {  
156 - return {  
157 - show: false,  
158 - timeData: {  
159 - selectTime: '',  
160 - getTimeGap: ''  
161 - },  
162 - showCalendar: false,  
163 - alertStatus: [  
164 - {  
165 - index: 1,  
166 - name: '全部',  
167 - bgColor: '#377DFF',  
168 - textColor: '#377DFF'  
169 - },  
170 - {  
171 - index: 2,  
172 - name: '激活未确认',  
173 - bgColor: '#F6F6F6',  
174 - textColor: '#F6F6F6'  
175 - },  
176 - {  
177 - index: 3,  
178 - name: '激活已确认',  
179 - bgColor: '#F6F6F6',  
180 - textColor: '#F6F6F6'  
181 - },  
182 - {  
183 - index: 4,  
184 - name: '清除未确认',  
185 - bgColor: '#F6F6F6',  
186 - textColor: '#F6F6F6'  
187 - },  
188 - {  
189 - index: 5,  
190 - name: '清除已确认',  
191 - bgColor: '#F6F6F6',  
192 - textColor: '#F6F6F6'  
193 - },  
194 - {  
195 - index: 6,  
196 - name: '清除已确认',  
197 - bgColor: '#F6F6F6',  
198 - textColor: '#F6F6F6'  
199 - }  
200 - ],  
201 - deviceType: [  
202 - {  
203 - index: 1,  
204 - name: '全部',  
205 - bgColor: '#377DFF',  
206 - textColor: '#377DFF'  
207 - },  
208 - {  
209 - index: 2,  
210 - name: '网关设备',  
211 - bgColor: '#F6F6F6',  
212 - textColor: '#F6F6F6'  
213 - },  
214 - {  
215 - index: 3,  
216 - name: '网关子设备',  
217 - bgColor: '#F6F6F6',  
218 - textColor: '#F6F6F6'  
219 - },  
220 - {  
221 - index: 4,  
222 - name: '直连设备',  
223 - bgColor: '#F6F6F6',  
224 - textColor: '#F6F6F6'  
225 - }  
226 - ],  
227 - alertLevel: [  
228 - {  
229 - index: 1,  
230 - name: '全部',  
231 - bgColor: '#377DFF',  
232 - textColor: '#377DFF'  
233 - },  
234 - {  
235 - index: 2,  
236 - name: '危险',  
237 - bgColor: '#F6F6F6',  
238 - textColor: '#F6F6F6'  
239 - },  
240 - {  
241 - index: 3,  
242 - name: '重要',  
243 - bgColor: '#F6F6F6',  
244 - textColor: '#F6F6F6'  
245 - },  
246 - {  
247 - index: 4,  
248 - name: '次要',  
249 - bgColor: '#F6F6F6',  
250 - textColor: '#F6F6F6'  
251 - },  
252 - {  
253 - index: 4,  
254 - name: '警告',  
255 - bgColor: '#F6F6F6',  
256 - textColor: '#F6F6F6'  
257 - },  
258 - {  
259 - index: 4,  
260 - name: '不确定',  
261 - bgColor: '#F6F6F6',  
262 - textColor: '#F6F6F6'  
263 - }  
264 - ],  
265 - timeArea: [  
266 - {  
267 - index: 1,  
268 - name: '全部',  
269 - value: '全部',  
270 - bgColor: '#F6F6F6',  
271 - textColor: '#F6F6F6'  
272 - },  
273 - {  
274 - index: 2,  
275 - name: '30分钟',  
276 - value: '30',  
277 - bgColor: '#F6F6F6',  
278 - textColor: '#F6F6F6'  
279 - },  
280 - {  
281 - index: 3,  
282 - name: '1小时',  
283 - value: '30',  
284 - bgColor: '#F6F6F6',  
285 - textColor: '#F6F6F6'  
286 - },  
287 - {  
288 - index: 4,  
289 - name: '2小时',  
290 - value: '120',  
291 - bgColor: '#F6F6F6',  
292 - textColor: '#F6F6F6'  
293 - },  
294 - {  
295 - index: 5,  
296 - name: '近一天',  
297 - value: '24',  
298 - bgColor: '#F6F6F6',  
299 - textColor: '#F6F6F6'  
300 - },  
301 - {  
302 - index: 6,  
303 - name: '',  
304 - value: '',  
305 - bgColor: '#F6F6F6',  
306 - textColor: '#F6F6F6'  
307 - }  
308 - ],  
309 - list: [  
310 - {  
311 - name1: '1号楼1楼三单元水表',  
312 - name2: 'CO₂:65.32',  
313 - name3: '告警状态:清除已确认',  
314 - name4: '../../../static/danger.png',  
315 - name5: '危险',  
316 - time: '2022-04-01 02:12:23',  
317 - id: 'xx1'  
318 - },  
319 - {  
320 - name1: '2号楼1楼三单元水表',  
321 - name2: 'PH:9.8',  
322 - name3: '告警状态:激活未确认',  
323 - name4: '../../../static/major.png',  
324 - name5: '重要',  
325 - time: '2022-04-01 02:12:23',  
326 - id: 'xx2'  
327 - },  
328 - {  
329 - name1: '3号楼1楼三单元水表',  
330 - name2: 'NH3:600',  
331 - name3: '告警状态:激活未确认',  
332 - name4: '../../../static/secondary.png',  
333 - name5: '次要',  
334 - time: '2022-04-01 02:12:23',  
335 - id: 'xx3'  
336 - },  
337 - {  
338 - name1: '4号楼1楼三单元水表',  
339 - name2: '水深:1.4',  
340 - name3: '告警状态:激活未确认',  
341 - name4: '../../../static/secondary.png',  
342 - name5: '次要',  
343 - time: '2022-04-01 02:12:23',  
344 - id: 'xx4'  
345 - },  
346 - {  
347 - name1: '5号楼1楼三单元水表',  
348 - name2: 'COD:125',  
349 - name3: '告警状态:激活未确认',  
350 - name4: '../../../static/noshue.png',  
351 - name5: '不确定',  
352 - time: '2022-04-01 02:12:23',  
353 - id: 'xx5'  
354 - }  
355 - ]  
356 - };  
357 - },  
358 - onLoad(e) {  
359 - // 隐藏原生的tabbar  
360 - uni.hideTabBar();  
361 - },  
362 - methods: {  
363 - open() {},  
364 - close() {  
365 - this.show = false;  
366 - },  
367 - openSearchDialog() {  
368 - this.show = true;  
369 - },  
370 - hideKeyboard() {  
371 - uni.hideKeyboard();  
372 - },  
373 - calendarConfirm(e) {  
374 - this.showCalendar = false;  
375 - this.timeData.selectTime = `${e[0]} / ${e[e.length - 1]}`;  
376 - },  
377 - calendarClose() {  
378 - this.showCalendar = false;  
379 - }  
380 - }  
381 -};  
382 -</script>  
383 -  
384 -<style lang="scss" scoped>  
385 -.alert-page {  
386 - margin-top: -39rpx;  
387 -}  
388 -.device-list {  
389 - display: flex;  
390 - flex-direction: column;  
391 - padding-left: 18rpx;  
392 - margin-top: -18rpx;  
393 - .list-item {  
394 - width: 713rpx;  
395 - height: 233rpx;  
396 - background-color: #fff;  
397 - margin-top: 24rpx;  
398 - display: flex;  
399 -  
400 - border-radius: 10px;  
401 - justify-content: space-between;  
402 - .item {  
403 - margin: 30rpx;  
404 - }  
405 - }  
406 -} 1 +<template>
  2 + <view class="alert-page">
  3 + <!-- 公共组件-每个页面必须引入 -->
  4 + <public-module></public-module>
  5 + <view style="width: 192rpx;margin: 19rpx;"><u-button @click="openSearchDialog" shape="circle" type="info" icon="search" text="筛选"></u-button></view>
  6 + <view class="device-list">
  7 + <view @click="openDeviceDetail(item.id)" class="list-item" v-for="(item, index) in list" :key="index">
  8 + <view class="u-flex item" style="justify-content: flex-start;flex-direction: column;align-items: center;">
  9 + <view style="width: 400rpx;text-align: left;">
  10 + <text style="color:#333;font-size: 15px;">{{ item.name1 }}</text>
  11 + </view>
  12 + <view style="width: 400rpx;text-align: left;">
  13 + <text style="color:#666;font-size: 15px;">{{ item.name2 }}</text>
  14 + </view>
  15 + <view style="width: 400rpx;text-align: left;">
  16 + <text style="color:#666;font-size: 15px;">{{ item.name3 }}</text>
  17 + </view>
  18 + <view style="width: 400rpx;text-align: left;">
  19 + <text style="color:#999;font-size: 15px;">{{ item.time }}</text>
  20 + </view>
  21 + </view>
  22 + <view class="item">
  23 + <view class="u-flex" style="margin-top: -6rpx;">
  24 + <image style="width: 30rpx;height: 30rpx;margin-top: 5rpx;margin-right: 5rpx;" :src="item.name4" mode=""></image>
  25 + <view>
  26 + <text style="color: #377DFF;font-size: 13px;margin-left: 5rpx;margin-top: 20rpx;">{{ item.name5 }}</text>
  27 + </view>
  28 + </view>
  29 + </view>
  30 + </view>
  31 + </view>
  32 + <view style="height: 30rpx;"></view>
  33 + <!-- 告警筛选 -->
  34 + <u-popup @close="close" closeable bgColor="transparent" :overlay="true" :show="show" mode="bottom">
  35 + <view style="height: 1100rpx;background:#fff;border-radius: 20rpx;overflow-y: scroll;">
  36 + <view style="text-align: center;position: relative;top: 68rpx;margin-top: -40rpx;"><text style="font-size: 16px;color: #333333;">筛选条件</text></view>
  37 + <view style="margin-top: 97rpx;margin-left: 43rpx;">
  38 + <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333333;font-size: 14px;">告警状态</text></view>
  39 + <view
  40 + class="u-flex"
  41 + style="margin-top: 15rpx;width:650rpx;height: 60rpx;
  42 + flex-wrap: wrap;justify-content: space-between; align-content: space-between;"
  43 + >
  44 + <view
  45 + v-for="(item, index) in alertStatus"
  46 + :key="index"
  47 + style="margin: 10rpx;line-height: 50rpx;text-align: center;
  48 + width:180rpx;height: 60rpx;
  49 + background-color:#F6F6F6;border-radius:32px"
  50 + >
  51 + <text style="color:#333333;font-size: 13px;">{{ item.name }}</text>
  52 + </view>
  53 + </view>
  54 + </view>
  55 + <view style="margin-top: 145rpx;margin-left: 43rpx;">
  56 + <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333333;font-size: 14px;">设备类型</text></view>
  57 + <view
  58 + class="u-flex"
  59 + style="margin-top: 15rpx;width:650rpx;height: 60rpx;
  60 + flex-wrap: wrap;justify-content: space-between; align-content: space-between;"
  61 + >
  62 + <view
  63 + v-for="(item, index) in deviceType"
  64 + :key="index"
  65 + style="margin: 10rpx;line-height: 50rpx;text-align: center;
  66 + width:180rpx;height: 60rpx;
  67 + background-color:#F6F6F6;border-radius:32px"
  68 + >
  69 + <text style="color:#333;font-size: 13px;">{{ item.name }}</text>
  70 + </view>
  71 + </view>
  72 + </view>
  73 + <view style="margin-top: 136rpx;margin-left: 43rpx;">
  74 + <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333;font-size: 14px;">告警等级</text></view>
  75 + <view
  76 + class="u-flex"
  77 + style="margin-top: 15rpx;width:650rpx;height: 60rpx;
  78 + flex-wrap: wrap;justify-content: space-between; align-content: space-between;"
  79 + >
  80 + <view
  81 + v-for="(item, index) in alertLevel"
  82 + :key="index"
  83 + style="margin: 10rpx;line-height: 50rpx;text-align: center;
  84 + width:180rpx;height: 60rpx;
  85 + background-color:#F6F6F6;border-radius:32px"
  86 + >
  87 + <text style="color:#333333;font-size: 13px;">{{ item.name }}</text>
  88 + </view>
  89 + </view>
  90 + </view>
  91 + <view style="margin-top: 136rpx;margin-left: 43rpx;">
  92 + <view style="width: 750rpx;margin-left: 14rpx;"><text style="color: #333333;font-size: 14px;">选择时间</text></view>
  93 + <view
  94 + class="u-flex"
  95 + style="margin-top: 15rpx;width:650rpx;height: 60rpx;
  96 + flex-wrap: wrap;justify-content: space-between; align-content: space-between;"
  97 + >
  98 + <view
  99 + v-for="(item, index) in timeArea"
  100 + :key="index"
  101 + style="margin: 10rpx;line-height: 50rpx;text-align: center;
  102 + width:180rpx;height: 60rpx;
  103 + background-color:#F6F6F6;border-radius:32px"
  104 + >
  105 + <text style="color:#333333;font-size: 13px;">{{ item.name }}</text>
  106 + </view>
  107 + </view>
  108 + </view>
  109 + <view style="margin-top: 136rpx;margin-left: 43rpx;">
  110 + <view class="u-flex" style="margin-left: 10rpx;margin-top: 15rpx;width:750rpx;height: 60rpx;">
  111 + <u--form labelPosition="left" :model="timeData" :rules="rules" ref="form1" style="padding-left: 26rpx;width: 617rpx!important;">
  112 + <u-form-item
  113 + style="font-size: 14px;"
  114 + label="选择日期"
  115 + prop="selectTime"
  116 + labelWidth="80"
  117 + borderBottom
  118 + @click="
  119 + showCalendar = true;
  120 + hideKeyboard();
  121 + "
  122 + >
  123 + <u--input v-model="timeData.selectTime" placeholder="请选择日期" border="none"></u--input>
  124 + </u-form-item>
  125 + </u--form>
  126 + </view>
  127 + </view>
  128 + <view class="u-flex" style="margin-top: 128rpx;margin-left: 55rpx;">
  129 + <view style="width: 300rpx"><u-button type="info" shape="circle" text="重置"></u-button></view>
  130 + <view style="width: 300rpx;margin-left:46rpx ;"><u-button type="primary" shape="circle" text="确认"></u-button></view>
  131 + </view>
  132 + <view style="height: 30rpx;"></view>
  133 + </view>
  134 + </u-popup>
  135 + <u-calendar
  136 + :show="showCalendar"
  137 + mode="range"
  138 + @confirm="calendarConfirm"
  139 + @close="calendarClose"
  140 + startText="开始时间"
  141 + endText="结束时间"
  142 + confirmDisabledText="请选择日期"
  143 + :formatter="formatter"
  144 + ></u-calendar>
  145 + <f-tabbar :isFillHeight="false"></f-tabbar>
  146 + </view>
  147 +</template>
  148 +
  149 +<script>
  150 +import fTabbar from '@/components/module/f-tabbar/f-tabbar';
  151 +export default {
  152 + components: {
  153 + fTabbar
  154 + },
  155 + data() {
  156 + return {
  157 + show: false,
  158 + timeData: {
  159 + selectTime: '',
  160 + getTimeGap: ''
  161 + },
  162 + showCalendar: false,
  163 + alertStatus: [
  164 + {
  165 + index: 1,
  166 + name: '全部',
  167 + bgColor: '#377DFF',
  168 + textColor: '#377DFF'
  169 + },
  170 + {
  171 + index: 2,
  172 + name: '激活未确认',
  173 + bgColor: '#F6F6F6',
  174 + textColor: '#F6F6F6'
  175 + },
  176 + {
  177 + index: 3,
  178 + name: '激活已确认',
  179 + bgColor: '#F6F6F6',
  180 + textColor: '#F6F6F6'
  181 + },
  182 + {
  183 + index: 4,
  184 + name: '清除未确认',
  185 + bgColor: '#F6F6F6',
  186 + textColor: '#F6F6F6'
  187 + },
  188 + {
  189 + index: 5,
  190 + name: '清除已确认',
  191 + bgColor: '#F6F6F6',
  192 + textColor: '#F6F6F6'
  193 + },
  194 + {
  195 + index: 6,
  196 + name: '清除已确认',
  197 + bgColor: '#F6F6F6',
  198 + textColor: '#F6F6F6'
  199 + }
  200 + ],
  201 + deviceType: [
  202 + {
  203 + index: 1,
  204 + name: '全部',
  205 + bgColor: '#377DFF',
  206 + textColor: '#377DFF'
  207 + },
  208 + {
  209 + index: 2,
  210 + name: '网关设备',
  211 + bgColor: '#F6F6F6',
  212 + textColor: '#F6F6F6'
  213 + },
  214 + {
  215 + index: 3,
  216 + name: '网关子设备',
  217 + bgColor: '#F6F6F6',
  218 + textColor: '#F6F6F6'
  219 + },
  220 + {
  221 + index: 4,
  222 + name: '直连设备',
  223 + bgColor: '#F6F6F6',
  224 + textColor: '#F6F6F6'
  225 + }
  226 + ],
  227 + alertLevel: [
  228 + {
  229 + index: 1,
  230 + name: '全部',
  231 + bgColor: '#377DFF',
  232 + textColor: '#377DFF'
  233 + },
  234 + {
  235 + index: 2,
  236 + name: '危险',
  237 + bgColor: '#F6F6F6',
  238 + textColor: '#F6F6F6'
  239 + },
  240 + {
  241 + index: 3,
  242 + name: '重要',
  243 + bgColor: '#F6F6F6',
  244 + textColor: '#F6F6F6'
  245 + },
  246 + {
  247 + index: 4,
  248 + name: '次要',
  249 + bgColor: '#F6F6F6',
  250 + textColor: '#F6F6F6'
  251 + },
  252 + {
  253 + index: 4,
  254 + name: '警告',
  255 + bgColor: '#F6F6F6',
  256 + textColor: '#F6F6F6'
  257 + },
  258 + {
  259 + index: 4,
  260 + name: '不确定',
  261 + bgColor: '#F6F6F6',
  262 + textColor: '#F6F6F6'
  263 + }
  264 + ],
  265 + timeArea: [
  266 + {
  267 + index: 1,
  268 + name: '全部',
  269 + value: '全部',
  270 + bgColor: '#F6F6F6',
  271 + textColor: '#F6F6F6'
  272 + },
  273 + {
  274 + index: 2,
  275 + name: '30分钟',
  276 + value: '30',
  277 + bgColor: '#F6F6F6',
  278 + textColor: '#F6F6F6'
  279 + },
  280 + {
  281 + index: 3,
  282 + name: '1小时',
  283 + value: '30',
  284 + bgColor: '#F6F6F6',
  285 + textColor: '#F6F6F6'
  286 + },
  287 + {
  288 + index: 4,
  289 + name: '2小时',
  290 + value: '120',
  291 + bgColor: '#F6F6F6',
  292 + textColor: '#F6F6F6'
  293 + },
  294 + {
  295 + index: 5,
  296 + name: '近一天',
  297 + value: '24',
  298 + bgColor: '#F6F6F6',
  299 + textColor: '#F6F6F6'
  300 + },
  301 + {
  302 + index: 6,
  303 + name: '',
  304 + value: '',
  305 + bgColor: '#F6F6F6',
  306 + textColor: '#F6F6F6'
  307 + }
  308 + ],
  309 + list: [
  310 + {
  311 + name1: '1号楼1楼三单元水表',
  312 + name2: 'CO₂:65.32',
  313 + name3: '告警状态:清除已确认',
  314 + name4: '../../../static/danger.png',
  315 + name5: '危险',
  316 + time: '2022-04-01 02:12:23',
  317 + id: 'xx1'
  318 + },
  319 + {
  320 + name1: '2号楼1楼三单元水表',
  321 + name2: 'PH:9.8',
  322 + name3: '告警状态:激活未确认',
  323 + name4: '../../../static/major.png',
  324 + name5: '重要',
  325 + time: '2022-04-01 02:12:23',
  326 + id: 'xx2'
  327 + },
  328 + {
  329 + name1: '3号楼1楼三单元水表',
  330 + name2: 'NH3:600',
  331 + name3: '告警状态:激活未确认',
  332 + name4: '../../../static/secondary.png',
  333 + name5: '次要',
  334 + time: '2022-04-01 02:12:23',
  335 + id: 'xx3'
  336 + },
  337 + {
  338 + name1: '4号楼1楼三单元水表',
  339 + name2: '水深:1.4',
  340 + name3: '告警状态:激活未确认',
  341 + name4: '../../../static/secondary.png',
  342 + name5: '次要',
  343 + time: '2022-04-01 02:12:23',
  344 + id: 'xx4'
  345 + },
  346 + {
  347 + name1: '5号楼1楼三单元水表',
  348 + name2: 'COD:125',
  349 + name3: '告警状态:激活未确认',
  350 + name4: '../../../static/noshue.png',
  351 + name5: '不确定',
  352 + time: '2022-04-01 02:12:23',
  353 + id: 'xx5'
  354 + }
  355 + ]
  356 + };
  357 + },
  358 + onLoad(e) {
  359 + // 隐藏原生的tabbar
  360 + uni.hideTabBar();
  361 + },
  362 + methods: {
  363 + open() {},
  364 + close() {
  365 + this.show = false;
  366 + },
  367 + openSearchDialog() {
  368 + this.show = true;
  369 + },
  370 + hideKeyboard() {
  371 + uni.hideKeyboard();
  372 + },
  373 + calendarConfirm(e) {
  374 + this.showCalendar = false;
  375 + this.timeData.selectTime = `${e[0]} / ${e[e.length - 1]}`;
  376 + },
  377 + calendarClose() {
  378 + this.showCalendar = false;
  379 + }
  380 + }
  381 +};
  382 +</script>
  383 +
  384 +<style lang="scss" scoped>
  385 +.alert-page {
  386 + margin-top: -39rpx;
  387 +}
  388 +.device-list {
  389 + display: flex;
  390 + flex-direction: column;
  391 + padding-left: 18rpx;
  392 + margin-top: -18rpx;
  393 + .list-item {
  394 + width: 713rpx;
  395 + height: 233rpx;
  396 + background-color: #fff;
  397 + margin-top: 24rpx;
  398 + display: flex;
  399 +
  400 + border-radius: 10px;
  401 + justify-content: space-between;
  402 + .item {
  403 + margin: 30rpx;
  404 + }
  405 + }
  406 +}
407 </style> 407 </style>
deviceSubPage/deviceDetailPage/tabDetail/basicInfo.vue renamed from pages/device/tabDetail/basicInfo.vue
1 -<template>  
2 - <view class="basic-page">  
3 - <!-- 公共组件-每个页面必须引入 -->  
4 - <public-module />  
5 - <view class="u-flex" style="justify-content: space-between;height: 140rpx;background-color: #fff;border-radius: 18px;">  
6 - <view class="u-flex">  
7 - <view style="margin-left: 20rpx;">  
8 - {{deviceDetail.name}}  
9 - </view>  
10 - <view style="margin-left: 20rpx; font-size: 14px;" :style="{color:deviceDetail.deviceState==='INACTIVE'?'#666':deviceDetail.deviceState==='ONLINE'?'#377DFF':'#DE4437'}">  
11 - {{deviceDetail.deviceState==='INACTIVE'?'未激活':deviceDetail.deviceState==='ONLINE'?'在线':'离线'}}  
12 - </view>  
13 - </view>  
14 - <view style="margin-right: 20rpx;">  
15 - <u-button type="primary" shape="circle" size="mini" text="下发命令" @click="showModal"/>  
16 - </view>  
17 - </view>  
18 - <view style="margin-top: 40rpx;height: 577rpx;background-color: #fff;border-radius: 20px;">  
19 - <u-list>  
20 - <u-list-item>  
21 -  
22 - <u-cell :title="deviceDetail.sn">  
23 - <view slot="icon">设备编号</view>  
24 - </u-cell>  
25 - </u-list-item>  
26 - <u-list-item>  
27 - <u-cell :title="deviceType">  
28 - <view slot="icon">设备类型</view>  
29 - </u-cell>  
30 - </u-list-item>  
31 - <u-list-item>  
32 - <u-cell :title="deviceDetail.organizationDTO.name">  
33 - <view slot="icon">所属组织</view>  
34 - </u-cell>  
35 - </u-list-item>  
36 - <u-list-item>  
37 - <u-cell :title="formatLastOnlineTime">  
38 - <view slot="icon">最后连接时间</view>  
39 - </u-cell>  
40 - </u-list-item>  
41 - <u-list-item>  
42 - <u-cell :title="alarmStatus">  
43 - <view slot="icon">是否告警</view>  
44 - </u-cell>  
45 - </u-list-ite>  
46 - <u-cell :title="deviceDetail.description">  
47 - <view slot="icon">设备描述</view>  
48 - </u-cell>  
49 - </u-list-item>  
50 - </u-list>  
51 - </view>  
52 - <!-- 下发指令 -->  
53 - <u-modal :show="showModel" title="命令下发" closeOnClickOverlay showCancelButton @close="hiddenModal" @cancel="hiddenModal" @confirm="handleConfirm" >  
54 - <u--textarea placeholder="请输入命令内容" v-model="formModel.intro" count />  
55 - </u-modal>  
56 - <f-tabbar />  
57 - </view>  
58 -</template>  
59 -  
60 -<script>  
61 -import {formatToDate} from '@/plugins/utils.js';  
62 -export default {  
63 - props:{  
64 - deviceDetail:{  
65 - type:Object,  
66 - default:()=>({}),  
67 - }  
68 - },  
69 - data() {  
70 - return {  
71 - showModel: false,  
72 - };  
73 - },  
74 - computed:{  
75 - deviceType(){  
76 - return this.deviceDetail.deviceType==='DIRECT_CONNECTION'?'直连设备':this.deviceDetail.deviceType==='GATEWAY'?'网关设备':this.deviceDetail.deviceType==='SENSOR'?'网关子设备':''  
77 - },  
78 - alarmStatus(){  
79 - return this.deviceDetail.alarmStatus === '0'?'否':'是'  
80 - },  
81 - formatLastOnlineTime(){  
82 - return formatToDate(Number(this.deviceDetail.lastOnlineTime),'YYYY-MM-DD HH:mm:ss')  
83 - }  
84 - },  
85 - onLoad(e) {  
86 - // 隐藏原生的tabbar  
87 - uni.hideTabBar();  
88 - },  
89 - onMounted(){  
90 - console.log(this.deviceDetail)  
91 -  
92 - },  
93 - methods: {  
94 - showModal() {  
95 - this.showModel = true;  
96 - },  
97 - hiddenModal(){  
98 - this.showModel = false;  
99 - },  
100 - handleConfirm(){  
101 - console.log('确定')  
102 - }  
103 - }  
104 -};  
105 -</script> 1 +<template>
  2 + <view class="basic-page">
  3 + <!-- 公共组件-每个页面必须引入 -->
  4 + <public-module />
  5 + <view class="u-flex" style="justify-content: space-between;height: 140rpx;background-color: #fff;border-radius: 18px;">
  6 + <view class="u-flex">
  7 + <view style="margin-left: 20rpx;">
  8 + {{deviceDetail.name}}
  9 + </view>
  10 + <view style="margin-left: 20rpx; font-size: 14px;" :style="{color:deviceDetail.deviceState==='INACTIVE'?'#666':deviceDetail.deviceState==='ONLINE'?'#377DFF':'#DE4437'}">
  11 + {{deviceDetail.deviceState==='INACTIVE'?'未激活':deviceDetail.deviceState==='ONLINE'?'在线':'离线'}}
  12 + </view>
  13 + </view>
  14 + <view style="margin-right: 20rpx;">
  15 + <u-button type="primary" shape="circle" size="mini" text="下发命令" @click="showModal"/>
  16 + </view>
  17 + </view>
  18 + <view style="margin-top: 40rpx;height: 577rpx;background-color: #fff;border-radius: 20px;">
  19 + <u-list>
  20 + <u-list-item>
  21 +
  22 + <u-cell :title="deviceDetail.sn">
  23 + <view slot="icon">设备编号</view>
  24 + </u-cell>
  25 + </u-list-item>
  26 + <u-list-item>
  27 + <u-cell :title="deviceType">
  28 + <view slot="icon">设备类型</view>
  29 + </u-cell>
  30 + </u-list-item>
  31 + <u-list-item>
  32 + <u-cell :title="deviceDetail.organizationDTO.name">
  33 + <view slot="icon">所属组织</view>
  34 + </u-cell>
  35 + </u-list-item>
  36 + <u-list-item>
  37 + <u-cell :title="formatLastOnlineTime">
  38 + <view slot="icon">最后连接时间</view>
  39 + </u-cell>
  40 + </u-list-item>
  41 + <u-list-item>
  42 + <u-cell :title="alarmStatus">
  43 + <view slot="icon">是否告警</view>
  44 + </u-cell>
  45 + </u-list-ite>
  46 + <u-cell :title="deviceDetail.description">
  47 + <view slot="icon">设备描述</view>
  48 + </u-cell>
  49 + </u-list-item>
  50 + </u-list>
  51 + </view>
  52 + <!-- 下发指令 -->
  53 + <u-modal :show="showModel" title="命令下发" closeOnClickOverlay showCancelButton @close="hiddenModal" @cancel="hiddenModal" @confirm="handleConfirm" >
  54 + <u--textarea placeholder="请输入命令内容" v-model="formModel.intro" count />
  55 + </u-modal>
  56 + <f-tabbar />
  57 + </view>
  58 +</template>
  59 +
  60 +<script>
  61 +import {formatToDate} from '@/plugins/utils.js';
  62 +export default {
  63 + props:{
  64 + deviceDetail:{
  65 + type:Object,
  66 + default:()=>({}),
  67 + }
  68 + },
  69 + data() {
  70 + return {
  71 + showModel: false,
  72 + };
  73 + },
  74 + computed:{
  75 + deviceType(){
  76 + return this.deviceDetail.deviceType==='DIRECT_CONNECTION'?'直连设备':this.deviceDetail.deviceType==='GATEWAY'?'网关设备':this.deviceDetail.deviceType==='SENSOR'?'网关子设备':''
  77 + },
  78 + alarmStatus(){
  79 + return this.deviceDetail.alarmStatus === '0'?'否':'是'
  80 + },
  81 + formatLastOnlineTime(){
  82 + return formatToDate(Number(this.deviceDetail.lastOnlineTime),'YYYY-MM-DD HH:mm:ss')
  83 + }
  84 + },
  85 + onLoad(e) {
  86 + // 隐藏原生的tabbar
  87 + uni.hideTabBar();
  88 + },
  89 + onMounted(){
  90 + console.log(this.deviceDetail)
  91 +
  92 + },
  93 + methods: {
  94 + showModal() {
  95 + this.showModel = true;
  96 + },
  97 + hiddenModal(){
  98 + this.showModel = false;
  99 + },
  100 + handleConfirm(){
  101 + console.log('确定')
  102 + }
  103 + }
  104 +};
  105 +</script>
deviceSubPage/deviceDetailPage/tabDetail/commondRecord.vue renamed from pages/device/tabDetail/commondRecord.vue
deviceSubPage/deviceDetailPage/tabDetail/historyData.vue renamed from pages/device/tabDetail/historyData.vue
1 -<template>  
2 - <view class="historyData">  
3 - <!-- 公共组件-每个页面必须引入 -->  
4 - <public-module></public-module>  
5 - <view class="historyData-top">  
6 - <u-form :label-style="{ 'font-size': '0rpx' }">  
7 - <u-form-item @click="openCalendar">  
8 - <u-input v-model="timeData.selectTime" disabled disabledColor="#fff" placeholder="请选择日期" border="none">  
9 - <template slot="prefix">  
10 - <image class="icon" src="../../../static/can-der.png"></image>  
11 - </template>  
12 - </u-input>  
13 - </u-form-item>  
14 - <u-form-item @click="openTimeGap">  
15 - <u-input v-model="timeData.getTimeGap" disabled disabledColor="#fff" placeholder="请选择时间区间" border="none">  
16 - <template slot="prefix">  
17 - <image class="icon" src="../../../static/time.png"></image>  
18 - </template>  
19 - </u-input>  
20 - </u-form-item>  
21 - <u-form-item @click="openType"><u-input shape="circle" v-model="timeData.getType" placeholder="请选择属性" disabled disabledColor="#377DFF0D" /></u-form-item>  
22 - </u-form>  
23 - <!-- <qiun-data-charts type="tarea" :chartData="chartData" canvas2d /> -->  
24 - </view>  
25 - <view class="historyData-bottom">  
26 - <view class="table">  
27 - <view class="tr bg-w">  
28 - <view class="th">变量值</view>  
29 - <view class="th">更新时间</view>  
30 - </view>  
31 - <view class="tr bg-g">  
32 - <view class="td">10</view>  
33 - <view class="td">2022-03-01 18:16:33</view>  
34 - </view>  
35 -  
36 - </view>  
37 - </view>  
38 - <u-calendar  
39 - :show="showCalendar"  
40 - closeOnClickOverlay  
41 - mode="range"  
42 - startText="开始时间"  
43 - endText="结束时间"  
44 - confirmDisabledText="请选择日期"  
45 - @confirm="calendarConfirm"  
46 - @close="calendarClose"  
47 - ></u-calendar>  
48 - <u-picker :show="showTimeGap" :columns="columns" keyName="label" closeOnClickOverlay @confirm="confirmTimeGap" @cancel="cancelTimeGap" @close="cancelTimeGap"></u-picker>  
49 - <u-picker :show="showSelectType" :columns="keys" closeOnClickOverlay @confirm="confirmTypeGap" @cancel="cancelTypeGap" @close="cancelTypeGap"></u-picker>  
50 - <f-tabbar></f-tabbar>  
51 - </view>  
52 -</template>  
53 -  
54 -<script>  
55 -import fTabbar from '@/components/module/f-tabbar/f-tabbar';  
56 -import qiunDataCharts from '@/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue';  
57 -import { getDeviceKeys, getHistroyData } from '../api/index.js';  
58 -export default {  
59 - components: {  
60 - fTabbar,  
61 - qiunDataCharts  
62 - },  
63 - props:{  
64 - keys:{  
65 - type:Array,  
66 - default:()=>[]  
67 - }  
68 - },  
69 - data() {  
70 - return {  
71 - showCalendar: false,  
72 - showTimeGap: false,  
73 - showSelectType: false,  
74 - columns: [  
75 - [  
76 - {  
77 - label: '5分钟',  
78 - value: 300  
79 - },  
80 - {  
81 - label: '10分钟',  
82 - value: 600  
83 - },  
84 - {  
85 - label: '15分钟',  
86 - value: 900  
87 - },  
88 - {  
89 - label: '30分钟',  
90 - value: 1800  
91 - },  
92 - {  
93 - label: '1小时',  
94 - value: 3600  
95 - },  
96 - {  
97 - label: '2小时',  
98 - value: 7200  
99 - },  
100 - {  
101 - label: '6小时',  
102 - value: 21600  
103 - }  
104 - ]  
105 - ],  
106 - timeData: {  
107 - selectTime: '',  
108 - getTimeGap: '',  
109 - getType: ''  
110 - }  
111 - };  
112 - },  
113 - methods: {  
114 - openCalendar() {  
115 - this.showCalendar = true;  
116 - },  
117 - openTimeGap() {  
118 - this.showTimeGap = true;  
119 - },  
120 - openType() {  
121 - this.showSelectType = true;  
122 - },  
123 - calendarConfirm(date) {  
124 - this.showCalendar = false;  
125 - this.timeData.selectTime = `${date[0]} 至 ${date[1]}`;  
126 - },  
127 - calendarClose() {  
128 - this.showCalendar = false;  
129 - },  
130 - confirmTimeGap(time) {  
131 - this.showTimeGap = false;  
132 - this.timeData.getTimeGap = time.value[0].label;  
133 - },  
134 -  
135 - cancelTimeGap() {  
136 - this.showTimeGap = false;  
137 - },  
138 - confirmTypeGap(time) {  
139 - this.showSelectType = false;  
140 - this.timeData.getType = time.value[0];  
141 - },  
142 - cancelTypeGap() {  
143 - this.showSelectType = false;  
144 - }  
145 - }  
146 -};  
147 -</script>  
148 -  
149 -<style lang="scss" scoped>  
150 -.historyData {  
151 - margin: 30rpx;  
152 - .historyData-top {  
153 - padding: 30rpx;  
154 - background-color: #fff;  
155 - height: 870rpx;  
156 - border-radius: 20rpx;  
157 - .icon {  
158 - width: 28rpx;  
159 - height: 28rpx;  
160 - margin-right: 15rpx;  
161 - }  
162 - }  
163 - .historyData-bottom {  
164 - margin-top: 30rpx;  
165 - background-color: #fff;  
166 - border-radius: 20rpx;  
167 - .table {  
168 - border: 0px solid darkgray;  
169 - .tr {  
170 - display: flex;  
171 - width: 100%;  
172 - justify-content: center;  
173 - height: 3rem;  
174 - align-items: center;  
175 - .th {  
176 - display: flex;  
177 - justify-content: center;  
178 - align-items: center;  
179 - width: 50%;  
180 - color: #333;  
181 - font-weight: 500;  
182 - }  
183 - .td {  
184 - color: #999;  
185 - width: 50%;  
186 - display: flex;  
187 - justify-content: center;  
188 - text-align: center;  
189 - }  
190 - }  
191 - }  
192 - }  
193 -}  
194 -.odd {  
195 - background-color: #f9fcff;  
196 -} 1 +<template>
  2 + <view class="historyData">
  3 + <!-- 公共组件-每个页面必须引入 -->
  4 + <public-module></public-module>
  5 + <view class="historyData-top">
  6 + <u-form :label-style="{ 'font-size': '0rpx' }">
  7 + <u-form-item @click="openCalendar">
  8 + <u-input v-model="timeData.selectTime" disabled disabledColor="#fff" placeholder="请选择日期" border="none">
  9 + <template slot="prefix">
  10 + <image class="icon" src="../../../static/can-der.png"></image>
  11 + </template>
  12 + </u-input>
  13 + </u-form-item>
  14 + <u-form-item @click="openTimeGap">
  15 + <u-input v-model="timeData.getTimeGap" disabled disabledColor="#fff" placeholder="请选择时间区间" border="none">
  16 + <template slot="prefix">
  17 + <image class="icon" src="../../../static/time.png"></image>
  18 + </template>
  19 + </u-input>
  20 + </u-form-item>
  21 + <u-form-item @click="openType"><u-input shape="circle" v-model="timeData.getType" placeholder="请选择属性" disabled disabledColor="#377DFF0D" /></u-form-item>
  22 + </u-form>
  23 + <!-- <qiun-data-charts type="tarea" :chartData="chartData" canvas2d /> -->
  24 + </view>
  25 + <view class="historyData-bottom">
  26 + <view class="table">
  27 + <view class="tr bg-w">
  28 + <view class="th">变量值</view>
  29 + <view class="th">更新时间</view>
  30 + </view>
  31 + <view class="tr bg-g">
  32 + <view class="td">10</view>
  33 + <view class="td">2022-03-01 18:16:33</view>
  34 + </view>
  35 +
  36 + </view>
  37 + </view>
  38 + <u-calendar
  39 + :show="showCalendar"
  40 + closeOnClickOverlay
  41 + mode="range"
  42 + startText="开始时间"
  43 + endText="结束时间"
  44 + confirmDisabledText="请选择日期"
  45 + @confirm="calendarConfirm"
  46 + @close="calendarClose"
  47 + ></u-calendar>
  48 + <u-picker :show="showTimeGap" :columns="columns" keyName="label" closeOnClickOverlay @confirm="confirmTimeGap" @cancel="cancelTimeGap" @close="cancelTimeGap"></u-picker>
  49 + <u-picker :show="showSelectType" :columns="keys" closeOnClickOverlay @confirm="confirmTypeGap" @cancel="cancelTypeGap" @close="cancelTypeGap"></u-picker>
  50 + <f-tabbar></f-tabbar>
  51 + </view>
  52 +</template>
  53 +
  54 +<script>
  55 +import fTabbar from '@/components/module/f-tabbar/f-tabbar';
  56 +import qiunDataCharts from '@/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue';
  57 +import { getDeviceKeys, getHistroyData } from '../../../pages/device/api/index';
  58 +export default {
  59 + components: {
  60 + fTabbar,
  61 + qiunDataCharts
  62 + },
  63 + props:{
  64 + keys:{
  65 + type:Array,
  66 + default:()=>[]
  67 + }
  68 + },
  69 + data() {
  70 + return {
  71 + showCalendar: false,
  72 + showTimeGap: false,
  73 + showSelectType: false,
  74 + columns: [
  75 + [
  76 + {
  77 + label: '5分钟',
  78 + value: 300
  79 + },
  80 + {
  81 + label: '10分钟',
  82 + value: 600
  83 + },
  84 + {
  85 + label: '15分钟',
  86 + value: 900
  87 + },
  88 + {
  89 + label: '30分钟',
  90 + value: 1800
  91 + },
  92 + {
  93 + label: '1小时',
  94 + value: 3600
  95 + },
  96 + {
  97 + label: '2小时',
  98 + value: 7200
  99 + },
  100 + {
  101 + label: '6小时',
  102 + value: 21600
  103 + }
  104 + ]
  105 + ],
  106 + timeData: {
  107 + selectTime: '',
  108 + getTimeGap: '',
  109 + getType: ''
  110 + }
  111 + };
  112 + },
  113 + methods: {
  114 + openCalendar() {
  115 + this.showCalendar = true;
  116 + },
  117 + openTimeGap() {
  118 + this.showTimeGap = true;
  119 + },
  120 + openType() {
  121 + this.showSelectType = true;
  122 + },
  123 + calendarConfirm(date) {
  124 + this.showCalendar = false;
  125 + this.timeData.selectTime = `${date[0]} 至 ${date[1]}`;
  126 + },
  127 + calendarClose() {
  128 + this.showCalendar = false;
  129 + },
  130 + confirmTimeGap(time) {
  131 + this.showTimeGap = false;
  132 + this.timeData.getTimeGap = time.value[0].label;
  133 + },
  134 +
  135 + cancelTimeGap() {
  136 + this.showTimeGap = false;
  137 + },
  138 + confirmTypeGap(time) {
  139 + this.showSelectType = false;
  140 + this.timeData.getType = time.value[0];
  141 + },
  142 + cancelTypeGap() {
  143 + this.showSelectType = false;
  144 + }
  145 + }
  146 +};
  147 +</script>
  148 +
  149 +<style lang="scss" scoped>
  150 +.historyData {
  151 + margin: 30rpx;
  152 + .historyData-top {
  153 + padding: 30rpx;
  154 + background-color: #fff;
  155 + height: 870rpx;
  156 + border-radius: 20rpx;
  157 + .icon {
  158 + width: 28rpx;
  159 + height: 28rpx;
  160 + margin-right: 15rpx;
  161 + }
  162 + }
  163 + .historyData-bottom {
  164 + margin-top: 30rpx;
  165 + background-color: #fff;
  166 + border-radius: 20rpx;
  167 + .table {
  168 + border: 0px solid darkgray;
  169 + .tr {
  170 + display: flex;
  171 + width: 100%;
  172 + justify-content: center;
  173 + height: 3rem;
  174 + align-items: center;
  175 + .th {
  176 + display: flex;
  177 + justify-content: center;
  178 + align-items: center;
  179 + width: 50%;
  180 + color: #333;
  181 + font-weight: 500;
  182 + }
  183 + .td {
  184 + color: #999;
  185 + width: 50%;
  186 + display: flex;
  187 + justify-content: center;
  188 + text-align: center;
  189 + }
  190 + }
  191 + }
  192 + }
  193 +}
  194 +.odd {
  195 + background-color: #f9fcff;
  196 +}
197 </style> 197 </style>
deviceSubPage/deviceDetailPage/tabDetail/realtimeData.vue renamed from pages/device/tabDetail/realtimeData.vue
feedBackSubPage/feedback/feedback.vue renamed from pages/feedback/feedback.vue
@@ -26,21 +26,6 @@ Vue.use(f_show_modal) @@ -26,21 +26,6 @@ Vue.use(f_show_modal)
26 import uView from '@/uni_modules/uview-ui' 26 import uView from '@/uni_modules/uview-ui'
27 Vue.use(uView) 27 Vue.use(uView)
28 28
29 -// #ifdef MP  
30 -// 引入uView对小程序分享的mixin封装  
31 -const mpShare = require('@/uni_modules/uview-ui/libs/mixin/mpShare.js')  
32 -Vue.mixin(mpShare)  
33 -// #endif  
34 -  
35 -// #ifdef H5  
36 -//微信公众号(分享、扫码、获取位置等)  
37 -import '@/plugins/jwxUtils.js';  
38 -// #endif  
39 -  
40 -// 基于iconfont图标库组件  
41 -// import fIcon from "@/components/module/f-icon/f-icon.vue";  
42 -// Vue.component("f-icon", fIcon);  
43 -  
44 // 公共组件 29 // 公共组件
45 import publicModule from "@/components/common/public-module.vue"; 30 import publicModule from "@/components/common/public-module.vue";
46 Vue.component("public-module", publicModule); 31 Vue.component("public-module", publicModule);
1 { 1 {
2 - "name": "yun-teng-app",  
3 - "appid": "__UNI__C873643",  
4 - "description": "云腾app、小程序",  
5 - "versionName": "1.0.0",  
6 - "versionCode": 100,  
7 - "transformPx": false,  
8 - "app-plus": {  
9 - "usingComponents": true,  
10 - "nvueStyleCompiler": "uni-app",  
11 - "compilerVersion": 3,  
12 - "splashscreen": {  
13 - "alwaysShowBeforeRender": true,  
14 - "waiting": true,  
15 - "autoclose": true,  
16 - "delay": 0  
17 - },  
18 - "modules": {},  
19 - "distribute": {  
20 - "android": {  
21 - "permissions": [  
22 - "<uses-feature android:name=\"android.hardware.camera\"/>",  
23 - "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",  
24 - "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",  
25 - "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",  
26 - "<uses-permission android:name=\"android.permission.CAMERA\"/>",  
27 - "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",  
28 - "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",  
29 - "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",  
30 - "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",  
31 - "<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>",  
32 - "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",  
33 - "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",  
34 - "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",  
35 - "<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>",  
36 - "<uses-permission android:name=\"android.permission.VIBRATE\"/>",  
37 - "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",  
38 - "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"  
39 - ]  
40 - },  
41 - "ios": {},  
42 - "sdkConfigs": {  
43 - "ad": {},  
44 - "geolocation": {  
45 - "system": {  
46 - "__platform__": ["ios", "android"]  
47 - },  
48 - "amap": {  
49 - "__platform__": ["ios", "android"],  
50 - "appkey_ios": "",  
51 - "appkey_android": ""  
52 - }  
53 - },  
54 - "maps": {}  
55 - }  
56 - }  
57 - },  
58 - "quickapp": {},  
59 - "mp-weixin": {  
60 - "appid": "wx0ad61d7bf6808e02",  
61 - "setting": {  
62 - "urlCheck": false,  
63 - "minified": true,  
64 - "es6": true  
65 - },  
66 - "usingComponents": true,  
67 - "permission": {  
68 - "scope.userLocation": {  
69 - "desc": "你的位置信息将用于小程序位置接口的效果展示"  
70 - }  
71 - },  
72 - "lazyCodeLoading": "requiredComponents"  
73 - },  
74 - "mp-alipay": {  
75 - "usingComponents": true  
76 - },  
77 - "mp-baidu": {  
78 - "usingComponents": true  
79 - },  
80 - "mp-toutiao": {  
81 - "usingComponents": true  
82 - },  
83 - "uniStatistics": {  
84 - "enable": false  
85 - },  
86 - "vueVersion": "2",  
87 - "h5": {  
88 - "sdkConfigs": {  
89 - "maps": {}  
90 - },  
91 - "router": {  
92 - "base": "minImage/h5/"  
93 - }  
94 - } 2 + "name" : "yun-teng-app",
  3 + "appid" : "__UNI__C873643",
  4 + "description" : "thingskit小程序",
  5 + "versionName" : "1.0.0",
  6 + "versionCode" : 100,
  7 + "transformPx" : false,
  8 + "app-plus" : {
  9 + "usingComponents" : true,
  10 + "nvueStyleCompiler" : "uni-app",
  11 + "compilerVersion" : 3,
  12 + "splashscreen" : {
  13 + "alwaysShowBeforeRender" : true,
  14 + "waiting" : true,
  15 + "autoclose" : true,
  16 + "delay" : 0
  17 + },
  18 + "modules" : {},
  19 + "distribute" : {
  20 + "android" : {
  21 + "permissions" : [
  22 + "<uses-feature android:name=\"android.hardware.camera\"/>",
  23 + "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
  24 + "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
  25 + "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
  26 + "<uses-permission android:name=\"android.permission.CAMERA\"/>",
  27 + "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
  28 + "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
  29 + "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
  30 + "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
  31 + "<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>",
  32 + "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
  33 + "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
  34 + "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
  35 + "<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>",
  36 + "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
  37 + "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
  38 + "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
  39 + ]
  40 + },
  41 + "ios" : {},
  42 + "sdkConfigs" : {
  43 + "ad" : {},
  44 + "geolocation" : {
  45 + "system" : {
  46 + "__platform__" : [ "ios", "android" ]
  47 + },
  48 + "amap" : {
  49 + "__platform__" : [ "ios", "android" ],
  50 + "appkey_ios" : "",
  51 + "appkey_android" : ""
  52 + }
  53 + },
  54 + "maps" : {}
  55 + }
  56 + }
  57 + },
  58 + "quickapp" : {},
  59 + "mp-weixin" : {
  60 + "appid" : "wxd5d018355f38262b",
  61 + "setting" : {
  62 + "urlCheck" : false,
  63 + "minified" : true,
  64 + "es6" : true,
  65 + "postcss" : true
  66 + },
  67 + "usingComponents" : true,
  68 + "permission" : {
  69 + "scope.userLocation" : {
  70 + "desc" : "你的位置信息将用于小程序位置接口的效果展示"
  71 + }
  72 + },
  73 + "lazyCodeLoading" : "requiredComponents",
  74 + //开启分包优化
  75 + "optimization" : {
  76 + "subPackages" : true
  77 + }
  78 + },
  79 + "mp-alipay" : {
  80 + "usingComponents" : true
  81 + },
  82 + "mp-baidu" : {
  83 + "usingComponents" : true
  84 + },
  85 + "mp-toutiao" : {
  86 + "usingComponents" : true
  87 + },
  88 + "uniStatistics" : {
  89 + "enable" : false
  90 + },
  91 + "vueVersion" : "2",
  92 + "h5" : {
  93 + "sdkConfigs" : {
  94 + "maps" : {}
  95 + },
  96 + "router" : {
  97 + "base" : "minImage/h5/"
  98 + }
  99 + }
95 } 100 }
@@ -4,7 +4,8 @@ @@ -4,7 +4,8 @@
4 "description": "### 项目结构", 4 "description": "### 项目结构",
5 "main": "main.js", 5 "main": "main.js",
6 "scripts": { 6 "scripts": {
7 - "test": "echo \"Error: no test specified\" && exit 1" 7 + "test": "echo \"Error: no test specified\" && exit 1",
  8 + "dev:mp-wenxin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --minimize"
8 }, 9 },
9 "repository": { 10 "repository": {
10 "type": "git", 11 "type": "git",
@@ -14,12 +14,12 @@ @@ -14,12 +14,12 @@
14 "navigationBarTitleText": "设备" 14 "navigationBarTitleText": "设备"
15 } 15 }
16 }, 16 },
17 - {  
18 - "path": "pages/device/deviceDetail",  
19 - "style": {  
20 - "navigationBarTitleText": "设备详情"  
21 - }  
22 - }, 17 + // {
  18 + // "path": "pages/device/deviceDetail",
  19 + // "style": {
  20 + // "navigationBarTitleText": "设备详情"
  21 + // }
  22 + // },
23 { 23 {
24 "path": "pages/device/org/org", 24 "path": "pages/device/org/org",
25 "style": { 25 "style": {
@@ -33,9 +33,9 @@ @@ -33,9 +33,9 @@
33 } 33 }
34 }, 34 },
35 { 35 {
36 - "path": "pages/alarm/alarmDetail", 36 + "path": "pages/alarm/org/org",
37 "style": { 37 "style": {
38 - "navigationBarTitleText": "告警详情" 38 + "navigationBarTitleText": "组织筛选"
39 } 39 }
40 }, 40 },
41 { 41 {
@@ -43,44 +43,8 @@ @@ -43,44 +43,8 @@
43 "style": { 43 "style": {
44 "navigationBarTitleText": "个人中心" 44 "navigationBarTitleText": "个人中心"
45 } 45 }
46 - }, {  
47 - "path": "pages/personal/code",  
48 - "style": {  
49 - "navigationBarTitleText": "验证码登录"  
50 - }  
51 -  
52 - }, {  
53 - "path": "pages/personal/findPassword",  
54 - "style": {  
55 - "navigationBarTitleText": "找回密码"  
56 - }  
57 -  
58 - }, {  
59 - "path": "pages/personal/set",  
60 - "style": {  
61 - "navigationBarTitleText": "个人资料"  
62 - }  
63 -  
64 - }, {  
65 - "path": "pages/systemNotify/systemNotify",  
66 - "style": {  
67 - "navigationBarTitleText": "通知列表"  
68 - }  
69 }, 46 },
70 { 47 {
71 - "path": "pages/systemNotify/notifyDetail",  
72 - "style": {  
73 - "navigationBarTitleText": "通知详情"  
74 - }  
75 - }, {  
76 - "path": "pages/feedback/feedback",  
77 - "style": {  
78 - "navigationBarTitleText": "意见反馈",  
79 - "app-plus": {  
80 - "scrollIndicator": "none"  
81 - }  
82 - }  
83 - }, {  
84 "path": "pages/index/camera/camera", 48 "path": "pages/index/camera/camera",
85 "style": { 49 "style": {
86 "navigationBarTitleText": "查看摄像头" 50 "navigationBarTitleText": "查看摄像头"
@@ -98,33 +62,86 @@ @@ -98,33 +62,86 @@
98 } 62 }
99 63
100 }, 64 },
101 -  
102 { 65 {
103 "path": "pages/index/configuration/configurationDetail", 66 "path": "pages/index/configuration/configurationDetail",
104 "style": { 67 "style": {
105 "navigationBarTitleText": "组态详情" 68 "navigationBarTitleText": "组态详情"
106 } 69 }
107 - 70 + }
  71 + ],
  72 + "subPackages": [{
  73 + "root": "alarmSubPage",
  74 + "pages": [{
  75 + "path": "alarmDetailPage/alarmDetail",
  76 + "style": {
  77 + "navigationBarTitleText": "告警详情"
  78 + }
  79 + }]
108 }, 80 },
109 { 81 {
110 - "path": "pages/alarm/org/org",  
111 - "style": {  
112 - "navigationBarTitleText": "组织筛选"  
113 - }  
114 - 82 + "root": "deviceSubPage",
  83 + "pages": [{
  84 + "path": "deviceDetailPage/deviceDetail",
  85 + "style": {
  86 + "navigationBarTitleText": "设备详情"
  87 + }
  88 + }]
115 }, 89 },
116 { 90 {
117 - "path": "pages/public/login",  
118 - "style": {  
119 - "navigationBarTitleText": "登录"  
120 - }  
121 - 91 + "root": "sysNotifySubPage",
  92 + "pages": [{
  93 + "path": "sysNotifyPage/systemNotify",
  94 + "style": {
  95 + "navigationBarTitleText": "系统通知"
  96 + }
  97 + },
  98 + {
  99 + "path": "sysNotifyPage/notifyDetail",
  100 + "style": {
  101 + "navigationBarTitleText": "通知详情"
  102 + }
  103 + }
  104 + ]
  105 + },
  106 + {
  107 + "root": "feedBackSubPage",
  108 + "pages": [{
  109 + "path": "feedback/feedback",
  110 + "style": {
  111 + "navigationBarTitleText": "意见反馈"
  112 + }
  113 + }]
  114 + },
  115 + {
  116 + "root": "publicLoginSubPage",
  117 + "pages": [{
  118 + "path": "public/login",
  119 + "style": {
  120 + "navigationBarTitleText": "登录"
  121 + }
  122 + },
  123 + {
  124 + "path": "other/set",
  125 + "style": {
  126 + "navigationBarTitleText": "个人资料"
  127 + }
  128 + },
  129 + {
  130 + "path": "other/code",
  131 + "style": {
  132 + "navigationBarTitleText": "验证码登录"
  133 + }
  134 + },
  135 + {
  136 + "path": "other/findPassword",
  137 + "style": {
  138 + "navigationBarTitleText": "忘记密码"
  139 + }
  140 + }
  141 + ]
122 } 142 }
123 ], 143 ],
124 "globalStyle": { 144 "globalStyle": {
125 - "mp-alipay": {  
126 - "allowsBounceVertical": "NO"  
127 - },  
128 "navigationBarTextStyle": "black", 145 "navigationBarTextStyle": "black",
129 "navigationBarTitleText": "云腾app", 146 "navigationBarTitleText": "云腾app",
130 "navigationBarBackgroundColor": "#FFFFFF", 147 "navigationBarBackgroundColor": "#FFFFFF",
@@ -427,7 +427,8 @@ export default { @@ -427,7 +427,8 @@ export default {
427 status: e.status 427 status: e.status
428 }; 428 };
429 uni.navigateTo({ 429 uni.navigateTo({
430 - url: './alarmDetail?data=' + JSON.stringify(obj) 430 + url:'/alarmSubPage/alarmDetailPage/alarmDetail?data='+JSON.stringify(obj)
  431 + // url: '/' + JSON.stringify(obj)
431 }); 432 });
432 } 433 }
433 } 434 }
@@ -225,7 +225,7 @@ export default { @@ -225,7 +225,7 @@ export default {
225 }, 225 },
226 openDeviceDetail(id, alarmStatus, lastOnlineTime,tbDeviceId) { 226 openDeviceDetail(id, alarmStatus, lastOnlineTime,tbDeviceId) {
227 uni.navigateTo({ 227 uni.navigateTo({
228 - url: `deviceDetail?id=${id}&alarmStatus=${alarmStatus}&lastOnlineTime=${lastOnlineTime}&tbDeviceId=${tbDeviceId}` 228 + url: `/deviceSubPage/deviceDetailPage/deviceDetail?id=${id}&alarmStatus=${alarmStatus}&lastOnlineTime=${lastOnlineTime}&tbDeviceId=${tbDeviceId}`
229 }); 229 });
230 }, 230 },
231 handleClickTag(currentIndex, list) { 231 handleClickTag(currentIndex, list) {
@@ -296,4 +296,4 @@ export default { @@ -296,4 +296,4 @@ export default {
296 } 296 }
297 } 297 }
298 } 298 }
299 -</style> 299 +</style>
@@ -102,7 +102,7 @@ export default { @@ -102,7 +102,7 @@ export default {
102 uni.$u.http.get('/yt/video', { params: httpData, custom: { load: false } }).then(res => { 102 uni.$u.http.get('/yt/video', { params: httpData, custom: { load: false } }).then(res => {
103 if (res) { 103 if (res) {
104 console.log('Video', res); 104 console.log('Video', res);
105 - // this.list = res.items; 105 + this.list = res.items;
106 } 106 }
107 }); 107 });
108 }, 108 },
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 <!-- 登录 --> 7 <!-- 登录 -->
8 <view class="u-flex u-p-l-30 u-p-r-20 u-p-t-75 u-p-b-30"> 8 <view class="u-flex u-p-l-30 u-p-r-20 u-p-t-75 u-p-b-30">
9 <block v-if="userInfo.isToken"> 9 <block v-if="userInfo.isToken">
10 - <view @click="openPersonalInfo" class="u-m-r-20"><image class="avatar" mode="aspectFill" :src="userInfo.avatar || '../../static/default-avatar.png'"></image></view> 10 + <view @click="openPersonalInfo" class="u-m-r-20"><image class="avatar" mode="aspectFill" :src="userInfo.avatar"></image></view>
11 <view @click="openPersonalInfo" class="u-flex-1"> 11 <view @click="openPersonalInfo" class="u-flex-1">
12 <view class="nickName u-flex"> 12 <view class="nickName u-flex">
13 <view class="name u-m-r-10" v-if="userInfo.realName"> 13 <view class="name u-m-r-10" v-if="userInfo.realName">
@@ -34,7 +34,7 @@ @@ -34,7 +34,7 @@
34 <!-- 登录 --> 34 <!-- 登录 -->
35 <view class="u-flex u-p-l-30 u-p-r-20 u-p-t-75 u-p-b-30"> 35 <view class="u-flex u-p-l-30 u-p-r-20 u-p-t-75 u-p-b-30">
36 <block v-if="userInfo.isToken"> 36 <block v-if="userInfo.isToken">
37 - <view @click="openPersonalInfo" class="u-m-r-20"><image class="avatar" mode="aspectFill" :src="userInfo.avatar||'../../static/default-avatar.png'"></image></view> 37 + <view @click="openPersonalInfo" class="u-m-r-20"><image class="avatar" mode="aspectFill" :src="userInfo.avatar"></image></view>
38 <view @click="openPersonalInfo" class="u-flex-1"> 38 <view @click="openPersonalInfo" class="u-flex-1">
39 <view class="nickName u-flex"> 39 <view class="nickName u-flex">
40 <view class="name u-m-r-10" v-if="userInfo.realName"> 40 <view class="name u-m-r-10" v-if="userInfo.realName">
@@ -60,12 +60,12 @@ @@ -60,12 +60,12 @@
60 </view> 60 </view>
61 <view class="u-flex my-nav"> 61 <view class="u-flex my-nav">
62 <view class="nav-main"> 62 <view class="nav-main">
63 - <view @click="onTokenJump('../systemNotify/systemNotify')" class="u-flex nav-link"> 63 + <view @click="onTokenJump('/sysNotifySubPage/sysNotifyPage/systemNotify')" class="u-flex nav-link">
64 <view class="nav-image"><image class="image" src="../../static/sys-not.png"></image></view> 64 <view class="nav-image"><image class="image" src="../../static/sys-not.png"></image></view>
65 <view class="nav-center"><text class="text">系统通知</text></view> 65 <view class="nav-center"><text class="text">系统通知</text></view>
66 <view class="nav-right"><image class="image" src="../../static/arrow-right.png"></image></view> 66 <view class="nav-right"><image class="image" src="../../static/arrow-right.png"></image></view>
67 </view> 67 </view>
68 - <view @click="onTokenJump('../feedback/feedback')" class="u-flex nav-link"> 68 + <view @click="onTokenJump('/feedBackSubPage/feedback/feedback')" class="u-flex nav-link">
69 <view class="nav-image"><image class="image" src="../../static/find-sugg.png"></image></view> 69 <view class="nav-image"><image class="image" src="../../static/find-sugg.png"></image></view>
70 <view class="nav-center"><text class="text">意见反馈</text></view> 70 <view class="nav-center"><text class="text">意见反馈</text></view>
71 <view class="nav-right"><image class="image" src="../../static/arrow-right.png"></image></view> 71 <view class="nav-right"><image class="image" src="../../static/arrow-right.png"></image></view>
@@ -173,18 +173,6 @@ export default { @@ -173,18 +173,6 @@ export default {
173 title: '绑定账号', 173 title: '绑定账号',
174 systemInfo: base.systemInfo, 174 systemInfo: base.systemInfo,
175 PrimaryButtonColor: '#0079fe', //主题色 175 PrimaryButtonColor: '#0079fe', //主题色
176 - list: [  
177 - {  
178 - title: '系统通知',  
179 - url: '../systemNotify/systemNotify',  
180 - icon: 'setting-fill'  
181 - },  
182 - {  
183 - title: '意见反馈',  
184 - url: '../feedback/feedback',  
185 - icon: 'more-circle-fill'  
186 - }  
187 - ]  
188 }; 176 };
189 }, 177 },
190 onLoad() { 178 onLoad() {
@@ -204,16 +192,6 @@ export default { @@ -204,16 +192,6 @@ export default {
204 }); 192 });
205 }); 193 });
206 }, 194 },
207 - // openSysNotify() {  
208 - // uni.navigateTo({  
209 - // url: '../systemNotify/systemNotify'  
210 - // });  
211 - // },  
212 - // openFeedBack() {  
213 - // uni.navigateTo({  
214 - // url: '../feedback/feedback'  
215 - // });  
216 - // },  
217 onJump(url) { 195 onJump(url) {
218 uni.navigateTo({ 196 uni.navigateTo({
219 url: url 197 url: url
@@ -221,7 +199,7 @@ export default { @@ -221,7 +199,7 @@ export default {
221 }, 199 },
222 openLoginFunc() { 200 openLoginFunc() {
223 uni.navigateTo({ 201 uni.navigateTo({
224 - url: '../public/login' 202 + url: '/publicLoginSubPage/public/login'
225 }); 203 });
226 }, 204 },
227 openPersonalInfo() { 205 openPersonalInfo() {
@@ -229,7 +207,7 @@ export default { @@ -229,7 +207,7 @@ export default {
229 data: this.userInfo 207 data: this.userInfo
230 }; 208 };
231 uni.navigateTo({ 209 uni.navigateTo({
232 - url: './set?data=' + JSON.stringify(obj) 210 + url: '/publicLoginSubPage/other/set?data=' + JSON.stringify(obj)
233 }); 211 });
234 }, 212 },
235 clickAccountFunc() { 213 clickAccountFunc() {
@@ -306,7 +284,7 @@ export default { @@ -306,7 +284,7 @@ export default {
306 that.showLogout = false; 284 that.showLogout = false;
307 setTimeout(() => { 285 setTimeout(() => {
308 uni.navigateTo({ 286 uni.navigateTo({
309 - url: '../public/login' 287 + url: '/publicLoginSubPage/public/login'
310 }); 288 });
311 }, 500); 289 }, 500);
312 } else if (res.cancel) { 290 } else if (res.cancel) {
1 -!function(e,n){"function"==typeof define&&(define.amd||define.cmd)?define(function(){return n(e)}):n(e,!0)}(this,function(e,n){function i(n,i,t){e.WeixinJSBridge?WeixinJSBridge.invoke(n,o(i),function(e){c(n,e,t)}):u(n,t)}function t(n,i,t){e.WeixinJSBridge?WeixinJSBridge.on(n,function(e){t&&t.trigger&&t.trigger(e),c(n,e,i)}):t?u(n,t):u(n,i)}function o(e){return e=e||{},e.appId=C.appId,e.verifyAppId=C.appId,e.verifySignType="sha1",e.verifyTimestamp=C.timestamp+"",e.verifyNonceStr=C.nonceStr,e.verifySignature=C.signature,e}function r(e){return{timeStamp:e.timestamp+"",nonceStr:e.nonceStr,package:e.package,paySign:e.paySign,signType:e.signType||"SHA1"}}function a(e){return e.postalCode=e.addressPostalCode,delete e.addressPostalCode,e.provinceName=e.proviceFirstStageName,delete e.proviceFirstStageName,e.cityName=e.addressCitySecondStageName,delete e.addressCitySecondStageName,e.countryName=e.addressCountiesThirdStageName,delete e.addressCountiesThirdStageName,e.detailInfo=e.addressDetailInfo,delete e.addressDetailInfo,e}function c(e,n,i){"openEnterpriseChat"==e&&(n.errCode=n.err_code),delete n.err_code,delete n.err_desc,delete n.err_detail;var t=n.errMsg;t||(t=n.err_msg,delete n.err_msg,t=s(e,t),n.errMsg=t),(i=i||{})._complete&&(i._complete(n),delete i._complete),t=n.errMsg||"",C.debug&&!i.isInnerInvoke&&alert(JSON.stringify(n));var o=t.indexOf(":");switch(t.substring(o+1)){case"ok":i.success&&i.success(n);break;case"cancel":i.cancel&&i.cancel(n);break;default:i.fail&&i.fail(n)}i.complete&&i.complete(n)}function s(e,n){var i=e,t=v[i];t&&(i=t);var o="ok";if(n){var r=n.indexOf(":");"confirm"==(o=n.substring(r+1))&&(o="ok"),"failed"==o&&(o="fail"),-1!=o.indexOf("failed_")&&(o=o.substring(7)),-1!=o.indexOf("fail_")&&(o=o.substring(5)),"access denied"!=(o=(o=o.replace(/_/g," ")).toLowerCase())&&"no permission to execute"!=o||(o="permission denied"),"config"==i&&"function not exist"==o&&(o="ok"),""==o&&(o="fail")}return n=i+":"+o}function d(e){if(e){for(var n=0,i=e.length;n<i;++n){var t=e[n],o=h[t];o&&(e[n]=o)}return e}}function u(e,n){if(!(!C.debug||n&&n.isInnerInvoke)){var i=v[e];i&&(e=i),n&&n._complete&&delete n._complete,console.log('"'+e+'",',n||"")}}function l(e){if(!(k||w||C.debug||x<"6.0.2"||V.systemType<0)){var n=new Image;V.appId=C.appId,V.initTime=A.initEndTime-A.initStartTime,V.preVerifyTime=A.preVerifyEndTime-A.preVerifyStartTime,N.getNetworkType({isInnerInvoke:!0,success:function(e){V.networkType=e.networkType;var i="https://open.weixin.qq.com/sdk/report?v="+V.version+"&o="+V.isPreVerifyOk+"&s="+V.systemType+"&c="+V.clientVersion+"&a="+V.appId+"&n="+V.networkType+"&i="+V.initTime+"&p="+V.preVerifyTime+"&u="+V.url;n.src=i}})}}function p(){return(new Date).getTime()}function f(n){T&&(e.WeixinJSBridge?n():S.addEventListener&&S.addEventListener("WeixinJSBridgeReady",n,!1))}function m(){N.invoke||(N.invoke=function(n,i,t){e.WeixinJSBridge&&WeixinJSBridge.invoke(n,o(i),t)},N.on=function(n,i){e.WeixinJSBridge&&WeixinJSBridge.on(n,i)})}function g(e){if("string"==typeof e&&e.length>0){var n=e.split("?")[0],i=e.split("?")[1];return n+=".html",void 0!==i?n+"?"+i:n}}if(!e.jWeixin){var h={config:"preVerifyJSAPI",onMenuShareTimeline:"menu:share:timeline",onMenuShareAppMessage:"menu:share:appmessage",onMenuShareQQ:"menu:share:qq",onMenuShareWeibo:"menu:share:weiboApp",onMenuShareQZone:"menu:share:QZone",previewImage:"imagePreview",getLocation:"geoLocation",openProductSpecificView:"openProductViewWithPid",addCard:"batchAddCard",openCard:"batchViewCard",chooseWXPay:"getBrandWCPayRequest",openEnterpriseRedPacket:"getRecevieBizHongBaoRequest",startSearchBeacons:"startMonitoringBeacons",stopSearchBeacons:"stopMonitoringBeacons",onSearchBeacons:"onBeaconsInRange",consumeAndShareCard:"consumedShareCard",openAddress:"editAddress"},v=function(){var e={};for(var n in h)e[h[n]]=n;return e}(),S=e.document,I=S.title,y=navigator.userAgent.toLowerCase(),_=navigator.platform.toLowerCase(),k=!(!_.match("mac")&&!_.match("win")),w=-1!=y.indexOf("wxdebugger"),T=-1!=y.indexOf("micromessenger"),M=-1!=y.indexOf("android"),P=-1!=y.indexOf("iphone")||-1!=y.indexOf("ipad"),x=function(){var e=y.match(/micromessenger\/(\d+\.\d+\.\d+)/)||y.match(/micromessenger\/(\d+\.\d+)/);return e?e[1]:""}(),A={initStartTime:p(),initEndTime:0,preVerifyStartTime:0,preVerifyEndTime:0},V={version:1,appId:"",initTime:0,preVerifyTime:0,networkType:"",isPreVerifyOk:1,systemType:P?1:M?2:-1,clientVersion:x,url:encodeURIComponent(location.href)},C={},L={_completes:[]},B={state:0,data:{}};f(function(){A.initEndTime=p()});var O=!1,E=[],N={config:function(e){C=e,u("config",e);var n=!1!==C.check;f(function(){if(n)i(h.config,{verifyJsApiList:d(C.jsApiList)},function(){L._complete=function(e){A.preVerifyEndTime=p(),B.state=1,B.data=e},L.success=function(e){V.isPreVerifyOk=0},L.fail=function(e){L._fail?L._fail(e):B.state=-1};var e=L._completes;return e.push(function(){l()}),L.complete=function(n){for(var i=0,t=e.length;i<t;++i)e[i]();L._completes=[]},L}()),A.preVerifyStartTime=p();else{B.state=1;for(var e=L._completes,t=0,o=e.length;t<o;++t)e[t]();L._completes=[]}}),m()},ready:function(e){0!=B.state?e():(L._completes.push(e),!T&&C.debug&&e())},error:function(e){x<"6.0.2"||(-1==B.state?e(B.data):L._fail=e)},checkJsApi:function(e){var n=function(e){var n=e.checkResult;for(var i in n){var t=v[i];t&&(n[t]=n[i],delete n[i])}return e};i("checkJsApi",{jsApiList:d(e.jsApiList)},(e._complete=function(e){if(M){var i=e.checkResult;i&&(e.checkResult=JSON.parse(i))}e=n(e)},e))},onMenuShareTimeline:function(e){t(h.onMenuShareTimeline,{complete:function(){i("shareTimeline",{title:e.title||I,desc:e.title||I,img_url:e.imgUrl||"",link:e.link||location.href,type:e.type||"link",data_url:e.dataUrl||""},e)}},e)},onMenuShareAppMessage:function(e){t(h.onMenuShareAppMessage,{complete:function(n){"favorite"===n.scene?i("sendAppMessage",{title:e.title||I,desc:e.desc||"",link:e.link||location.href,img_url:e.imgUrl||"",type:e.type||"link",data_url:e.dataUrl||""}):i("sendAppMessage",{title:e.title||I,desc:e.desc||"",link:e.link||location.href,img_url:e.imgUrl||"",type:e.type||"link",data_url:e.dataUrl||""},e)}},e)},onMenuShareQQ:function(e){t(h.onMenuShareQQ,{complete:function(){i("shareQQ",{title:e.title||I,desc:e.desc||"",img_url:e.imgUrl||"",link:e.link||location.href},e)}},e)},onMenuShareWeibo:function(e){t(h.onMenuShareWeibo,{complete:function(){i("shareWeiboApp",{title:e.title||I,desc:e.desc||"",img_url:e.imgUrl||"",link:e.link||location.href},e)}},e)},onMenuShareQZone:function(e){t(h.onMenuShareQZone,{complete:function(){i("shareQZone",{title:e.title||I,desc:e.desc||"",img_url:e.imgUrl||"",link:e.link||location.href},e)}},e)},updateTimelineShareData:function(e){i("updateTimelineShareData",{title:e.title,link:e.link,imgUrl:e.imgUrl},e)},updateAppMessageShareData:function(e){i("updateAppMessageShareData",{title:e.title,desc:e.desc,link:e.link,imgUrl:e.imgUrl},e)},startRecord:function(e){i("startRecord",{},e)},stopRecord:function(e){i("stopRecord",{},e)},onVoiceRecordEnd:function(e){t("onVoiceRecordEnd",e)},playVoice:function(e){i("playVoice",{localId:e.localId},e)},pauseVoice:function(e){i("pauseVoice",{localId:e.localId},e)},stopVoice:function(e){i("stopVoice",{localId:e.localId},e)},onVoicePlayEnd:function(e){t("onVoicePlayEnd",e)},uploadVoice:function(e){i("uploadVoice",{localId:e.localId,isShowProgressTips:0==e.isShowProgressTips?0:1},e)},downloadVoice:function(e){i("downloadVoice",{serverId:e.serverId,isShowProgressTips:0==e.isShowProgressTips?0:1},e)},translateVoice:function(e){i("translateVoice",{localId:e.localId,isShowProgressTips:0==e.isShowProgressTips?0:1},e)},chooseImage:function(e){i("chooseImage",{scene:"1|2",count:e.count||9,sizeType:e.sizeType||["original","compressed"],sourceType:e.sourceType||["album","camera"]},(e._complete=function(e){if(M){var n=e.localIds;try{n&&(e.localIds=JSON.parse(n))}catch(e){}}},e))},getLocation:function(e){},previewImage:function(e){i(h.previewImage,{current:e.current,urls:e.urls},e)},uploadImage:function(e){i("uploadImage",{localId:e.localId,isShowProgressTips:0==e.isShowProgressTips?0:1},e)},downloadImage:function(e){i("downloadImage",{serverId:e.serverId,isShowProgressTips:0==e.isShowProgressTips?0:1},e)},getLocalImgData:function(e){!1===O?(O=!0,i("getLocalImgData",{localId:e.localId},(e._complete=function(e){if(O=!1,E.length>0){var n=E.shift();wx.getLocalImgData(n)}},e))):E.push(e)},getNetworkType:function(e){var n=function(e){var n=e.errMsg;e.errMsg="getNetworkType:ok";var i=e.subtype;if(delete e.subtype,i)e.networkType=i;else{var t=n.indexOf(":"),o=n.substring(t+1);switch(o){case"wifi":case"edge":case"wwan":e.networkType=o;break;default:e.errMsg="getNetworkType:fail"}}return e};i("getNetworkType",{},(e._complete=function(e){e=n(e)},e))},openLocation:function(e){i("openLocation",{latitude:e.latitude,longitude:e.longitude,name:e.name||"",address:e.address||"",scale:e.scale||28,infoUrl:e.infoUrl||""},e)},getLocation:function(e){e=e||{},i(h.getLocation,{type:e.type||"wgs84"},(e._complete=function(e){delete e.type},e))},hideOptionMenu:function(e){i("hideOptionMenu",{},e)},showOptionMenu:function(e){i("showOptionMenu",{},e)},closeWindow:function(e){i("closeWindow",{},e=e||{})},hideMenuItems:function(e){i("hideMenuItems",{menuList:e.menuList},e)},showMenuItems:function(e){i("showMenuItems",{menuList:e.menuList},e)},hideAllNonBaseMenuItem:function(e){i("hideAllNonBaseMenuItem",{},e)},showAllNonBaseMenuItem:function(e){i("showAllNonBaseMenuItem",{},e)},scanQRCode:function(e){i("scanQRCode",{needResult:(e=e||{}).needResult||0,scanType:e.scanType||["qrCode","barCode"]},(e._complete=function(e){if(P){var n=e.resultStr;if(n){var i=JSON.parse(n);e.resultStr=i&&i.scan_code&&i.scan_code.scan_result}}},e))},openAddress:function(e){i(h.openAddress,{},(e._complete=function(e){e=a(e)},e))},openProductSpecificView:function(e){i(h.openProductSpecificView,{pid:e.productId,view_type:e.viewType||0,ext_info:e.extInfo},e)},addCard:function(e){for(var n=e.cardList,t=[],o=0,r=n.length;o<r;++o){var a=n[o],c={card_id:a.cardId,card_ext:a.cardExt};t.push(c)}i(h.addCard,{card_list:t},(e._complete=function(e){var n=e.card_list;if(n){for(var i=0,t=(n=JSON.parse(n)).length;i<t;++i){var o=n[i];o.cardId=o.card_id,o.cardExt=o.card_ext,o.isSuccess=!!o.is_succ,delete o.card_id,delete o.card_ext,delete o.is_succ}e.cardList=n,delete e.card_list}},e))},chooseCard:function(e){i("chooseCard",{app_id:C.appId,location_id:e.shopId||"",sign_type:e.signType||"SHA1",card_id:e.cardId||"",card_type:e.cardType||"",card_sign:e.cardSign,time_stamp:e.timestamp+"",nonce_str:e.nonceStr},(e._complete=function(e){e.cardList=e.choose_card_info,delete e.choose_card_info},e))},openCard:function(e){for(var n=e.cardList,t=[],o=0,r=n.length;o<r;++o){var a=n[o],c={card_id:a.cardId,code:a.code};t.push(c)}i(h.openCard,{card_list:t},e)},consumeAndShareCard:function(e){i(h.consumeAndShareCard,{consumedCardId:e.cardId,consumedCode:e.code},e)},chooseWXPay:function(e){i(h.chooseWXPay,r(e),e)},openEnterpriseRedPacket:function(e){i(h.openEnterpriseRedPacket,r(e),e)},startSearchBeacons:function(e){i(h.startSearchBeacons,{ticket:e.ticket},e)},stopSearchBeacons:function(e){i(h.stopSearchBeacons,{},e)},onSearchBeacons:function(e){t(h.onSearchBeacons,e)},openEnterpriseChat:function(e){i("openEnterpriseChat",{useridlist:e.userIds,chatname:e.groupName},e)},launchMiniProgram:function(e){i("launchMiniProgram",{targetAppId:e.targetAppId,path:g(e.path),envVersion:e.envVersion},e)},miniProgram:{navigateBack:function(e){e=e||{},f(function(){i("invokeMiniProgramAPI",{name:"navigateBack",arg:{delta:e.delta||1}},e)})},navigateTo:function(e){f(function(){i("invokeMiniProgramAPI",{name:"navigateTo",arg:{url:e.url}},e)})},redirectTo:function(e){f(function(){i("invokeMiniProgramAPI",{name:"redirectTo",arg:{url:e.url}},e)})},switchTab:function(e){f(function(){i("invokeMiniProgramAPI",{name:"switchTab",arg:{url:e.url}},e)})},reLaunch:function(e){f(function(){i("invokeMiniProgramAPI",{name:"reLaunch",arg:{url:e.url}},e)})},postMessage:function(e){f(function(){i("invokeMiniProgramAPI",{name:"postMessage",arg:e.data||{}},e)})},getEnv:function(n){f(function(){n({miniprogram:"miniprogram"===e.__wxjs_environment})})}}},b=1,R={};return S.addEventListener("error",function(e){if(!M){var n=e.target,i=n.tagName,t=n.src;if(("IMG"==i||"VIDEO"==i||"AUDIO"==i||"SOURCE"==i)&&-1!=t.indexOf("wxlocalresource://")){e.preventDefault(),e.stopPropagation();var o=n["wx-id"];if(o||(o=b++,n["wx-id"]=o),R[o])return;R[o]=!0,wx.ready(function(){wx.getLocalImgData({localId:t,success:function(e){n.src=e.localData}})})}}},!0),S.addEventListener("load",function(e){if(!M){var n=e.target,i=n.tagName;n.src;if("IMG"==i||"VIDEO"==i||"AUDIO"==i||"SOURCE"==i){var t=n["wx-id"];t&&(R[t]=!1)}}},!0),n&&(e.wx=e.jWeixin=N),N}});  
1 -// 获取微信公众号SDK权限  
2 -import base from '@/config/baseUrl';  
3 -import { isWechat } from '@/config/h5Utils';  
4 -  
5 -//获取地理位置  
6 -export const getLocation = () => {  
7 - return new Promise((resolve, reject) => {  
8 - jWeixin.ready(function () {  
9 - jWeixin.getLocation({  
10 - type: 'gcj02',  
11 - success: function (res) {  
12 - resolve(res);  
13 - },  
14 - fail: (err) => {  
15 - reject(err);  
16 - }  
17 - });  
18 - });  
19 - });  
20 -}  
21 -export const shareData = (info) => {  
22 - let item = {  
23 - title: info.title || base.share.title, // 分享标题  
24 - desc: info.desc || base.share.desc, // 分享描述  
25 - imgUrl: info.imgUrl || base.share.imgUrl, // 分享链接  
26 - link: info.link || base.share.link, // 分享图标  
27 - }  
28 - return item  
29 -}  
30 -//设置分享信息  
31 -export const setShare = (data, callback) => {  
32 - //配置校验成功后执行  
33 - jWeixin.ready(function () {  
34 - if (!data.link) {  
35 - let url = window.location.href;  
36 - let index = url.indexOf("?");  
37 - if (index != -1) {  
38 - if (url.indexOf("#") != -1 && url.indexOf("#") > index) {  
39 - url = url.substring(0, index) + url.substring(url.indexOf("#"));  
40 - } else {  
41 - url = url.substr(0, index);  
42 - }  
43 - }  
44 - data.link = url;  
45 - }  
46 - jWeixin.updateAppMessageShareData(shareData(data));  
47 - jWeixin.updateTimelineShareData(shareData(data));  
48 - });  
49 -}  
50 -//微信扫一扫  
51 -export const scanQRCode = ( callback,needResult = 0) => {  
52 - //配置校验成功后执行  
53 - jWeixin.ready(function () {  
54 - jWeixin.scanQRCode({  
55 - needResult: needResult, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,  
56 - scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有  
57 - success: function (res) {  
58 - callback && callback(res);  
59 - }  
60 - });  
61 - });  
62 -}  
63 -//获取微信JSSDK授权  
64 -window.onload = function () {  
65 - // 需配置公众号appId  
66 - if (!(base.publicAppId && isWechat())) {  
67 - return;  
68 - }  
69 - //获取当前页面地址  
70 - let url = window.location.href;  
71 - url = url.substring(0, url.indexOf("#"));  
72 - //获取微信公众号SDK权限的签名、随机数、时间戳  
73 - uni.$u.http.post("api/jWeixinConfig", {  
74 - url: url  
75 - }).then(res => {  
76 - // 微信SDK配置  
77 - jWeixin.config({  
78 - debug: false,  
79 - appId: base.publicAppId, // 必填,公众号的唯一标识  
80 - timestamp: res.timestamp, // 必填,生成签名的时间戳  
81 - nonceStr: res.noncestr, // 必填,生成签名的随机串  
82 - signature: res.signature,// 必填,签名  
83 - jsApiList: [  
84 - 'scanQRCode',  
85 - "getLocation",  
86 - "updateAppMessageShareData",  
87 - "updateTimelineShareData",  
88 - 'onMenuShareAppMessage', //旧的接口,即将废弃  
89 - 'onMenuShareTimeline' //旧的接口,即将废弃  
90 - ]  
91 - });  
92 - //设置分享内容  
93 - setShare();  
94 - });  
95 - //配置校验失败后执行  
96 - jWeixin.error(function (res) {  
97 - // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。  
98 - console.log(res);  
99 - });  
100 -};  
1 -/*  
2 - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message  
3 - * Digest Algorithm, as defined in RFC 1321.  
4 - * Version 1.1 Copyright (C) Paul Johnston 1999 - 2002.  
5 - * Code also contributed by Greg Holt  
6 - * See http://pajhome.org.uk/site/legal.html for details.  
7 - */  
8 -  
9 -/*  
10 - * Add integers, wrapping at 2^32. This uses 16-bit operations internally  
11 - * to work around bugs in some JS interpreters.  
12 - */  
13 -function safe_add(x, y) {  
14 - var lsw = (x & 0xFFFF) + (y & 0xFFFF)  
15 - var msw = (x >> 16) + (y >> 16) + (lsw >> 16)  
16 - return (msw << 16) | (lsw & 0xFFFF)  
17 -}  
18 -  
19 -/*  
20 - * Bitwise rotate a 32-bit number to the left.  
21 - */  
22 -function rol(num, cnt) {  
23 - return (num << cnt) | (num >>> (32 - cnt))  
24 -}  
25 -  
26 -/*  
27 - * These functions implement the four basic operations the algorithm uses.  
28 - */  
29 -function cmn(q, a, b, x, s, t) {  
30 - return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)  
31 -}  
32 -function ff(a, b, c, d, x, s, t) {  
33 - return cmn((b & c) | ((~b) & d), a, b, x, s, t)  
34 -}  
35 -function gg(a, b, c, d, x, s, t) {  
36 - return cmn((b & d) | (c & (~d)), a, b, x, s, t)  
37 -}  
38 -function hh(a, b, c, d, x, s, t) {  
39 - return cmn(b ^ c ^ d, a, b, x, s, t)  
40 -}  
41 -function ii(a, b, c, d, x, s, t) {  
42 - return cmn(c ^ (b | (~d)), a, b, x, s, t)  
43 -}  
44 -  
45 -/*  
46 - * Calculate the MD5 of an array of little-endian words, producing an array  
47 - * of little-endian words.  
48 - */  
49 -function coreMD5(x) {  
50 - var a = 1732584193  
51 - var b = -271733879  
52 - var c = -1732584194  
53 - var d = 271733878  
54 -  
55 - for (var i = 0; i < x.length; i += 16) {  
56 - var olda = a  
57 - var oldb = b  
58 - var oldc = c  
59 - var oldd = d  
60 -  
61 - a = ff(a, b, c, d, x[i + 0], 7, -680876936)  
62 - d = ff(d, a, b, c, x[i + 1], 12, -389564586)  
63 - c = ff(c, d, a, b, x[i + 2], 17, 606105819)  
64 - b = ff(b, c, d, a, x[i + 3], 22, -1044525330)  
65 - a = ff(a, b, c, d, x[i + 4], 7, -176418897)  
66 - d = ff(d, a, b, c, x[i + 5], 12, 1200080426)  
67 - c = ff(c, d, a, b, x[i + 6], 17, -1473231341)  
68 - b = ff(b, c, d, a, x[i + 7], 22, -45705983)  
69 - a = ff(a, b, c, d, x[i + 8], 7, 1770035416)  
70 - d = ff(d, a, b, c, x[i + 9], 12, -1958414417)  
71 - c = ff(c, d, a, b, x[i + 10], 17, -42063)  
72 - b = ff(b, c, d, a, x[i + 11], 22, -1990404162)  
73 - a = ff(a, b, c, d, x[i + 12], 7, 1804603682)  
74 - d = ff(d, a, b, c, x[i + 13], 12, -40341101)  
75 - c = ff(c, d, a, b, x[i + 14], 17, -1502002290)  
76 - b = ff(b, c, d, a, x[i + 15], 22, 1236535329)  
77 -  
78 - a = gg(a, b, c, d, x[i + 1], 5, -165796510)  
79 - d = gg(d, a, b, c, x[i + 6], 9, -1069501632)  
80 - c = gg(c, d, a, b, x[i + 11], 14, 643717713)  
81 - b = gg(b, c, d, a, x[i + 0], 20, -373897302)  
82 - a = gg(a, b, c, d, x[i + 5], 5, -701558691)  
83 - d = gg(d, a, b, c, x[i + 10], 9, 38016083)  
84 - c = gg(c, d, a, b, x[i + 15], 14, -660478335)  
85 - b = gg(b, c, d, a, x[i + 4], 20, -405537848)  
86 - a = gg(a, b, c, d, x[i + 9], 5, 568446438)  
87 - d = gg(d, a, b, c, x[i + 14], 9, -1019803690)  
88 - c = gg(c, d, a, b, x[i + 3], 14, -187363961)  
89 - b = gg(b, c, d, a, x[i + 8], 20, 1163531501)  
90 - a = gg(a, b, c, d, x[i + 13], 5, -1444681467)  
91 - d = gg(d, a, b, c, x[i + 2], 9, -51403784)  
92 - c = gg(c, d, a, b, x[i + 7], 14, 1735328473)  
93 - b = gg(b, c, d, a, x[i + 12], 20, -1926607734)  
94 -  
95 - a = hh(a, b, c, d, x[i + 5], 4, -378558)  
96 - d = hh(d, a, b, c, x[i + 8], 11, -2022574463)  
97 - c = hh(c, d, a, b, x[i + 11], 16, 1839030562)  
98 - b = hh(b, c, d, a, x[i + 14], 23, -35309556)  
99 - a = hh(a, b, c, d, x[i + 1], 4, -1530992060)  
100 - d = hh(d, a, b, c, x[i + 4], 11, 1272893353)  
101 - c = hh(c, d, a, b, x[i + 7], 16, -155497632)  
102 - b = hh(b, c, d, a, x[i + 10], 23, -1094730640)  
103 - a = hh(a, b, c, d, x[i + 13], 4, 681279174)  
104 - d = hh(d, a, b, c, x[i + 0], 11, -358537222)  
105 - c = hh(c, d, a, b, x[i + 3], 16, -722521979)  
106 - b = hh(b, c, d, a, x[i + 6], 23, 76029189)  
107 - a = hh(a, b, c, d, x[i + 9], 4, -640364487)  
108 - d = hh(d, a, b, c, x[i + 12], 11, -421815835)  
109 - c = hh(c, d, a, b, x[i + 15], 16, 530742520)  
110 - b = hh(b, c, d, a, x[i + 2], 23, -995338651)  
111 -  
112 - a = ii(a, b, c, d, x[i + 0], 6, -198630844)  
113 - d = ii(d, a, b, c, x[i + 7], 10, 1126891415)  
114 - c = ii(c, d, a, b, x[i + 14], 15, -1416354905)  
115 - b = ii(b, c, d, a, x[i + 5], 21, -57434055)  
116 - a = ii(a, b, c, d, x[i + 12], 6, 1700485571)  
117 - d = ii(d, a, b, c, x[i + 3], 10, -1894986606)  
118 - c = ii(c, d, a, b, x[i + 10], 15, -1051523)  
119 - b = ii(b, c, d, a, x[i + 1], 21, -2054922799)  
120 - a = ii(a, b, c, d, x[i + 8], 6, 1873313359)  
121 - d = ii(d, a, b, c, x[i + 15], 10, -30611744)  
122 - c = ii(c, d, a, b, x[i + 6], 15, -1560198380)  
123 - b = ii(b, c, d, a, x[i + 13], 21, 1309151649)  
124 - a = ii(a, b, c, d, x[i + 4], 6, -145523070)  
125 - d = ii(d, a, b, c, x[i + 11], 10, -1120210379)  
126 - c = ii(c, d, a, b, x[i + 2], 15, 718787259)  
127 - b = ii(b, c, d, a, x[i + 9], 21, -343485551)  
128 -  
129 - a = safe_add(a, olda)  
130 - b = safe_add(b, oldb)  
131 - c = safe_add(c, oldc)  
132 - d = safe_add(d, oldd)  
133 - }  
134 - return [a, b, c, d]  
135 -}  
136 -  
137 -/*  
138 - * Convert an array of little-endian words to a hex string.  
139 - */  
140 -function binl2hex(binarray) {  
141 - var hex_tab = "0123456789abcdef"  
142 - var str = ""  
143 - for (var i = 0; i < binarray.length * 4; i++) {  
144 - str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +  
145 - hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF)  
146 - }  
147 - return str  
148 -}  
149 -  
150 -/*  
151 - * Convert an array of little-endian words to a base64 encoded string.  
152 - */  
153 -function binl2b64(binarray) {  
154 - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  
155 - var str = ""  
156 - for (var i = 0; i < binarray.length * 32; i += 6) {  
157 - str += tab.charAt(((binarray[i >> 5] << (i % 32)) & 0x3F) |  
158 - ((binarray[i >> 5 + 1] >> (32 - i % 32)) & 0x3F))  
159 - }  
160 - return str  
161 -}  
162 -  
163 -/*  
164 - * Convert an 8-bit character string to a sequence of 16-word blocks, stored  
165 - * as an array, and append appropriate padding for MD4/5 calculation.  
166 - * If any of the characters are >255, the high byte is silently ignored.  
167 - */  
168 -function str2binl(str) {  
169 - var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks  
170 - var blks = new Array(nblk * 16)  
171 - for (var i = 0; i < nblk * 16; i++) blks[i] = 0  
172 - for (var i = 0; i < str.length; i++)  
173 - blks[i >> 2] |= (str.charCodeAt(i) & 0xFF) << ((i % 4) * 8)  
174 - blks[i >> 2] |= 0x80 << ((i % 4) * 8)  
175 - blks[nblk * 16 - 2] = str.length * 8  
176 - return blks  
177 -}  
178 -  
179 -/*  
180 - * Convert a wide-character string to a sequence of 16-word blocks, stored as  
181 - * an array, and append appropriate padding for MD4/5 calculation.  
182 - */  
183 -function strw2binl(str) {  
184 - var nblk = ((str.length + 4) >> 5) + 1 // number of 16-word blocks  
185 - var blks = new Array(nblk * 16)  
186 - for (var i = 0; i < nblk * 16; i++) blks[i] = 0  
187 - for (var i = 0; i < str.length; i++)  
188 - blks[i >> 1] |= str.charCodeAt(i) << ((i % 2) * 16)  
189 - blks[i >> 1] |= 0x80 << ((i % 2) * 16)  
190 - blks[nblk * 16 - 2] = str.length * 16  
191 - return blks  
192 -}  
193 -  
194 -/*  
195 - * External interface  
196 - */  
197 -function md5(str) { return binl2hex(coreMD5(str2binl(str))) }  
198 -function hexMD5w(str) { return binl2hex(coreMD5(strw2binl(str))) }  
199 -function b64MD5(str) { return binl2b64(coreMD5(str2binl(str))) }  
200 -function b64MD5w(str) { return binl2b64(coreMD5(strw2binl(str))) }  
201 -/* Backward compatibility */  
202 -function calcMD5(str) { return binl2hex(coreMD5(str2binl(str))) }  
203 -module.exports = md5  
1 -var ERROR_CONF={KEY_ERR:311,KEY_ERR_MSG:'key格式错误',PARAM_ERR:310,PARAM_ERR_MSG:'请求参数信息有误',SYSTEM_ERR:600,SYSTEM_ERR_MSG:'系统错误',WX_ERR_CODE:1000,WX_OK_CODE:200};var BASE_URL='https://apis.map.qq.com/ws/';var URL_SEARCH=BASE_URL+'place/v1/search';var URL_SUGGESTION=BASE_URL+'place/v1/suggestion';var URL_GET_GEOCODER=BASE_URL+'geocoder/v1/';var URL_CITY_LIST=BASE_URL+'district/v1/list';var URL_AREA_LIST=BASE_URL+'district/v1/getchildren';var URL_DISTANCE=BASE_URL+'distance/v1/';var URL_DIRECTION=BASE_URL+'direction/v1/';var MODE={driving:'driving',transit:'transit'};var EARTH_RADIUS=6378136.49;var Utils={safeAdd(x,y){var lsw=(x&0xffff)+(y&0xffff);var msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&0xffff)},bitRotateLeft(num,cnt){return(num<<cnt)|(num>>>(32-cnt))},md5cmn(q,a,b,x,s,t){return this.safeAdd(this.bitRotateLeft(this.safeAdd(this.safeAdd(a,q),this.safeAdd(x,t)),s),b)},md5ff(a,b,c,d,x,s,t){return this.md5cmn((b&c)|(~b&d),a,b,x,s,t)},md5gg(a,b,c,d,x,s,t){return this.md5cmn((b&d)|(c&~d),a,b,x,s,t)},md5hh(a,b,c,d,x,s,t){return this.md5cmn(b^c^d,a,b,x,s,t)},md5ii(a,b,c,d,x,s,t){return this.md5cmn(c^(b|~d),a,b,x,s,t)},binlMD5(x,len){x[len>>5]|=0x80<<(len%32);x[((len+64)>>>9<<4)+14]=len;var i;var olda;var oldb;var oldc;var oldd;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;for(i=0;i<x.length;i+=16){olda=a;oldb=b;oldc=c;oldd=d;a=this.md5ff(a,b,c,d,x[i],7,-680876936);d=this.md5ff(d,a,b,c,x[i+1],12,-389564586);c=this.md5ff(c,d,a,b,x[i+2],17,606105819);b=this.md5ff(b,c,d,a,x[i+3],22,-1044525330);a=this.md5ff(a,b,c,d,x[i+4],7,-176418897);d=this.md5ff(d,a,b,c,x[i+5],12,1200080426);c=this.md5ff(c,d,a,b,x[i+6],17,-1473231341);b=this.md5ff(b,c,d,a,x[i+7],22,-45705983);a=this.md5ff(a,b,c,d,x[i+8],7,1770035416);d=this.md5ff(d,a,b,c,x[i+9],12,-1958414417);c=this.md5ff(c,d,a,b,x[i+10],17,-42063);b=this.md5ff(b,c,d,a,x[i+11],22,-1990404162);a=this.md5ff(a,b,c,d,x[i+12],7,1804603682);d=this.md5ff(d,a,b,c,x[i+13],12,-40341101);c=this.md5ff(c,d,a,b,x[i+14],17,-1502002290);b=this.md5ff(b,c,d,a,x[i+15],22,1236535329);a=this.md5gg(a,b,c,d,x[i+1],5,-165796510);d=this.md5gg(d,a,b,c,x[i+6],9,-1069501632);c=this.md5gg(c,d,a,b,x[i+11],14,643717713);b=this.md5gg(b,c,d,a,x[i],20,-373897302);a=this.md5gg(a,b,c,d,x[i+5],5,-701558691);d=this.md5gg(d,a,b,c,x[i+10],9,38016083);c=this.md5gg(c,d,a,b,x[i+15],14,-660478335);b=this.md5gg(b,c,d,a,x[i+4],20,-405537848);a=this.md5gg(a,b,c,d,x[i+9],5,568446438);d=this.md5gg(d,a,b,c,x[i+14],9,-1019803690);c=this.md5gg(c,d,a,b,x[i+3],14,-187363961);b=this.md5gg(b,c,d,a,x[i+8],20,1163531501);a=this.md5gg(a,b,c,d,x[i+13],5,-1444681467);d=this.md5gg(d,a,b,c,x[i+2],9,-51403784);c=this.md5gg(c,d,a,b,x[i+7],14,1735328473);b=this.md5gg(b,c,d,a,x[i+12],20,-1926607734);a=this.md5hh(a,b,c,d,x[i+5],4,-378558);d=this.md5hh(d,a,b,c,x[i+8],11,-2022574463);c=this.md5hh(c,d,a,b,x[i+11],16,1839030562);b=this.md5hh(b,c,d,a,x[i+14],23,-35309556);a=this.md5hh(a,b,c,d,x[i+1],4,-1530992060);d=this.md5hh(d,a,b,c,x[i+4],11,1272893353);c=this.md5hh(c,d,a,b,x[i+7],16,-155497632);b=this.md5hh(b,c,d,a,x[i+10],23,-1094730640);a=this.md5hh(a,b,c,d,x[i+13],4,681279174);d=this.md5hh(d,a,b,c,x[i],11,-358537222);c=this.md5hh(c,d,a,b,x[i+3],16,-722521979);b=this.md5hh(b,c,d,a,x[i+6],23,76029189);a=this.md5hh(a,b,c,d,x[i+9],4,-640364487);d=this.md5hh(d,a,b,c,x[i+12],11,-421815835);c=this.md5hh(c,d,a,b,x[i+15],16,530742520);b=this.md5hh(b,c,d,a,x[i+2],23,-995338651);a=this.md5ii(a,b,c,d,x[i],6,-198630844);d=this.md5ii(d,a,b,c,x[i+7],10,1126891415);c=this.md5ii(c,d,a,b,x[i+14],15,-1416354905);b=this.md5ii(b,c,d,a,x[i+5],21,-57434055);a=this.md5ii(a,b,c,d,x[i+12],6,1700485571);d=this.md5ii(d,a,b,c,x[i+3],10,-1894986606);c=this.md5ii(c,d,a,b,x[i+10],15,-1051523);b=this.md5ii(b,c,d,a,x[i+1],21,-2054922799);a=this.md5ii(a,b,c,d,x[i+8],6,1873313359);d=this.md5ii(d,a,b,c,x[i+15],10,-30611744);c=this.md5ii(c,d,a,b,x[i+6],15,-1560198380);b=this.md5ii(b,c,d,a,x[i+13],21,1309151649);a=this.md5ii(a,b,c,d,x[i+4],6,-145523070);d=this.md5ii(d,a,b,c,x[i+11],10,-1120210379);c=this.md5ii(c,d,a,b,x[i+2],15,718787259);b=this.md5ii(b,c,d,a,x[i+9],21,-343485551);a=this.safeAdd(a,olda);b=this.safeAdd(b,oldb);c=this.safeAdd(c,oldc);d=this.safeAdd(d,oldd)}return[a,b,c,d]},binl2rstr(input){var i;var output='';var length32=input.length*32;for(i=0;i<length32;i+=8){output+=String.fromCharCode((input[i>>5]>>>(i%32))&0xff)}return output},rstr2binl(input){var i;var output=[];output[(input.length>>2)-1]=undefined;for(i=0;i<output.length;i+=1){output[i]=0}var length8=input.length*8;for(i=0;i<length8;i+=8){output[i>>5]|=(input.charCodeAt(i/8)&0xff)<<(i%32)}return output},rstrMD5(s){return this.binl2rstr(this.binlMD5(this.rstr2binl(s),s.length*8))},rstrHMACMD5(key,data){var i;var bkey=this.rstr2binl(key);var ipad=[];var opad=[];var hash;ipad[15]=opad[15]=undefined;if(bkey.length>16){bkey=this.binlMD5(bkey,key.length*8)}for(i=0;i<16;i+=1){ipad[i]=bkey[i]^0x36363636;opad[i]=bkey[i]^0x5c5c5c5c}hash=this.binlMD5(ipad.concat(this.rstr2binl(data)),512+data.length*8);return this.binl2rstr(this.binlMD5(opad.concat(hash),512+128))},rstr2hex(input){var hexTab='0123456789abcdef';var output='';var x;var i;for(i=0;i<input.length;i+=1){x=input.charCodeAt(i);output+=hexTab.charAt((x>>>4)&0x0f)+hexTab.charAt(x&0x0f)}return output},str2rstrUTF8(input){return unescape(encodeURIComponent(input))},rawMD5(s){return this.rstrMD5(this.str2rstrUTF8(s))},hexMD5(s){return this.rstr2hex(this.rawMD5(s))},rawHMACMD5(k,d){return this.rstrHMACMD5(this.str2rstrUTF8(k),str2rstrUTF8(d))},hexHMACMD5(k,d){return this.rstr2hex(this.rawHMACMD5(k,d))},md5(string,key,raw){if(!key){if(!raw){return this.hexMD5(string)}return this.rawMD5(string)}if(!raw){return this.hexHMACMD5(key,string)}return this.rawHMACMD5(key,string)},getSig(requestParam,sk,feature,mode){var sig=null;var requestArr=[];Object.keys(requestParam).sort().forEach(function(key){requestArr.push(key+'='+requestParam[key])});if(feature=='search'){sig='/ws/place/v1/search?'+requestArr.join('&')+sk}if(feature=='suggest'){sig='/ws/place/v1/suggestion?'+requestArr.join('&')+sk}if(feature=='reverseGeocoder'){sig='/ws/geocoder/v1/?'+requestArr.join('&')+sk}if(feature=='geocoder'){sig='/ws/geocoder/v1/?'+requestArr.join('&')+sk}if(feature=='getCityList'){sig='/ws/district/v1/list?'+requestArr.join('&')+sk}if(feature=='getDistrictByCityId'){sig='/ws/district/v1/getchildren?'+requestArr.join('&')+sk}if(feature=='calculateDistance'){sig='/ws/distance/v1/?'+requestArr.join('&')+sk}if(feature=='direction'){sig='/ws/direction/v1/'+mode+'?'+requestArr.join('&')+sk}sig=this.md5(sig);return sig},location2query(data){if(typeof data=='string'){return data}var query='';for(var i=0;i<data.length;i++){var d=data[i];if(!!query){query+=';'}if(d.location){query=query+d.location.lat+','+d.location.lng}if(d.latitude&&d.longitude){query=query+d.latitude+','+d.longitude}}return query},rad(d){return d*Math.PI/180.0},getEndLocation(location){var to=location.split(';');var endLocation=[];for(var i=0;i<to.length;i++){endLocation.push({lat:parseFloat(to[i].split(',')[0]),lng:parseFloat(to[i].split(',')[1])})}return endLocation},getDistance(latFrom,lngFrom,latTo,lngTo){var radLatFrom=this.rad(latFrom);var radLatTo=this.rad(latTo);var a=radLatFrom-radLatTo;var b=this.rad(lngFrom)-this.rad(lngTo);var distance=2*Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2)+Math.cos(radLatFrom)*Math.cos(radLatTo)*Math.pow(Math.sin(b/2),2)));distance=distance*EARTH_RADIUS;distance=Math.round(distance*10000)/10000;return parseFloat(distance.toFixed(0))},getWXLocation(success,fail,complete){wx.getLocation({type:'gcj02',success:success,fail:fail,complete:complete})},getLocationParam(location){if(typeof location=='string'){var locationArr=location.split(',');if(locationArr.length===2){location={latitude:location.split(',')[0],longitude:location.split(',')[1]}}else{location={}}}return location},polyfillParam(param){param.success=param.success||function(){};param.fail=param.fail||function(){};param.complete=param.complete||function(){}},checkParamKeyEmpty(param,key){if(!param[key]){var errconf=this.buildErrorConfig(ERROR_CONF.PARAM_ERR,ERROR_CONF.PARAM_ERR_MSG+key+'参数格式有误');param.fail(errconf);param.complete(errconf);return true}return false},checkKeyword(param){return!this.checkParamKeyEmpty(param,'keyword')},checkLocation(param){var location=this.getLocationParam(param.location);if(!location||!location.latitude||!location.longitude){var errconf=this.buildErrorConfig(ERROR_CONF.PARAM_ERR,ERROR_CONF.PARAM_ERR_MSG+' location参数格式有误');param.fail(errconf);param.complete(errconf);return false}return true},buildErrorConfig(errCode,errMsg){return{status:errCode,message:errMsg}},handleData(param,data,feature){if(feature=='search'){var searchResult=data.data;var searchSimplify=[];for(var i=0;i<searchResult.length;i++){searchSimplify.push({id:searchResult[i].id||null,title:searchResult[i].title||null,latitude:searchResult[i].location&&searchResult[i].location.lat||null,longitude:searchResult[i].location&&searchResult[i].location.lng||null,address:searchResult[i].address||null,category:searchResult[i].category||null,tel:searchResult[i].tel||null,adcode:searchResult[i].ad_info&&searchResult[i].ad_info.adcode||null,city:searchResult[i].ad_info&&searchResult[i].ad_info.city||null,district:searchResult[i].ad_info&&searchResult[i].ad_info.district||null,province:searchResult[i].ad_info&&searchResult[i].ad_info.province||null})}param.success(data,{searchResult:searchResult,searchSimplify:searchSimplify})}else if(feature=='suggest'){var suggestResult=data.data;var suggestSimplify=[];for(var i=0;i<suggestResult.length;i++){suggestSimplify.push({adcode:suggestResult[i].adcode||null,address:suggestResult[i].address||null,category:suggestResult[i].category||null,city:suggestResult[i].city||null,district:suggestResult[i].district||null,id:suggestResult[i].id||null,latitude:suggestResult[i].location&&suggestResult[i].location.lat||null,longitude:suggestResult[i].location&&suggestResult[i].location.lng||null,province:suggestResult[i].province||null,title:suggestResult[i].title||null,type:suggestResult[i].type||null})}param.success(data,{suggestResult:suggestResult,suggestSimplify:suggestSimplify})}else if(feature=='reverseGeocoder'){var reverseGeocoderResult=data.result;var reverseGeocoderSimplify={address:reverseGeocoderResult.address||null,latitude:reverseGeocoderResult.location&&reverseGeocoderResult.location.lat||null,longitude:reverseGeocoderResult.location&&reverseGeocoderResult.location.lng||null,adcode:reverseGeocoderResult.ad_info&&reverseGeocoderResult.ad_info.adcode||null,city:reverseGeocoderResult.address_component&&reverseGeocoderResult.address_component.city||null,district:reverseGeocoderResult.address_component&&reverseGeocoderResult.address_component.district||null,nation:reverseGeocoderResult.address_component&&reverseGeocoderResult.address_component.nation||null,province:reverseGeocoderResult.address_component&&reverseGeocoderResult.address_component.province||null,street:reverseGeocoderResult.address_component&&reverseGeocoderResult.address_component.street||null,street_number:reverseGeocoderResult.address_component&&reverseGeocoderResult.address_component.street_number||null,recommend:reverseGeocoderResult.formatted_addresses&&reverseGeocoderResult.formatted_addresses.recommend||null,rough:reverseGeocoderResult.formatted_addresses&&reverseGeocoderResult.formatted_addresses.rough||null};if(reverseGeocoderResult.pois){var pois=reverseGeocoderResult.pois;var poisSimplify=[];for(var i=0;i<pois.length;i++){poisSimplify.push({id:pois[i].id||null,title:pois[i].title||null,latitude:pois[i].location&&pois[i].location.lat||null,longitude:pois[i].location&&pois[i].location.lng||null,address:pois[i].address||null,category:pois[i].category||null,adcode:pois[i].ad_info&&pois[i].ad_info.adcode||null,city:pois[i].ad_info&&pois[i].ad_info.city||null,district:pois[i].ad_info&&pois[i].ad_info.district||null,province:pois[i].ad_info&&pois[i].ad_info.province||null})}param.success(data,{reverseGeocoderResult:reverseGeocoderResult,reverseGeocoderSimplify:reverseGeocoderSimplify,pois:pois,poisSimplify:poisSimplify})}else{param.success(data,{reverseGeocoderResult:reverseGeocoderResult,reverseGeocoderSimplify:reverseGeocoderSimplify})}}else if(feature=='geocoder'){var geocoderResult=data.result;var geocoderSimplify={title:geocoderResult.title||null,latitude:geocoderResult.location&&geocoderResult.location.lat||null,longitude:geocoderResult.location&&geocoderResult.location.lng||null,adcode:geocoderResult.ad_info&&geocoderResult.ad_info.adcode||null,province:geocoderResult.address_components&&geocoderResult.address_components.province||null,city:geocoderResult.address_components&&geocoderResult.address_components.city||null,district:geocoderResult.address_components&&geocoderResult.address_components.district||null,street:geocoderResult.address_components&&geocoderResult.address_components.street||null,street_number:geocoderResult.address_components&&geocoderResult.address_components.street_number||null,level:geocoderResult.level||null};param.success(data,{geocoderResult:geocoderResult,geocoderSimplify:geocoderSimplify})}else if(feature=='getCityList'){var provinceResult=data.result[0];var cityResult=data.result[1];var districtResult=data.result[2];param.success(data,{provinceResult:provinceResult,cityResult:cityResult,districtResult:districtResult})}else if(feature=='getDistrictByCityId'){var districtByCity=data.result[0];param.success(data,districtByCity)}else if(feature=='calculateDistance'){var calculateDistanceResult=data.result.elements;var distance=[];for(var i=0;i<calculateDistanceResult.length;i++){distance.push(calculateDistanceResult[i].distance)}param.success(data,{calculateDistanceResult:calculateDistanceResult,distance:distance})}else if(feature=='direction'){var direction=data.result.routes;param.success(data,direction)}else{param.success(data)}},buildWxRequestConfig(param,options,feature){var that=this;options.header={"content-type":"application/json"};options.method='GET';options.success=function(res){var data=res.data;if(data.status===0){that.handleData(param,data,feature)}else{param.fail(data)}};options.fail=function(res){res.statusCode=ERROR_CONF.WX_ERR_CODE;param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,res.errMsg))};options.complete=function(res){var statusCode=+res.statusCode;switch(statusCode){case ERROR_CONF.WX_ERR_CODE:{param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,res.errMsg));break}case ERROR_CONF.WX_OK_CODE:{var data=res.data;if(data.status===0){param.complete(data)}else{param.complete(that.buildErrorConfig(data.status,data.message))}break}default:{param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR,ERROR_CONF.SYSTEM_ERR_MSG))}}};return options},locationProcess(param,locationsuccess,locationfail,locationcomplete){var that=this;locationfail=locationfail||function(res){res.statusCode=ERROR_CONF.WX_ERR_CODE;param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,res.errMsg))};locationcomplete=locationcomplete||function(res){if(res.statusCode==ERROR_CONF.WX_ERR_CODE){param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,res.errMsg))}};if(!param.location){that.getWXLocation(locationsuccess,locationfail,locationcomplete)}else if(that.checkLocation(param)){var location=Utils.getLocationParam(param.location);locationsuccess(location)}}};class QQMapWX{constructor(options){if(!options.key){throw Error('key值不能为空')}this.key=options.key};search(options){var that=this;options=options||{};Utils.polyfillParam(options);if(!Utils.checkKeyword(options)){return}var requestParam={keyword:options.keyword,orderby:options.orderby||'_distance',page_size:options.page_size||10,page_index:options.page_index||1,output:'json',key:that.key};if(options.address_format){requestParam.address_format=options.address_format}if(options.filter){requestParam.filter=options.filter}var distance=options.distance||"1000";var auto_extend=options.auto_extend||1;var region=null;var rectangle=null;if(options.region){region=options.region}if(options.rectangle){rectangle=options.rectangle}var locationsuccess=function(result){if(region&&!rectangle){requestParam.boundary="region("+region+","+auto_extend+","+result.latitude+","+result.longitude+")";if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'search')}}else if(rectangle&&!region){requestParam.boundary="rectangle("+rectangle+")";if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'search')}}else{requestParam.boundary="nearby("+result.latitude+","+result.longitude+","+distance+","+auto_extend+")";if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'search')}}wx.request(Utils.buildWxRequestConfig(options,{url:URL_SEARCH,data:requestParam},'search'))};Utils.locationProcess(options,locationsuccess)};getSuggestion(options){var that=this;options=options||{};Utils.polyfillParam(options);if(!Utils.checkKeyword(options)){return}var requestParam={keyword:options.keyword,region:options.region||'全国',region_fix:options.region_fix||0,policy:options.policy||0,page_size:options.page_size||10,page_index:options.page_index||1,get_subpois:options.get_subpois||0,output:'json',key:that.key};if(options.address_format){requestParam.address_format=options.address_format}if(options.filter){requestParam.filter=options.filter}if(options.location){var locationsuccess=function(result){requestParam.location=result.latitude+','+result.longitude;if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'suggest')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_SUGGESTION,data:requestParam},"suggest"))};Utils.locationProcess(options,locationsuccess)}else{if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'suggest')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_SUGGESTION,data:requestParam},"suggest"))}};reverseGeocoder(options){var that=this;options=options||{};Utils.polyfillParam(options);var requestParam={coord_type:options.coord_type||5,get_poi:options.get_poi||0,output:'json',key:that.key};if(options.poi_options){requestParam.poi_options=options.poi_options}var locationsuccess=function(result){requestParam.location=result.latitude+','+result.longitude;if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'reverseGeocoder')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_GET_GEOCODER,data:requestParam},'reverseGeocoder'))};Utils.locationProcess(options,locationsuccess)};geocoder(options){var that=this;options=options||{};Utils.polyfillParam(options);if(Utils.checkParamKeyEmpty(options,'address')){return}var requestParam={address:options.address,output:'json',key:that.key};if(options.region){requestParam.region=options.region}if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'geocoder')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_GET_GEOCODER,data:requestParam},'geocoder'))};getCityList(options){var that=this;options=options||{};Utils.polyfillParam(options);var requestParam={output:'json',key:that.key};if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'getCityList')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_CITY_LIST,data:requestParam},'getCityList'))};getDistrictByCityId(options){var that=this;options=options||{};Utils.polyfillParam(options);if(Utils.checkParamKeyEmpty(options,'id')){return}var requestParam={id:options.id||'',output:'json',key:that.key};if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'getDistrictByCityId')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_AREA_LIST,data:requestParam},'getDistrictByCityId'))};calculateDistance(options){var that=this;options=options||{};Utils.polyfillParam(options);if(Utils.checkParamKeyEmpty(options,'to')){return}var requestParam={mode:options.mode||'walking',to:Utils.location2query(options.to),output:'json',key:that.key};if(options.from){options.location=options.from}if(requestParam.mode=='straight'){var locationsuccess=function(result){var locationTo=Utils.getEndLocation(requestParam.to);var data={message:"query ok",result:{elements:[]},status:0};for(var i=0;i<locationTo.length;i++){data.result.elements.push({distance:Utils.getDistance(result.latitude,result.longitude,locationTo[i].lat,locationTo[i].lng),duration:0,from:{lat:result.latitude,lng:result.longitude},to:{lat:locationTo[i].lat,lng:locationTo[i].lng}})}var calculateResult=data.result.elements;var distanceResult=[];for(var i=0;i<calculateResult.length;i++){distanceResult.push(calculateResult[i].distance)}return options.success(data,{calculateResult:calculateResult,distanceResult:distanceResult})};Utils.locationProcess(options,locationsuccess)}else{var locationsuccess=function(result){requestParam.from=result.latitude+','+result.longitude;if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'calculateDistance')}wx.request(Utils.buildWxRequestConfig(options,{url:URL_DISTANCE,data:requestParam},'calculateDistance'))};Utils.locationProcess(options,locationsuccess)}};direction(options){var that=this;options=options||{};Utils.polyfillParam(options);if(Utils.checkParamKeyEmpty(options,'to')){return}var requestParam={output:'json',key:that.key};if(typeof options.to=='string'){requestParam.to=options.to}else{requestParam.to=options.to.latitude+','+options.to.longitude}var SET_URL_DIRECTION=null;options.mode=options.mode||MODE.driving;SET_URL_DIRECTION=URL_DIRECTION+options.mode;if(options.from){options.location=options.from}if(options.mode==MODE.driving){if(options.from_poi){requestParam.from_poi=options.from_poi}if(options.heading){requestParam.heading=options.heading}if(options.speed){requestParam.speed=options.speed}if(options.accuracy){requestParam.accuracy=options.accuracy}if(options.road_type){requestParam.road_type=options.road_type}if(options.to_poi){requestParam.to_poi=options.to_poi}if(options.from_track){requestParam.from_track=options.from_track}if(options.waypoints){requestParam.waypoints=options.waypoints}if(options.policy){requestParam.policy=options.policy}if(options.plate_number){requestParam.plate_number=options.plate_number}}if(options.mode==MODE.transit){if(options.departure_time){requestParam.departure_time=options.departure_time}if(options.policy){requestParam.policy=options.policy}}var locationsuccess=function(result){requestParam.from=result.latitude+','+result.longitude;if(options.sig){requestParam.sig=Utils.getSig(requestParam,options.sig,'direction',options.mode)}wx.request(Utils.buildWxRequestConfig(options,{url:SET_URL_DIRECTION,data:requestParam},'direction'))};Utils.locationProcess(options,locationsuccess)}};module.exports=QQMapWX;  
publicLoginSubPage/other/code.vue renamed from pages/personal/code.vue
publicLoginSubPage/other/findPassword.vue renamed from pages/personal/findPassword.vue
publicLoginSubPage/other/set.vue renamed from pages/personal/set.vue
publicLoginSubPage/other/static/code.scss renamed from pages/personal/static/code.scss
publicLoginSubPage/other/static/findPassword.scss renamed from pages/personal/static/findPassword.scss
publicLoginSubPage/other/static/set.scss renamed from pages/personal/static/set.scss
@@ -122,22 +122,12 @@ export default { @@ -122,22 +122,12 @@ export default {
122 uni.showToast({ 122 uni.showToast({
123 title: '登录成功~', 123 title: '登录成功~',
124 icon: 'none' 124 icon: 'none'
  125 + }).then(res => {
  126 + uni.reLaunch({
  127 + url: '/pages/personal/personal'
125 }); 128 });
126 - this.saveUserInfo();  
127 - // #ifndef MP  
128 - // setTimeout(() => {  
129 - // uni.navigateBack();  
130 - // }, 500);  
131 - uni.switchTab({  
132 - url: '../personal/personal'  
133 - });  
134 - // #endif  
135 - // #ifdef MP  
136 - // uni.navigateBack();  
137 - uni.switchTab({  
138 - url: '../personal/personal'  
139 }); 129 });
140 - // #endif 130 + this.saveUserInfo();
141 } 131 }
142 }) 132 })
143 .catch(e => { 133 .catch(e => {
@@ -154,12 +144,12 @@ export default { @@ -154,12 +144,12 @@ export default {
154 }, 144 },
155 openCodeFunc() { 145 openCodeFunc() {
156 uni.navigateTo({ 146 uni.navigateTo({
157 - url: '../personal/code' 147 + url: '../other/code'
158 }); 148 });
159 }, 149 },
160 findPassrordFunc() { 150 findPassrordFunc() {
161 uni.navigateTo({ 151 uni.navigateTo({
162 - url: '../personal/findPassword' 152 + url: '../other/findPassword'
163 }); 153 });
164 }, 154 },
165 showPasswordMode() { 155 showPasswordMode() {
publicLoginSubPage/public/static/login.scss renamed from pages/public/static/login.scss
sysNotifySubPage/sysNotifyPage/notifyDetail.vue renamed from pages/systemNotify/notifyDetail.vue
sysNotifySubPage/sysNotifyPage/static/notifyDetail.scss renamed from pages/systemNotify/static/notifyDetail.scss
sysNotifySubPage/sysNotifyPage/static/systemNotify.scss renamed from pages/systemNotify/static/systemNotify.scss
sysNotifySubPage/sysNotifyPage/systemNotify.vue renamed from pages/systemNotify/systemNotify.vue
@@ -7,14 +7,13 @@ @@ -7,14 +7,13 @@
7 <u-form-item 7 <u-form-item
8 label="类型" 8 label="类型"
9 prop="userInfo.sex" 9 prop="userInfo.sex"
10 - borderBottom  
11 @click=" 10 @click="
12 showType = true; 11 showType = true;
13 hideKeyboard(); 12 hideKeyboard();
14 " 13 "
15 ref="item1" 14 ref="item1"
16 > 15 >
17 - <u--input v-model="model1.userInfo.type" placeholder="请选择类型" border="none"></u--input> 16 + <u--input v-model="model1.userInfo.type" placeholder="请选择类型" border="surround"></u--input>
18 <u-icon slot="right" name="arrow-right"></u-icon> 17 <u-icon slot="right" name="arrow-right"></u-icon>
19 </u-form-item> 18 </u-form-item>
20 </u--form> 19 </u--form>
@@ -38,19 +37,15 @@ @@ -38,19 +37,15 @@
38 </view> 37 </view>
39 </mescroll-body> 38 </mescroll-body>
40 </view> 39 </view>
41 - <f-tabbar></f-tabbar>  
42 </view> 40 </view>
43 </template> 41 </template>
44 42
45 <script> 43 <script>
46 -import fTabbar from '@/components/module/f-tabbar/f-tabbar';  
47 import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; 44 import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
48 45
49 export default { 46 export default {
50 mixins: [MescrollMixin], // 使用mixin (在main.js注册全局组件) 47 mixins: [MescrollMixin], // 使用mixin (在main.js注册全局组件)
51 - components: {  
52 - fTabbar  
53 - }, 48 +
54 data() { 49 data() {
55 return { 50 return {
56 model1: { 51 model1: {
@@ -61,6 +56,10 @@ export default { @@ -61,6 +56,10 @@ export default {
61 showType: false, 56 showType: false,
62 actions: [ 57 actions: [
63 { 58 {
  59 + name: '全部',
  60 + value: ''
  61 + },
  62 + {
64 name: '会议', 63 name: '会议',
65 value: 'MEETING' 64 value: 'MEETING'
66 }, 65 },
1 -export default {  
2 - props: {  
3 - // 显示文字  
4 - title: {  
5 - type: String,  
6 - default: uni.$u.props.alert.title  
7 - },  
8 - // 主题,success/warning/info/error  
9 - type: {  
10 - type: String,  
11 - default: uni.$u.props.alert.type  
12 - },  
13 - // 辅助性文字  
14 - description: {  
15 - type: String,  
16 - default: uni.$u.props.alert.description  
17 - },  
18 - // 是否可关闭  
19 - closable: {  
20 - type: Boolean,  
21 - default: uni.$u.props.alert.closable  
22 - },  
23 - // 是否显示图标  
24 - showIcon: {  
25 - type: Boolean,  
26 - default: uni.$u.props.alert.showIcon  
27 - },  
28 - // 浅或深色调,light-浅色,dark-深色  
29 - effect: {  
30 - type: String,  
31 - default: uni.$u.props.alert.effect  
32 - },  
33 - // 文字是否居中  
34 - center: {  
35 - type: Boolean,  
36 - default: uni.$u.props.alert.center  
37 - },  
38 - // 字体大小  
39 - fontSize: {  
40 - type: [String, Number],  
41 - default: uni.$u.props.alert.fontSize  
42 - }  
43 - }  
44 -}  
1 -<template>  
2 - <u-transition  
3 - mode="fade"  
4 - :show="show"  
5 - >  
6 - <view  
7 - class="u-alert"  
8 - :class="[`u-alert--${type}--${effect}`]"  
9 - @tap.stop="clickHandler"  
10 - :style="[$u.addStyle(customStyle)]"  
11 - >  
12 - <view  
13 - class="u-alert__icon"  
14 - v-if="showIcon"  
15 - >  
16 - <u-icon  
17 - :name="iconName"  
18 - size="18"  
19 - :color="iconColor"  
20 - ></u-icon>  
21 - </view>  
22 - <view  
23 - class="u-alert__content"  
24 - :style="[{  
25 - paddingRight: closable ? '20px' : 0  
26 - }]"  
27 - >  
28 - <text  
29 - class="u-alert__content__title"  
30 - v-if="title"  
31 - :style="[{  
32 - fontSize: $u.addUnit(fontSize),  
33 - textAlign: center ? 'center' : 'left'  
34 - }]"  
35 - :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"  
36 - >{{ title }}</text>  
37 - <text  
38 - class="u-alert__content__desc"  
39 - v-if="description"  
40 - :style="[{  
41 - fontSize: $u.addUnit(fontSize),  
42 - textAlign: center ? 'center' : 'left'  
43 - }]"  
44 - :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"  
45 - >{{ description }}</text>  
46 - </view>  
47 - <view  
48 - class="u-alert__close"  
49 - v-if="closable"  
50 - @tap.stop="closeHandler"  
51 - >  
52 - <u-icon  
53 - name="close"  
54 - :color="iconColor"  
55 - size="15"  
56 - ></u-icon>  
57 - </view>  
58 - </view>  
59 - </u-transition>  
60 -</template>  
61 -  
62 -<script>  
63 - import props from './props.js';  
64 - /**  
65 - * Alert 警告提示  
66 - * @description 警告提示,展现需要关注的信息。  
67 - * @tutorial https://www.uviewui.com/components/alertTips.html  
68 - *  
69 - * @property {String} title 显示的文字  
70 - * @property {String} type 使用预设的颜色 (默认 'warning' )  
71 - * @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选  
72 - * @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false )  
73 - * @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false )  
74 - * @property {String} effect 多图时,图片缩放裁剪的模式 (默认 'light' )  
75 - * @property {Boolean} center 文字是否居中 (默认 false )  
76 - * @property {String | Number} fontSize 字体大小 (默认 14 )  
77 - * @property {Object} customStyle 定义需要用到的外部样式  
78 - * @event {Function} click 点击组件时触发  
79 - * @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>  
80 - */  
81 - export default {  
82 - name: 'u-alert',  
83 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
84 - data() {  
85 - return {  
86 - show: true  
87 - }  
88 - },  
89 - computed: {  
90 - iconColor() {  
91 - return this.effect === 'light' ? this.type : '#fff'  
92 - },  
93 - // 不同主题对应不同的图标  
94 - iconName() {  
95 - switch (this.type) {  
96 - case 'success':  
97 - return 'checkmark-circle-fill';  
98 - break;  
99 - case 'error':  
100 - return 'close-circle-fill';  
101 - break;  
102 - case 'warning':  
103 - return 'error-circle-fill';  
104 - break;  
105 - case 'info':  
106 - return 'info-circle-fill';  
107 - break;  
108 - case 'primary':  
109 - return 'more-circle-fill';  
110 - break;  
111 - default:  
112 - return 'error-circle-fill';  
113 - }  
114 - }  
115 - },  
116 - methods: {  
117 - // 点击内容  
118 - clickHandler() {  
119 - this.$emit('click')  
120 - },  
121 - // 点击关闭按钮  
122 - closeHandler() {  
123 - this.show = false  
124 - }  
125 - }  
126 - }  
127 -</script>  
128 -  
129 -<style lang="scss" scoped>  
130 - @import "../../libs/css/components.scss";  
131 -  
132 - .u-alert {  
133 - position: relative;  
134 - background-color: $u-primary;  
135 - padding: 8px 10px;  
136 - @include flex(row);  
137 - align-items: center;  
138 - border-top-left-radius: 4px;  
139 - border-top-right-radius: 4px;  
140 - border-bottom-left-radius: 4px;  
141 - border-bottom-right-radius: 4px;  
142 -  
143 - &--primary--dark {  
144 - background-color: $u-primary;  
145 - }  
146 -  
147 - &--primary--light {  
148 - background-color: #ecf5ff;  
149 - }  
150 -  
151 - &--error--dark {  
152 - background-color: $u-error;  
153 - }  
154 -  
155 - &--error--light {  
156 - background-color: #FEF0F0;  
157 - }  
158 -  
159 - &--success--dark {  
160 - background-color: $u-success;  
161 - }  
162 -  
163 - &--success--light {  
164 - background-color: #f5fff0;  
165 - }  
166 -  
167 - &--warning--dark {  
168 - background-color: $u-warning;  
169 - }  
170 -  
171 - &--warning--light {  
172 - background-color: #FDF6EC;  
173 - }  
174 -  
175 - &--info--dark {  
176 - background-color: $u-info;  
177 - }  
178 -  
179 - &--info--light {  
180 - background-color: #f4f4f5;  
181 - }  
182 -  
183 - &__icon {  
184 - margin-right: 5px;  
185 - }  
186 -  
187 - &__content {  
188 - @include flex(column);  
189 - flex: 1;  
190 -  
191 - &__title {  
192 - color: $u-main-color;  
193 - font-size: 14px;  
194 - font-weight: bold;  
195 - color: #fff;  
196 - margin-bottom: 2px;  
197 - }  
198 -  
199 - &__desc {  
200 - color: $u-main-color;  
201 - font-size: 14px;  
202 - flex-wrap: wrap;  
203 - color: #fff;  
204 - }  
205 - }  
206 -  
207 - &__title--dark,  
208 - &__desc--dark {  
209 - color: #FFFFFF;  
210 - }  
211 -  
212 - &__text--primary--light,  
213 - &__text--primary--light {  
214 - color: $u-primary;  
215 - }  
216 -  
217 - &__text--success--light,  
218 - &__text--success--light {  
219 - color: $u-success;  
220 - }  
221 -  
222 - &__text--warning--light,  
223 - &__text--warning--light {  
224 - color: $u-warning;  
225 - }  
226 -  
227 - &__text--error--light,  
228 - &__text--error--light {  
229 - color: $u-error;  
230 - }  
231 -  
232 - &__text--info--light,  
233 - &__text--info--light {  
234 - color: $u-info;  
235 - }  
236 -  
237 - &__close {  
238 - position: absolute;  
239 - top: 11px;  
240 - right: 10px;  
241 - }  
242 - }  
243 -</style>  
1 -export default {  
2 - props: {  
3 - // 最大输入长度  
4 - maxlength: {  
5 - type: [String, Number],  
6 - default: uni.$u.props.codeInput.maxlength  
7 - },  
8 - // 是否用圆点填充  
9 - dot: {  
10 - type: Boolean,  
11 - default: uni.$u.props.codeInput.dot  
12 - },  
13 - // 显示模式,box-盒子模式,line-底部横线模式  
14 - mode: {  
15 - type: String,  
16 - default: uni.$u.props.codeInput.mode  
17 - },  
18 - // 是否细边框  
19 - hairline: {  
20 - type: Boolean,  
21 - default: uni.$u.props.codeInput.hairline  
22 - },  
23 - // 字符间的距离  
24 - space: {  
25 - type: [String, Number],  
26 - default: uni.$u.props.codeInput.space  
27 - },  
28 - // 预置值  
29 - value: {  
30 - type: [String, Number],  
31 - default: uni.$u.props.codeInput.value  
32 - },  
33 - // 是否自动获取焦点  
34 - focus: {  
35 - type: Boolean,  
36 - default: uni.$u.props.codeInput.focus  
37 - },  
38 - // 字体是否加粗  
39 - bold: {  
40 - type: Boolean,  
41 - default: uni.$u.props.codeInput.bold  
42 - },  
43 - // 字体颜色  
44 - color: {  
45 - type: String,  
46 - default: uni.$u.props.codeInput.color  
47 - },  
48 - // 字体大小  
49 - fontSize: {  
50 - type: [String, Number],  
51 - default: uni.$u.props.codeInput.fontSize  
52 - },  
53 - // 输入框的大小,宽等于高  
54 - size: {  
55 - type: [String, Number],  
56 - default: uni.$u.props.codeInput.size  
57 - },  
58 - // 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true  
59 - disabledKeyboard: {  
60 - type: Boolean,  
61 - default: uni.$u.props.codeInput.disabledKeyboard  
62 - },  
63 - // 边框和线条颜色  
64 - borderColor: {  
65 - type: String,  
66 - default: uni.$u.props.codeInput.borderColor  
67 - },  
68 - // 是否禁止输入"."符号  
69 - disabledDot: {  
70 - type: Boolean,  
71 - default: uni.$u.props.codeInput.disabledDot  
72 - }  
73 - }  
74 -}  
1 -<template>  
2 - <view class="u-code-input">  
3 - <view  
4 - class="u-code-input__item"  
5 - :style="[itemStyle(index)]"  
6 - v-for="(item, index) in codeLength"  
7 - :key="index"  
8 - >  
9 - <view  
10 - class="u-code-input__item__dot"  
11 - v-if="dot && codeArray.length > index"  
12 - ></view>  
13 - <text  
14 - v-else  
15 - :style="{  
16 - fontSize: $u.addUnit(fontSize),  
17 - fontWeight: bold ? 'bold' : 'normal',  
18 - color: color  
19 - }"  
20 - >{{codeArray[index]}}</text>  
21 - <view  
22 - class="u-code-input__item__line"  
23 - v-if="mode === 'line'"  
24 - :style="[lineStyle]"  
25 - ></view>  
26 - </view>  
27 - <input  
28 - :disabled="disabledKeyboard"  
29 - type="number"  
30 - :focus="focus"  
31 - :value="inputValue"  
32 - :maxlength="maxlength"  
33 - class="u-code-input__input"  
34 - @input="inputHandler"  
35 - :style="{  
36 - height: $u.addUnit(size)  
37 - }"  
38 - />  
39 - </view>  
40 -</template>  
41 -  
42 -<script>  
43 - import props from './props.js';  
44 - /**  
45 - * CodeInput 验证码输入  
46 - * @description 该组件一般用于验证用户短信验证码的场景,也可以结合uView的键盘组件使用  
47 - * @tutorial https://www.uviewui.com/components/codeInput.html  
48 - * @property {String | Number} maxlength 最大输入长度 (默认 6 )  
49 - * @property {Boolean} dot 是否用圆点填充 (默认 false )  
50 - * @property {String} mode 显示模式,box-盒子模式,line-底部横线模式 (默认 'box' )  
51 - * @property {Boolean} hairline 是否细边框 (默认 false )  
52 - * @property {String | Number} space 字符间的距离 (默认 10 )  
53 - * @property {String | Number} value 预置值  
54 - * @property {Boolean} focus 是否自动获取焦点 (默认 false )  
55 - * @property {Boolean} bold 字体和输入横线是否加粗 (默认 false )  
56 - * @property {String} color 字体颜色 (默认 '#606266' )  
57 - * @property {String | Number} fontSize 字体大小,单位px (默认 18 )  
58 - * @property {String | Number} size 输入框的大小,宽等于高 (默认 35 )  
59 - * @property {Boolean} disabledKeyboard 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true (默认 false )  
60 - * @property {String} borderColor 边框和线条颜色 (默认 '#c9cacc' )  
61 - * @property {Boolean} disabledDot 是否禁止输入"."符号 (默认 true )  
62 - *  
63 - * @event {Function} change 输入内容发生改变时触发,具体见上方说明 value:当前输入的值  
64 - * @event {Function} finish 输入字符个数达maxlength值时触发,见上方说明 value:当前输入的值  
65 - * @example <u-code-input v-model="value4" :focus="true"></u-code-input>  
66 - */  
67 - export default {  
68 - name: 'u-code-input',  
69 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
70 - data() {  
71 - return {  
72 - inputValue: ''  
73 - }  
74 - },  
75 - watch: {  
76 - value: {  
77 - immediate: true,  
78 - handler(val) {  
79 - // 转为字符串,超出部分截掉  
80 - this.inputValue = String(val).substring(0, this.maxlength)  
81 - }  
82 - },  
83 - },  
84 - computed: {  
85 - // 根据长度,循环输入框的个数,因为头条小程序数值不能用于v-for  
86 - codeLength() {  
87 - return new Array(Number(this.maxlength))  
88 - },  
89 - // 循环item的样式  
90 - itemStyle() {  
91 - return index => {  
92 - const addUnit = uni.$u.addUnit  
93 - const style = {  
94 - width: addUnit(this.size),  
95 - height: addUnit(this.size)  
96 - }  
97 - // 盒子模式下,需要额外进行处理  
98 - if (this.mode === 'box') {  
99 - // 设置盒子的边框,如果是细边框,则设置为0.5px宽度  
100 - style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}`  
101 - // 如果盒子间距为0的话  
102 - if (uni.$u.getPx(this.space) === 0) {  
103 - // 给第一和最后一个盒子设置圆角  
104 - if (index === 0) {  
105 - style.borderTopLeftRadius = '3px'  
106 - style.borderBottomLeftRadius = '3px'  
107 - }  
108 - if (index === this.codeLength.length - 1) {  
109 - style.borderTopRightRadius = '3px'  
110 - style.borderBottomRightRadius = '3px'  
111 - }  
112 - // 最后一个盒子的右边框需要保留  
113 - if (index !== this.codeLength.length - 1) {  
114 - style.borderRight = 'none'  
115 - }  
116 - }  
117 - }  
118 - if (index !== this.codeLength.length - 1) {  
119 - // 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框  
120 - style.marginRight = addUnit(this.space)  
121 - } else {  
122 - // 最后一个盒子的有边框需要保留  
123 - style.marginRight = 0  
124 - }  
125 -  
126 - return style  
127 - }  
128 - },  
129 - // 将输入的值,转为数组,给item历遍时,根据当前的索引显示数组的元素  
130 - codeArray() {  
131 - return String(this.inputValue).split('')  
132 - },  
133 - // 下划线模式下,横线的样式  
134 - lineStyle() {  
135 - const style = {}  
136 - style.height = this.hairline ? '2px' : '4px'  
137 - style.width = uni.$u.addUnit(this.size)  
138 - // 线条模式下,背景色即为边框颜色  
139 - style.backgroundColor = this.borderColor  
140 - return style  
141 - }  
142 - },  
143 - methods: {  
144 - // 监听输入框的值发生变化  
145 - inputHandler(e) {  
146 - const value = e.detail.value  
147 - this.inputValue = value  
148 - // 是否允许输入“.”符号  
149 - if(this.disabledDot) {  
150 - this.$nextTick(() => {  
151 - this.inputValue = value.replace('.', '')  
152 - })  
153 - }  
154 - // 未达到maxlength之前,发送change事件,达到后发送finish事件  
155 - this.$emit('change', value)  
156 - // 修改通过v-model双向绑定的值  
157 - this.$emit('input', value)  
158 - // 达到用户指定输入长度时,发出完成事件  
159 - if (String(value).length >= Number(this.maxlength)) {  
160 - this.$emit('finish', value)  
161 - }  
162 - }  
163 - }  
164 - }  
165 -</script>  
166 -  
167 -<style lang="scss" scoped>  
168 - @import "../../libs/css/components.scss";  
169 -  
170 - .u-code-input {  
171 - @include flex;  
172 - position: relative;  
173 - overflow: hidden;  
174 -  
175 - &__item {  
176 - @include flex;  
177 - justify-content: center;  
178 - align-items: center;  
179 -  
180 - &__text {  
181 - font-size: 15px;  
182 - color: $u-content-color;  
183 - }  
184 -  
185 - &__dot {  
186 - width: 7px;  
187 - height: 7px;  
188 - border-radius: 100px;  
189 - background-color: $u-content-color;  
190 - }  
191 -  
192 - &__line {  
193 - position: absolute;  
194 - bottom: 0;  
195 - height: 4px;  
196 - border-radius: 100px;  
197 - width: 40px;  
198 - background-color: $u-content-color;  
199 - }  
200 - }  
201 -  
202 - &__input {  
203 - // 之所以需要input输入框,是因为有它才能唤起键盘  
204 - // 这里将它设置为两倍的屏幕宽度,再将左边的一半移出屏幕,为了不让用户看到输入的内容  
205 - position: absolute;  
206 - left: -750rpx;  
207 - width: 1500rpx;  
208 - top: 0;  
209 - background-color: transparent;  
210 - text-align: left;  
211 - }  
212 - }  
213 -</style>  
1 -export default {  
2 - props: {  
3 - // 倒计时总秒数  
4 - seconds: {  
5 - type: [String, Number],  
6 - default: uni.$u.props.code.seconds  
7 - },  
8 - // 尚未开始时提示  
9 - startText: {  
10 - type: String,  
11 - default: uni.$u.props.code.startText  
12 - },  
13 - // 正在倒计时中的提示  
14 - changeText: {  
15 - type: String,  
16 - default: uni.$u.props.code.changeText  
17 - },  
18 - // 倒计时结束时的提示  
19 - endText: {  
20 - type: String,  
21 - default: uni.$u.props.code.endText  
22 - },  
23 - // 是否在H5刷新或各端返回再进入时继续倒计时  
24 - keepRunning: {  
25 - type: Boolean,  
26 - default: uni.$u.props.code.keepRunning  
27 - },  
28 - // 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了  
29 - uniqueKey: {  
30 - type: String,  
31 - default: uni.$u.props.code.uniqueKey  
32 - }  
33 - }  
34 -}  
1 -<template>  
2 - <view class="u-code">  
3 - <!-- 此组件功能由js完成,无需写html逻辑 -->  
4 - </view>  
5 -</template>  
6 -  
7 -<script>  
8 - import props from './props.js';  
9 - /**  
10 - * Code 验证码输入框  
11 - * @description 考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件 不提供界面显示,只提供提示语,由用户将提示语嵌入到具体的场景  
12 - * @tutorial https://www.uviewui.com/components/code.html  
13 - * @property {String | Number} seconds 倒计时所需的秒数(默认 60 )  
14 - * @property {String} startText 开始前的提示语,见官网说明(默认 '获取验证码' )  
15 - * @property {String} changeText 倒计时期间的提示语,必须带有字母"x",见官网说明(默认 'X秒重新获取' )  
16 - * @property {String} endText 倒计结束的提示语,见官网说明(默认 '重新获取' )  
17 - * @property {Boolean} keepRunning 是否在H5刷新或各端返回再进入时继续倒计时( 默认false )  
18 - * @property {String} uniqueKey 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了  
19 - *  
20 - * @event {Function} change 倒计时期间,每秒触发一次  
21 - * @event {Function} start 开始倒计时触发  
22 - * @event {Function} end 结束倒计时触发  
23 - * @example <u-code ref="uCode" @change="codeChange" seconds="20"></u-code>  
24 - */  
25 - export default {  
26 - name: "u-code",  
27 - mixins: [uni.$u.mpMixin, uni.$u.mixin,props],  
28 - data() {  
29 - return {  
30 - secNum: this.seconds,  
31 - timer: null,  
32 - canGetCode: true, // 是否可以执行验证码操作  
33 - }  
34 - },  
35 - mounted() {  
36 - this.checkKeepRunning()  
37 - },  
38 - watch: {  
39 - seconds: {  
40 - immediate: true,  
41 - handler(n) {  
42 - this.secNum = n  
43 - }  
44 - }  
45 - },  
46 - methods: {  
47 - checkKeepRunning() {  
48 - // 获取上一次退出页面(H5还包括刷新)时的时间戳,如果没有上次的保存,此值可能为空  
49 - let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'))  
50 - if(!lastTimestamp) return this.changeEvent(this.startText)  
51 - // 当前秒的时间戳  
52 - let nowTimestamp = Math.floor((+ new Date()) / 1000)  
53 - // 判断当前的时间戳,是否小于上一次的本该按设定结束,却提前结束的时间戳  
54 - if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {  
55 - // 剩余尚未执行完的倒计秒数  
56 - this.secNum = lastTimestamp - nowTimestamp  
57 - // 清除本地保存的变量  
58 - uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp')  
59 - // 开始倒计时  
60 - this.start()  
61 - } else {  
62 - // 如果不存在需要继续上一次的倒计时,执行正常的逻辑  
63 - this.changeEvent(this.startText)  
64 - }  
65 - },  
66 - // 开始倒计时  
67 - start() {  
68 - // 防止快速点击获取验证码的按钮而导致内部产生多个定时器导致混乱  
69 - if(this.timer) {  
70 - clearInterval(this.timer)  
71 - this.timer = null  
72 - }  
73 - this.$emit('start')  
74 - this.canGetCode = false  
75 - // 这里放这句,是为了一开始时就提示,否则要等setInterval的1秒后才会有提示  
76 - this.changeEvent(this.changeText.replace(/x|X/, this.secNum))  
77 - this.setTimeToStorage()  
78 - this.timer = setInterval(() => {  
79 - if (--this.secNum) {  
80 - // 用当前倒计时的秒数替换提示字符串中的"x"字母  
81 - this.changeEvent(this.changeText.replace(/x|X/, this.secNum))  
82 - } else {  
83 - clearInterval(this.timer)  
84 - this.timer = null  
85 - this.changeEvent(this.endText)  
86 - this.secNum = this.seconds  
87 - this.$emit('end')  
88 - this.canGetCode = true  
89 - }  
90 - }, 1000)  
91 - },  
92 - // 重置,可以让用户再次获取验证码  
93 - reset() {  
94 - this.canGetCode = true  
95 - clearInterval(this.timer)  
96 - this.secNum = this.seconds  
97 - this.changeEvent(this.endText)  
98 - },  
99 - changeEvent(text) {  
100 - this.$emit('change', text)  
101 - },  
102 - // 保存时间戳,为了防止倒计时尚未结束,H5刷新或者各端的右上角返回上一页再进来  
103 - setTimeToStorage() {  
104 - if(!this.keepRunning || !this.timer) return  
105 - // 记录当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时  
106 - // 倒计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理  
107 - if(this.secNum > 0 && this.secNum <= this.seconds) {  
108 - // 获取当前时间戳(+ new Date()为特殊写法),除以1000变成秒,再去除小数部分  
109 - let nowTimestamp = Math.floor((+ new Date()) / 1000)  
110 - // 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数  
111 - uni.setStorage({  
112 - key: this.uniqueKey + '_$uCountDownTimestamp',  
113 - data: nowTimestamp + Number(this.secNum)  
114 - })  
115 - }  
116 - }  
117 - },  
118 - // 组件销毁的时候,清除定时器,否则定时器会继续存在,系统不会自动清除  
119 - beforeDestroy() {  
120 - this.setTimeToStorage()  
121 - clearTimeout(this.timer)  
122 - this.timer = null  
123 - }  
124 - }  
125 -</script>  
126 -  
127 -<style lang="scss" scoped>  
128 - @import "../../libs/css/components.scss";  
129 -</style>  
1 -export default {  
2 - props: {  
3 - // 宫格的name  
4 - name: {  
5 - type: [String, Number, null],  
6 - default: uni.$u.props.gridItem.name  
7 - },  
8 - // 背景颜色  
9 - bgColor: {  
10 - type: String,  
11 - default: uni.$u.props.gridItem.bgColor  
12 - }  
13 - }  
14 -}  
1 -<template>  
2 - <!-- #ifndef APP-NVUE -->  
3 - <view  
4 - class="u-grid-item"  
5 - hover-class="u-grid-item--hover-class"  
6 - :hover-stay-time="200"  
7 - @tap="clickHandler"  
8 - :class="classes"  
9 - :style="[itemStyle]"  
10 - >  
11 - <slot />  
12 - </view>  
13 - <!-- #endif -->  
14 - <!-- #ifdef APP-NVUE -->  
15 - <view  
16 - class="u-grid-item"  
17 - :hover-stay-time="200"  
18 - @tap="clickHandler"  
19 - :class="classes"  
20 - :style="[itemStyle]"  
21 - >  
22 - <slot />  
23 - </view>  
24 - <!-- #endif -->  
25 -</template>  
26 -  
27 -<script>  
28 - import props from './props.js';  
29 - /**  
30 - * gridItem 提示  
31 - * @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。搭配u-grid使用  
32 - * @tutorial https://www.uviewui.com/components/grid.html  
33 - * @property {String | Number} name 宫格的name ( 默认 null )  
34 - * @property {String} bgColor 宫格的背景颜色 (默认 'transparent' )  
35 - * @property {Object} customStyle 自定义样式,对象形式  
36 - * @event {Function} click 点击宫格触发  
37 - * @example <u-grid-item></u-grid-item>  
38 - */  
39 - export default {  
40 - name: "u-grid-item",  
41 - mixins: [uni.$u.mpMixin, uni.$u.mixin,props],  
42 - data() {  
43 - return {  
44 - parentData: {  
45 - col: 3, // 父组件划分的宫格数  
46 - border: true, // 是否显示边框,根据父组件决定  
47 - },  
48 - // #ifdef APP-NVUE  
49 - width: 0, // nvue下才这么计算,vue下放到computed中,否则会因为延时造成闪烁  
50 - // #endif  
51 - classes: [], // 类名集合,用于判断是否显示右边和下边框  
52 - };  
53 - },  
54 - mounted() {  
55 - this.init()  
56 - },  
57 - computed: {  
58 - // #ifndef APP-NVUE  
59 - // vue下放到computed中,否则会因为延时造成闪烁  
60 - width() {  
61 - return 100 / Number(this.parentData.col) + '%'  
62 - },  
63 - // #endif  
64 - itemStyle() {  
65 - const style = {  
66 - background: this.bgColor,  
67 - width: this.width  
68 - }  
69 - return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))  
70 - }  
71 - },  
72 - methods: {  
73 - init() {  
74 - // 用于在父组件u-grid的children中被添加入子组件时,  
75 - // 重新计算item的边框  
76 - uni.$on('$uGridItem', () => {  
77 - this.gridItemClasses()  
78 - })  
79 - // 父组件的实例  
80 - this.updateParentData()  
81 - // #ifdef APP-NVUE  
82 - // 获取元素该有的长度,nvue下要延时才准确  
83 - this.$nextTick(function(){  
84 - this.getItemWidth()  
85 - })  
86 - // #endif  
87 - // 发出事件,通知所有的grid-item都重新计算自己的边框  
88 - uni.$emit('$uGridItem')  
89 - this.gridItemClasses()  
90 - },  
91 - // 获取父组件的参数  
92 - updateParentData() {  
93 - // 此方法写在mixin中  
94 - this.getParentData('u-grid');  
95 - },  
96 - clickHandler() {  
97 - let name = this.name  
98 - // 如果没有设置name属性,历遍父组件的children数组,判断当前的元素是否和本实例this相等,找出当前组件的索引  
99 - const children = this.parent?.children  
100 - if(children && this.name === null) {  
101 - name = children.findIndex(child => child === this)  
102 - }  
103 - // 调用父组件方法,发出事件  
104 - this.parent && this.parent.childClick(name)  
105 - this.$emit('click', name)  
106 - },  
107 - async getItemWidth() {  
108 - // 如果是nvue,不能使用百分比,只能使用固定宽度  
109 - let width = 0  
110 - if(this.parent) {  
111 - // 获取父组件宽度后,除以栅格数,得出每个item的宽度  
112 - const parentWidth = await this.getParentWidth()  
113 - width = parentWidth / Number(this.parentData.col) + 'px'  
114 - }  
115 - this.width = width  
116 - },  
117 - // 获取父元素的尺寸  
118 - getParentWidth() {  
119 - // #ifdef APP-NVUE  
120 - // 返回一个promise,让调用者可以用await同步获取  
121 - const dom = uni.requireNativePlugin('dom')  
122 - return new Promise(resolve => {  
123 - // 调用父组件的ref  
124 - dom.getComponentRect(this.parent.$refs['u-grid'], res => {  
125 - resolve(res.size.width)  
126 - })  
127 - })  
128 - // #endif  
129 - },  
130 - gridItemClasses() {  
131 - if(this.parentData.border) {  
132 - const classes = []  
133 - this.parent.children.map((child, index) =>{  
134 - if(this === child) {  
135 - const len = this.parent.children.length  
136 - // 贴近右边屏幕边沿的child,并且最后一个(比如只有横向2个的时候),无需右边框  
137 - if((index + 1) % this.parentData.col !== 0 && index + 1 !== len) {  
138 - classes.push('u-border-right')  
139 - }  
140 - // 总的宫格数量对列数取余的值  
141 - // 如果取余后,值为0,则意味着要将最后一排的宫格,都不需要下边框  
142 - const lessNum = len % this.parentData.col === 0 ? this.parentData.col : len % this.parentData.col  
143 - // 最下面的一排child,无需下边框  
144 - if(index < len - lessNum) {  
145 - classes.push('u-border-bottom')  
146 - }  
147 - }  
148 - })  
149 - // 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效  
150 - // #ifdef MP-ALIPAY || MP-TOUTIAO  
151 - classes = classes.join(' ')  
152 - // #endif  
153 - this.classes = classes  
154 - }  
155 - }  
156 - },  
157 - beforeDestroy() {  
158 - // 移除事件监听,释放性能  
159 - uni.$off('$uGridItem')  
160 - }  
161 - };  
162 -</script>  
163 -  
164 -<style lang="scss" scoped>  
165 - @import "../../libs/css/components.scss";  
166 - $u-grid-item-hover-class-opcatiy:.5 !default;  
167 - $u-grid-item-margin-top:1rpx !default;  
168 - $u-grid-item-border-right-width:0.5px !default;  
169 - $u-grid-item-border-bottom-width:0.5px !default;  
170 - $u-grid-item-border-right-color:$u-border-color !default;  
171 - $u-grid-item-border-bottom-color:$u-border-color !default;  
172 - .u-grid-item {  
173 - align-items: center;  
174 - justify-content: center;  
175 - position: relative;  
176 - flex-direction: column;  
177 - /* #ifndef APP-NVUE */  
178 - box-sizing: border-box;  
179 - display: flex;  
180 - /* #endif */  
181 -  
182 - /* #ifdef MP */  
183 - position: relative;  
184 - float: left;  
185 - /* #endif */  
186 -  
187 - /* #ifdef MP-WEIXIN */  
188 - margin-top:$u-grid-item-margin-top;  
189 - /* #endif */  
190 -  
191 - &--hover-class {  
192 - opacity:$u-grid-item-hover-class-opcatiy;  
193 - }  
194 - }  
195 -  
196 - /* #ifdef APP-NVUE */  
197 - // 由于nvue不支持组件内引入app.vue中再引入的样式,所以需要写在这里  
198 - .u-border-right {  
199 - border-right-width:$u-grid-item-border-right-width;  
200 - border-color: $u-grid-item-border-right-color;  
201 - }  
202 -  
203 - .u-border-bottom {  
204 - border-bottom-width:$u-grid-item-border-bottom-width;  
205 - border-color:$u-grid-item-border-bottom-color;  
206 - }  
207 -  
208 - /* #endif */  
209 -</style>  
1 -export default {  
2 - props: {  
3 - // 分成几列  
4 - col: {  
5 - type: [String, Number],  
6 - default: uni.$u.props.grid.col  
7 - },  
8 - // 是否显示边框  
9 - border: {  
10 - type: Boolean,  
11 - default: uni.$u.props.grid.border  
12 - },  
13 - // 宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右  
14 - align: {  
15 - type: String,  
16 - default: uni.$u.props.grid.align  
17 - }  
18 - }  
19 -}  
1 -<template>  
2 - <view  
3 - class="u-grid"  
4 - ref='u-grid'  
5 - :style="[gridStyle]"  
6 - >  
7 - <slot />  
8 - </view>  
9 -</template>  
10 -  
11 -<script>  
12 - import props from './props.js';  
13 - /**  
14 - * grid 宫格布局  
15 - * @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。  
16 - * @tutorial https://www.uviewui.com/components/grid.html  
17 - * @property {String | Number} col 宫格的列数(默认 3 )  
18 - * @property {Boolean} border 是否显示宫格的边框(默认 false )  
19 - * @property {String} align 宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右 (默认 'left' )  
20 - * @property {Object} customStyle 定义需要用到的外部样式  
21 - * @event {Function} click 点击宫格触发  
22 - * @example <u-grid :col="3" @click="click"></u-grid>  
23 - */  
24 - export default {  
25 - name: 'u-grid',  
26 - mixins: [uni.$u.mpMixin, uni.$u.mixin,props],  
27 - data() {  
28 - return {  
29 - index: 0,  
30 - width: 0  
31 - }  
32 - },  
33 - watch: {  
34 - // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件  
35 - parentData() {  
36 - if (this.children.length) {  
37 - this.children.map(child => {  
38 - // 判断子组件(u-radio)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)  
39 - typeof(child.updateParentData) == 'function' && child.updateParentData();  
40 - })  
41 - }  
42 - },  
43 - },  
44 - created() {  
45 - // 如果将children定义在data中,在微信小程序会造成循环引用而报错  
46 - this.children = []  
47 - },  
48 - computed: {  
49 - // 计算父组件的值是否发生变化  
50 - parentData() {  
51 - return [this.hoverClass, this.col, this.size, this.border];  
52 - },  
53 - // 宫格对齐方式  
54 - gridStyle() {  
55 - let style = {};  
56 - switch (this.align) {  
57 - case 'left':  
58 - style.justifyContent = 'flex-start';  
59 - break;  
60 - case 'center':  
61 - style.justifyContent = 'center';  
62 - break;  
63 - case 'right':  
64 - style.justifyContent = 'flex-end';  
65 - break;  
66 - default:  
67 - style.justifyContent = 'flex-start';  
68 - };  
69 - return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle));  
70 - }  
71 - },  
72 - methods: {  
73 - // 此方法由u-grid-item触发,用于在u-grid发出事件  
74 - childClick(name) {  
75 - this.$emit('click', name)  
76 - }  
77 - }  
78 - };  
79 -</script>  
80 -  
81 -<style lang="scss" scoped>  
82 - @import "../../libs/css/components.scss";  
83 - $u-grid-width:100% !default;  
84 - .u-grid {  
85 - /* #ifdef MP */  
86 - width: $u-grid-width;  
87 - position: relative;  
88 - box-sizing: border-box;  
89 - overflow: hidden;  
90 - display: block;  
91 - /* #endif */  
92 - justify-content: center;  
93 - @include flex;  
94 - flex-wrap: wrap;  
95 - align-items: center;  
96 - }  
97 -</style>  
1 -export default {  
2 - props: {  
3 - // 标题  
4 - title: {  
5 - type: [String, Number],  
6 - default: uni.$u.props.stepsItem.title  
7 - },  
8 - // 描述文本  
9 - desc: {  
10 - type: [String, Number],  
11 - default: uni.$u.props.stepsItem.desc  
12 - },  
13 - // 图标大小  
14 - iconSize: {  
15 - type: [String, Number],  
16 - default: uni.$u.props.stepsItem.iconSize  
17 - },  
18 - // 当前步骤是否处于失败状态  
19 - error: {  
20 - type: Boolean,  
21 - default: uni.$u.props.stepsItem.error  
22 - }  
23 - }  
24 -}  
1 -<template>  
2 - <view class="u-steps-item" ref="u-steps-item" :class="[`u-steps-item--${parentData.direction}`]">  
3 - <view class="u-steps-item__line" v-if="index + 1 < childLength"  
4 - :class="[`u-steps-item__line--${parentData.direction}`]" :style="[lineStyle]"></view>  
5 - <view class="u-steps-item__wrapper"  
6 - :class="[`u-steps-item__wrapper--${parentData.direction}`, parentData.dot && `u-steps-item__wrapper--${parentData.direction}--dot`]">  
7 - <slot name="icon">  
8 - <view class="u-steps-item__wrapper__dot" v-if="parentData.dot" :style="{  
9 - backgroundColor: statusColor  
10 - }">  
11 -  
12 - </view>  
13 - <view class="u-steps-item__wrapper__icon" v-else-if="parentData.activeIcon || parentData.inactiveIcon">  
14 - <u-icon :name="index <= parentData.current ? parentData.activeIcon : parentData.inactiveIcon"  
15 - :size="iconSize"  
16 - :color="index <= parentData.current ? parentData.activeColor : parentData.inactiveColor">  
17 - </u-icon>  
18 - </view>  
19 - <view v-else :style="{  
20 - backgroundColor: statusClass === 'process' ? parentData.activeColor : 'transparent',  
21 - borderColor: statusColor  
22 - }" class="u-steps-item__wrapper__circle">  
23 - <text v-if="statusClass === 'process' || statusClass === 'wait'"  
24 - class="u-steps-item__wrapper__circle__text" :style="{  
25 - color: index == parentData.current ? '#ffffff' : parentData.inactiveColor  
26 - }">{{ index + 1}}</text>  
27 - <u-icon v-else :color="statusClass === 'error' ? 'error' : parentData.activeColor" size="12"  
28 - :name="statusClass === 'error' ? 'close' : 'checkmark'"></u-icon>  
29 - </view>  
30 - </slot>  
31 - </view>  
32 - <view class="u-steps-item__content" :class="[`u-steps-item__content--${parentData.direction}`]"  
33 - :style="[contentStyle]">  
34 - <u--text :text="title" :type="parentData.current == index ? 'main' : 'content'" lineHeight="20px"  
35 - :size="parentData.current == index ? 14 : 13"></u--text>  
36 - <slot name="desc">  
37 - <u--text :text="desc" type="tips" size="12"></u--text>  
38 - </slot>  
39 - </view>  
40 - <!-- <view  
41 - class="u-steps-item__line"  
42 - v-if="showLine && parentData.direction === 'column'"  
43 - :class="[`u-steps-item__line--${parentData.direction}`]"  
44 - :style="[lineStyle]"  
45 - ></view> -->  
46 - </view>  
47 -</template>  
48 -  
49 -<script>  
50 - import props from './props.js';  
51 - // #ifdef APP-NVUE  
52 - const dom = uni.requireNativePlugin('dom')  
53 - // #endif  
54 - /**  
55 - * StepsItem 步骤条的子组件  
56 - * @description 本组件需要和u-steps配合使用  
57 - * @tutorial https://uviewui.com/components/steps.html  
58 - * @property {String} title 标题文字  
59 - * @property {String} current 描述文本  
60 - * @property {String | Number} iconSize 图标大小 (默认 17 )  
61 - * @property {Boolean} error 当前步骤是否处于失败状态 (默认 false )  
62 - * @example <u-steps current="0"><u-steps-item title="已出库" desc="10:35" ></u-steps-item></u-steps>  
63 - */  
64 - export default {  
65 - name: 'u-steps-item',  
66 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
67 - data() {  
68 - return {  
69 - index: 0,  
70 - childLength: 0,  
71 - showLine: false,  
72 - size: {  
73 - height: 0,  
74 - width: 0  
75 - },  
76 - parentData: {  
77 - direction: 'row',  
78 - current: 0,  
79 - activeColor: '',  
80 - inactiveColor: '',  
81 - activeIcon: '',  
82 - inactiveIcon: '',  
83 - dot: false  
84 - }  
85 - }  
86 - },  
87 - watch: {  
88 - 'parentData'(newValue, oldValue) {  
89 - }  
90 - },  
91 - created() {  
92 - this.init()  
93 - },  
94 - computed: {  
95 - lineStyle() {  
96 - const style = {}  
97 - if (this.parentData.direction === 'row') {  
98 - style.width = this.size.width + 'px'  
99 - style.left = this.size.width / 2 + 'px'  
100 - } else {  
101 - style.height = this.size.height + 'px'  
102 - // style.top = this.size.height / 2 + 'px'  
103 - }  
104 - style.backgroundColor = this.parent.children?.[this.index + 1]?.error ? uni.$u.color.error : this.index <  
105 - this  
106 - .parentData  
107 - .current ? this.parentData.activeColor : this.parentData.inactiveColor  
108 - return style  
109 - },  
110 - statusClass() {  
111 - const {  
112 - index,  
113 - error  
114 - } = this  
115 - const {  
116 - current  
117 - } = this.parentData  
118 - if (current == index) {  
119 - return error === true ? 'error' : 'process'  
120 - } else if (error) {  
121 - return 'error'  
122 - } else if (current > index) {  
123 - return 'finish'  
124 - } else {  
125 - return 'wait'  
126 - }  
127 - },  
128 - statusColor() {  
129 - let color = ''  
130 - switch (this.statusClass) {  
131 - case 'finish':  
132 - color = this.parentData.activeColor  
133 - break  
134 - case 'error':  
135 - color = uni.$u.color.error  
136 - break  
137 - case 'process':  
138 - color = this.parentData.dot ? this.parentData.activeColor : 'transparent'  
139 - break  
140 - default:  
141 - color = this.parentData.inactiveColor  
142 - break  
143 - }  
144 - return color  
145 - },  
146 - contentStyle() {  
147 - const style = {}  
148 - if (this.parentData.direction === 'column') {  
149 - style.marginLeft = this.parentData.dot ? '2px' : '6px'  
150 - style.marginTop = this.parentData.dot ? '0px' : '6px'  
151 - } else {  
152 - style.marginTop = this.parentData.dot ? '2px' : '6px'  
153 - style.marginLeft = this.parentData.dot ? '2px' : '6px'  
154 - }  
155 -  
156 - return style  
157 - }  
158 - },  
159 - mounted() {  
160 - this.parent && this.parent.updateFromChild()  
161 - uni.$u.sleep().then(() => {  
162 - this.getStepsItemRect()  
163 - })  
164 - },  
165 - methods: {  
166 - init() {  
167 - // 初始化数据  
168 - this.updateParentData()  
169 - if (!this.parent) {  
170 - return uni.$u.error('u-steps-item必须要搭配u-steps组件使用')  
171 - }  
172 - this.index = this.parent.children.indexOf(this)  
173 - this.childLength = this.parent.children.length  
174 - },  
175 - updateParentData() {  
176 - // 此方法在mixin中  
177 - this.getParentData('u-steps')  
178 - },  
179 - // 父组件数据发生变化  
180 - updateFromParent() {  
181 - this.init()  
182 - },  
183 - // 获取组件的尺寸,用于设置横线的位置  
184 - getStepsItemRect() {  
185 - // #ifndef APP-NVUE  
186 - this.$uGetRect('.u-steps-item').then(size => {  
187 - this.size = size  
188 - })  
189 - // #endif  
190 -  
191 - // #ifdef APP-NVUE  
192 - dom.getComponentRect(this.$refs['u-steps-item'], res => {  
193 - const {  
194 - size  
195 - } = res  
196 - this.size = size  
197 - })  
198 - // #endif  
199 - }  
200 - }  
201 - }  
202 -</script>  
203 -  
204 -<style lang="scss" scoped>  
205 - @import "../../libs/css/components.scss";  
206 -  
207 - .u-steps-item {  
208 - flex: 1;  
209 - @include flex;  
210 -  
211 - &--row {  
212 - flex-direction: column;  
213 - align-items: center;  
214 - position: relative;  
215 - }  
216 -  
217 - &--column {  
218 - position: relative;  
219 - flex-direction: row;  
220 - justify-content: flex-start;  
221 - padding-bottom: 5px;  
222 - }  
223 -  
224 - &__wrapper {  
225 - @include flex;  
226 - justify-content: center;  
227 - align-items: center;  
228 - position: relative;  
229 - background-color: #fff;  
230 -  
231 - &--column {  
232 - width: 20px;  
233 - height: 32px;  
234 -  
235 - &--dot {  
236 - height: 20px;  
237 - width: 20px;  
238 - }  
239 - }  
240 -  
241 - &--row {  
242 - width: 32px;  
243 - height: 20px;  
244 -  
245 - &--dot {  
246 - width: 20px;  
247 - height: 20px;  
248 - }  
249 - }  
250 -  
251 - &__circle {  
252 - width: 20px;  
253 - height: 20px;  
254 - /* #ifndef APP-NVUE */  
255 - box-sizing: border-box;  
256 - flex-shrink: 0;  
257 - /* #endif */  
258 - border-radius: 100px;  
259 - border-width: 1px;  
260 - border-color: $u-tips-color;  
261 - border-style: solid;  
262 - @include flex(row);  
263 - align-items: center;  
264 - justify-content: center;  
265 - transition: background-color 0.3s;  
266 -  
267 - &__text {  
268 - color: $u-tips-color;  
269 - font-size: 11px;  
270 - @include flex(row);  
271 - align-items: center;  
272 - justify-content: center;  
273 - text-align: center;  
274 - line-height: 11px;  
275 - }  
276 - }  
277 -  
278 - &__dot {  
279 - width: 10px;  
280 - height: 10px;  
281 - border-radius: 100px;  
282 - background-color: $u-content-color;  
283 - }  
284 - }  
285 -  
286 - &__content {  
287 - @include flex;  
288 - flex: 1;  
289 -  
290 - &--row {  
291 - flex-direction: column;  
292 - align-items: center;  
293 - }  
294 -  
295 - &--column {  
296 - flex-direction: column;  
297 - margin-left: 6px;  
298 - }  
299 - }  
300 -  
301 - &__line {  
302 - position: absolute;  
303 - background: $u-tips-color;  
304 -  
305 - &--row {  
306 - top: 10px;  
307 - height: 1px;  
308 - }  
309 -  
310 - &--column {  
311 - width: 1px;  
312 - left: 10px;  
313 - }  
314 - }  
315 - }  
316 -</style>  
1 -export default {  
2 - props: {  
3 - // 排列方向  
4 - direction: {  
5 - type: String,  
6 - default: uni.$u.props.steps.direction  
7 - },  
8 - // 设置第几个步骤  
9 - current: {  
10 - type: [String, Number],  
11 - default: uni.$u.props.steps.current  
12 - },  
13 - // 激活状态颜色  
14 - activeColor: {  
15 - type: String,  
16 - default: uni.$u.props.steps.activeColor  
17 - },  
18 - // 未激活状态颜色  
19 - inactiveColor: {  
20 - type: String,  
21 - default: uni.$u.props.steps.inactiveColor  
22 - },  
23 - // 激活状态的图标  
24 - activeIcon: {  
25 - type: String,  
26 - default: uni.$u.props.steps.activeIcon  
27 - },  
28 - // 未激活状态图标  
29 - inactiveIcon: {  
30 - type: String,  
31 - default: uni.$u.props.steps.inactiveIcon  
32 - },  
33 - // 是否显示点类型  
34 - dot: {  
35 - type: Boolean,  
36 - default: uni.$u.props.steps.dot  
37 - }  
38 - }  
39 -}  
1 -<template>  
2 - <view  
3 - class="u-steps"  
4 - :class="[`u-steps--${direction}`]"  
5 - >  
6 - <slot></slot>  
7 - </view>  
8 -</template>  
9 -  
10 -<script>  
11 - import props from './props.js';  
12 - /**  
13 - * Steps 步骤条  
14 - * @description 该组件一般用于完成一个任务要分几个步骤,标识目前处于第几步的场景。  
15 - * @tutorial https://uviewui.com/components/steps.html  
16 - * @property {String} direction row-横向,column-竖向 (默认 'row' )  
17 - * @property {String | Number} current 设置当前处于第几步 (默认 0 )  
18 - * @property {String} activeColor 激活状态颜色 (默认 '#3c9cff' )  
19 - * @property {String} inactiveColor 未激活状态颜色 (默认 '#969799' )  
20 - * @property {String} activeIcon 激活状态的图标  
21 - * @property {String} inactiveIcon 未激活状态图标  
22 - * @property {Boolean} dot 是否显示点类型 (默认 false )  
23 - * @example <u-steps current="0"><u-steps-item title="已出库" desc="10:35" ></u-steps-item></u-steps>  
24 - */  
25 - export default {  
26 - name: 'u-steps',  
27 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
28 - data() {  
29 - return {  
30 - }  
31 - },  
32 - watch: {  
33 - children() {  
34 - this.updateChildData()  
35 - },  
36 - parentData() {  
37 - this.updateChildData()  
38 - }  
39 - },  
40 - computed: {  
41 - // 监听参数的变化,通过watch中,手动去更新子组件的数据,否则子组件不会自动变化  
42 - parentData() {  
43 - return [this.current, this.direction, this.activeColor, this.inactiveColor, this.activeIcon, this.inactiveIcon, this.dot]  
44 - }  
45 - },  
46 - methods: {  
47 - // 更新子组件的数据  
48 - updateChildData() {  
49 - this.children.map(child => {  
50 - // 先判断子组件是否存在对应的方法  
51 - uni.$u.test.func((child || {}).updateFromParent()) && child.updateFromParent()  
52 - })  
53 - },  
54 - // 接受子组件的通知,去修改其他子组件的数据  
55 - updateFromChild() {  
56 - this.updateChildData()  
57 - }  
58 - },  
59 - created() {  
60 - this.children = []  
61 - }  
62 - }  
63 -</script>  
64 -  
65 -<style lang="scss" scoped>  
66 - @import "../../libs/css/components.scss";  
67 -  
68 - .u-steps {  
69 - @include flex;  
70 -  
71 - &--column {  
72 - flex-direction: column  
73 - }  
74 -  
75 - &--row {  
76 - flex-direction: row;  
77 - flex: 1;  
78 - }  
79 - }  
80 -</style>  
1 -/**  
2 - * 此为wxs模块,只支持APP-VUE,微信和QQ小程序以及H5平台  
3 - * wxs内部不支持es6语法,变量只能使用var定义,无法使用解构,箭头函数等特性  
4 - */  
5 -  
6 -// 开始触摸  
7 -function touchstart(event, ownerInstance) {  
8 - // 触发事件的组件的ComponentDescriptor实例  
9 - var instance = event.instance  
10 - // wxs内的局部变量快照,此快照是属于整个组件的,在touchstart和touchmove事件中都能获取到相同的结果  
11 - var state = instance.getState()  
12 - if (state.disable) return  
13 - var touches = event.touches  
14 - // 如果进行的是多指触控,不允许进行操作  
15 - if (touches && touches.length > 1) return  
16 - // 标识当前为滑动中状态  
17 - state.moving = true  
18 - // 记录触摸开始点的坐标值  
19 - state.startX = touches[0].pageX  
20 - state.startY = touches[0].pageY  
21 -}  
22 -  
23 -// 触摸滑动  
24 -function touchmove(event, ownerInstance) {  
25 - // 触发事件的组件的ComponentDescriptor实例  
26 - var instance = event.instance  
27 - // wxs内的局部变量快照  
28 - var state = instance.getState()  
29 - if (state.disabled || !state.moving) return  
30 -  
31 - var touches = event.touches  
32 - var pageX = touches[0].pageX  
33 - var pageY = touches[0].pageY  
34 - var moveX = pageX - state.startX  
35 - var moveY = pageY - state.startY  
36 - var buttonsWidth = state.buttonsWidth  
37 -  
38 - // 移动的X轴距离大于Y轴距离,也即终点与起点位置连线,与X轴夹角小于45度时,禁止页面滚动  
39 - if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > state.threshold) {  
40 - event.preventDefault()  
41 - event.stopPropagation()  
42 - }  
43 - // 如果移动的X轴距离小于Y轴距离,也即终点位置与起点位置连线,与Y轴夹角小于45度时,认为是页面上下滑动,而不是左右滑动单元格  
44 - if (Math.abs(moveX) < Math.abs(moveY)) return  
45 -  
46 - // 限制右滑的距离,不允许内容部分往右偏移,右滑会导致X轴偏移值大于0,以此做判断  
47 - // 此处不能直接return,因为滑动过程中会缺失某些关键点坐标,会导致错乱,最好的办法就是  
48 - // 在超出后,设置为0  
49 - if (state.status === 'open') {  
50 - // 在开启状态下,向左滑动,需忽略  
51 - if (moveX < 0) moveX = 0  
52 - // 想要收起菜单,最大能移动的距离为按钮的总宽度  
53 - if (moveX > buttonsWidth) moveX = buttonsWidth  
54 - // 如果是已经打开了的状态,向左滑动时,移动收起菜单  
55 - moveSwipeAction(-buttonsWidth + moveX, instance, ownerInstance)  
56 - } else {  
57 - // 关闭状态下,右滑动需忽略  
58 - if (moveX > 0) moveX = 0  
59 - // 滑动的距离不允许超过所有按钮的总宽度,此时只能是左滑,最终设置按钮的总宽度,同时为负数  
60 - if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth  
61 - // 只要是在滑过程中,就不断移动菜单的内容部分,从而使隐藏的菜单显示出来  
62 - moveSwipeAction(moveX, instance, ownerInstance)  
63 - }  
64 -}  
65 -  
66 -// 触摸结束  
67 -function touchend(event, ownerInstance) {  
68 - // 触发事件的组件的ComponentDescriptor实例  
69 - var instance = event.instance  
70 - // wxs内的局部变量快照  
71 - var state = instance.getState()  
72 - if (!state.moving || state.disabled) return  
73 - var touches = event.changedTouches ? event.changedTouches[0] : {}  
74 - var pageX = touches.pageX  
75 - var pageY = touches.pageY  
76 - var moveX = pageX - state.startX  
77 - if (state.status === 'open') {  
78 - // 在展开的状态下,继续左滑,无需操作  
79 - if (moveX < 0) return  
80 - // 在开启状态下,点击一下内容区域,moveX为0,也即没有进行移动,这时执行收起菜单逻辑  
81 - if (moveX === 0) {  
82 - return closeSwipeAction(instance, ownerInstance)  
83 - }  
84 - // 在开启状态下,滑动距离小于阈值,则默认为不关闭,同时恢复原来的打开状态  
85 - if (Math.abs(moveX) < state.threshold) {  
86 - openSwipeAction(instance, ownerInstance)  
87 - } else {  
88 - // 如果滑动距离大于阈值,则执行收起逻辑  
89 - closeSwipeAction(instance, ownerInstance)  
90 - }  
91 - } else {  
92 - // 在关闭的状态下,右滑,无需操作  
93 - if (moveX > 0) return  
94 - // 理由同上  
95 - if (Math.abs(moveX) < state.threshold) {  
96 - closeSwipeAction(instance, ownerInstance)  
97 - } else {  
98 - openSwipeAction(instance, ownerInstance)  
99 - }  
100 - }  
101 -}  
102 -  
103 -// 获取过渡时间  
104 -function getDuration(value) {  
105 - if (value.toString().indexOf('s') >= 0) return value  
106 - return value > 30 ? value + 'ms' : value + 's'  
107 -}  
108 -  
109 -// 滑动结束时判断滑动的方向  
110 -function getMoveDirection(instance, ownerInstance) {  
111 - var state = instance.getState()  
112 -}  
113 -  
114 -// 移动滑动选择器内容区域,同时显示出其隐藏的菜单  
115 -function moveSwipeAction(moveX, instance, ownerInstance) {  
116 - var state = instance.getState()  
117 - // 获取所有按钮的实例,需要通过它去设置按钮的位移  
118 - var buttons = ownerInstance.selectAllComponents('.u-swipe-action-item__right__button')  
119 - var len = buttons.length  
120 - var previewButtonsMoveX = 0  
121 -  
122 - // 设置菜单内容部分的偏移  
123 - instance.requestAnimationFrame(function() {  
124 - instance.setStyle({  
125 - // 设置translateX的值  
126 - 'transition': 'none',  
127 - transform: 'translateX(' + moveX + 'px)',  
128 - '-webkit-transform': 'translateX(' + moveX + 'px)'  
129 - })  
130 - // 折叠按钮动画  
131 - for (var i = len - 1; i >= 0; i--) {  
132 - // 通过比例,得出元素自身该移动的距离  
133 - var translateX = state.buttons[i].width / state.buttonsWidth * moveX  
134 - // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和  
135 - var realTranslateX = translateX + previewButtonsMoveX  
136 - buttons[i].setStyle({  
137 - // 在移动期间,不能使用过渡效果,否则会造成卡顿,本质原因是每次移动一点,就要花一定时间去过渡这个过程  
138 - 'transition': 'none',  
139 - 'transform': 'translateX(' + realTranslateX + 'px)',  
140 - '-webkit-transform': 'translateX(' + realTranslateX + 'px)'  
141 - })  
142 - // 记录本按钮之前的所有按钮的移动距离之和  
143 - previewButtonsMoveX += translateX  
144 - }  
145 - })  
146 -}  
147 -  
148 -// 一次性展开滑动菜单  
149 -function openSwipeAction(instance, ownerInstance) {  
150 - var state = instance.getState()  
151 - // 获取所有按钮的实例,需要通过它去设置按钮的位移  
152 - var buttons = ownerInstance.selectAllComponents('.u-swipe-action-item__right__button')  
153 - var len = buttons.length  
154 - // 处理duration单位问题  
155 - const duration = getDuration(state.duration)  
156 - // 展开过程中,是向左移动,所以X的偏移应该为负值  
157 - var buttonsWidth = -state.buttonsWidth  
158 - var previewButtonsMoveX = 0  
159 - instance.requestAnimationFrame(function() {  
160 - // 设置菜单主体内容  
161 - instance.setStyle({  
162 - 'transition': 'transform ' + duration,  
163 - 'transform': 'translateX(' + buttonsWidth + 'px)',  
164 - '-webkit-transform': 'translateX(' + buttonsWidth + 'px)',  
165 - })  
166 - // 设置各个隐藏的按钮为展开的状态  
167 - for (var i = len - 1; i >= 0; i--) {  
168 - // 通过比例,得出元素自身该移动的距离  
169 - var translateX = state.buttons[i].width / state.buttonsWidth * buttonsWidth  
170 - // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和  
171 - var realTranslateX = translateX + previewButtonsMoveX  
172 - buttons[i].setStyle({  
173 - // 在移动期间,需要加上动画效果  
174 - 'transition': 'transform ' + duration,  
175 - 'transform': 'translateX(' + realTranslateX + 'px)',  
176 - '-webkit-transform': 'translateX(' + realTranslateX + 'px)'  
177 - })  
178 - // 记录本按钮之前的所有按钮的移动距离之和  
179 - previewButtonsMoveX += translateX  
180 - }  
181 - })  
182 - setStatus('open', instance)  
183 -}  
184 -  
185 -// 标记菜单的当前状态,open-已经打开,close-已经关闭  
186 -function setStatus(status, instance) {  
187 - var state = instance.getState()  
188 - state.status = status  
189 -}  
190 -  
191 -// 一次性收起滑动菜单  
192 -function closeSwipeAction(instance, ownerInstance) {  
193 - var state = instance.getState()  
194 - // 获取所有按钮的实例,需要通过它去设置按钮的位移  
195 - var buttons = ownerInstance.selectAllComponents('.u-swipe-action-item__right__button')  
196 - var len = buttons.length  
197 - // 处理duration单位问题  
198 - const duration = getDuration(state.duration)  
199 - instance.requestAnimationFrame(function() {  
200 - // 设置菜单主体内容  
201 - instance.setStyle({  
202 - 'transition': 'transform ' + duration,  
203 - 'transform': 'translateX(0px)',  
204 - '-webkit-transform': 'translateX(0px)'  
205 - })  
206 - // 设置各个隐藏的按钮为收起的状态  
207 - for (var i = len - 1; i >= 0; i--) {  
208 - buttons[i].setStyle({  
209 - 'transition': 'transform ' + duration,  
210 - 'transform': 'translateX(0px)',  
211 - '-webkit-transform': 'translateX(0px)'  
212 - })  
213 - }  
214 - })  
215 - setStatus('close', instance)  
216 -}  
217 -  
218 -// show的状态发生变化  
219 -function showChange(newValue, oldValue, ownerInstance, instance) {  
220 - var state = instance.getState()  
221 - if (state.disabled) return  
222 - // 打开或关闭单元格  
223 - if (newValue) {  
224 - openSwipeAction(instance, ownerInstance)  
225 - } else {  
226 - closeSwipeAction(instance, ownerInstance)  
227 - }  
228 -}  
229 -  
230 -// 菜单尺寸发生变化  
231 -function sizeChange(newValue, oldValue, ownerInstance, instance) {  
232 - // wxs内的局部变量快照  
233 - var state = instance.getState()  
234 - state.disabled = newValue.disabled  
235 - state.duration = newValue.duration  
236 - state.show = newValue.show  
237 - state.threshold = newValue.threshold  
238 - state.buttons = newValue.buttons  
239 -  
240 - var len = state.buttons.length  
241 - if (len) {  
242 - var buttonsWidth = 0  
243 - var buttons = newValue.buttons  
244 - for (var i = 0; i < len; i++) {  
245 - buttonsWidth += buttons[i].width  
246 - }  
247 - }  
248 - state.buttonsWidth = buttonsWidth  
249 -}  
250 -  
251 -module.exports = {  
252 - touchstart: touchstart,  
253 - touchmove: touchmove,  
254 - touchend: touchend,  
255 - sizeChange: sizeChange  
256 -}  
1 -/**  
2 - * 此为wxs模块,只支持APP-VUE,微信和QQ小程序以及H5平台  
3 - * wxs内部不支持es6语法,变量只能使用var定义,无法使用解构,箭头函数等特性  
4 - */  
5 -  
6 -// 开始触摸  
7 -function touchstart(event, ownerInstance) {  
8 - // 触发事件的组件的ComponentDescriptor实例  
9 - var instance = event.instance  
10 - // wxs内的局部变量快照,此快照是属于整个组件的,在touchstart和touchmove事件中都能获取到相同的结果  
11 - var state = instance.getState()  
12 - if (state.disabled) return  
13 - var touches = event.touches  
14 - // 如果进行的是多指触控,不允许进行操作  
15 - if (touches && touches.length > 1) return  
16 - // 标识当前为滑动中状态  
17 - state.moving = true  
18 - // 记录触摸开始点的坐标值  
19 - state.startX = touches[0].pageX  
20 - state.startY = touches[0].pageY  
21 -  
22 - ownerInstance.callMethod('closeOther')  
23 -}  
24 -  
25 -// 触摸滑动  
26 -function touchmove(event, ownerInstance) {  
27 - // 触发事件的组件的ComponentDescriptor实例  
28 - var instance = event.instance  
29 - // wxs内的局部变量快照  
30 - var state = instance.getState()  
31 - if (state.disabled || !state.moving) return  
32 - var touches = event.touches  
33 - var pageX = touches[0].pageX  
34 - var pageY = touches[0].pageY  
35 - var moveX = pageX - state.startX  
36 - var moveY = pageY - state.startY  
37 - var buttonsWidth = state.buttonsWidth  
38 -  
39 - // 移动的X轴距离大于Y轴距离,也即终点与起点位置连线,与X轴夹角小于45度时,禁止页面滚动  
40 - if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > state.threshold) {  
41 - event.preventDefault && event.preventDefault()  
42 - event.stopPropagation && event.stopPropagation()  
43 - }  
44 - // 如果移动的X轴距离小于Y轴距离,也即终点位置与起点位置连线,与Y轴夹角小于45度时,认为是页面上下滑动,而不是左右滑动单元格  
45 - if (Math.abs(moveX) < Math.abs(moveY)) return  
46 -  
47 - // 限制右滑的距离,不允许内容部分往右偏移,右滑会导致X轴偏移值大于0,以此做判断  
48 - // 此处不能直接return,因为滑动过程中会缺失某些关键点坐标,会导致错乱,最好的办法就是  
49 - // 在超出后,设置为0  
50 - if (state.status === 'open') {  
51 - // 在开启状态下,向左滑动,需忽略  
52 - if (moveX < 0) moveX = 0  
53 - // 想要收起菜单,最大能移动的距离为按钮的总宽度  
54 - if (moveX > buttonsWidth) moveX = buttonsWidth  
55 - // 如果是已经打开了的状态,向左滑动时,移动收起菜单  
56 - moveSwipeAction(-buttonsWidth + moveX, instance, ownerInstance)  
57 - } else {  
58 - // 关闭状态下,右滑动需忽略  
59 - if (moveX > 0) moveX = 0  
60 - // 滑动的距离不允许超过所有按钮的总宽度,此时只能是左滑,最终设置按钮的总宽度,同时为负数  
61 - if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth  
62 - // 只要是在滑过程中,就不断移动单元格内容部分,从而使隐藏的菜单显示出来  
63 - moveSwipeAction(moveX, instance, ownerInstance)  
64 - }  
65 -}  
66 -  
67 -// 触摸结束  
68 -function touchend(event, ownerInstance) {  
69 - // 触发事件的组件的ComponentDescriptor实例  
70 - var instance = event.instance  
71 - // wxs内的局部变量快照  
72 - var state = instance.getState()  
73 - if (!state.moving || state.disabled) return  
74 - var touches = event.changedTouches ? event.changedTouches[0] : {}  
75 - var pageX = touches.pageX  
76 - var pageY = touches.pageY  
77 - var moveX = pageX - state.startX  
78 - if (state.status === 'open') {  
79 - // 在展开的状态下,继续左滑,无需操作  
80 - if (moveX < 0) return  
81 - // 在开启状态下,点击一下内容区域,moveX为0,也即没有进行移动,这时执行收起菜单逻辑  
82 - if (moveX === 0) {  
83 - return closeSwipeAction(instance, ownerInstance)  
84 - }  
85 - // 在开启状态下,滑动距离小于阈值,则默认为不关闭,同时恢复原来的打开状态  
86 - if (Math.abs(moveX) < state.threshold) {  
87 - openSwipeAction(instance, ownerInstance)  
88 - } else {  
89 - // 如果滑动距离大于阈值,则执行收起逻辑  
90 - closeSwipeAction(instance, ownerInstance)  
91 - }  
92 - } else {  
93 - // 在关闭的状态下,右滑,无需操作  
94 - if (moveX > 0) return  
95 - // 理由同上  
96 - if (Math.abs(moveX) < state.threshold) {  
97 - closeSwipeAction(instance, ownerInstance)  
98 - } else {  
99 - openSwipeAction(instance, ownerInstance)  
100 - }  
101 - }  
102 -}  
103 -  
104 -// 获取过渡时间  
105 -function getDuration(value) {  
106 - if (value.toString().indexOf('s') >= 0) return value  
107 - return value > 30 ? value + 'ms' : value + 's'  
108 -}  
109 -  
110 -// 滑动结束时判断滑动的方向  
111 -function getMoveDirection(instance, ownerInstance) {  
112 - var state = instance.getState()  
113 -}  
114 -  
115 -// 移动滑动选择器内容区域,同时显示出其隐藏的菜单  
116 -function moveSwipeAction(moveX, instance, ownerInstance) {  
117 - var state = instance.getState()  
118 - // 获取所有按钮的实例,需要通过它去设置按钮的位移  
119 - var buttons = ownerInstance.selectAllComponents('.u-swipe-action-item__right__button')  
120 -  
121 - // 设置菜单内容部分的偏移  
122 - instance.requestAnimationFrame(function() {  
123 - instance.setStyle({  
124 - // 设置translateX的值  
125 - 'transition': 'none',  
126 - transform: 'translateX(' + moveX + 'px)',  
127 - '-webkit-transform': 'translateX(' + moveX + 'px)'  
128 - })  
129 - })  
130 -}  
131 -  
132 -// 一次性展开滑动菜单  
133 -function openSwipeAction(instance, ownerInstance) {  
134 - var state = instance.getState()  
135 - // 获取所有按钮的实例,需要通过它去设置按钮的位移  
136 - var buttons = ownerInstance.selectAllComponents('.u-swipe-action-item__right__button')  
137 - // 处理duration单位问题  
138 - var duration = getDuration(state.duration)  
139 - // 展开过程中,是向左移动,所以X的偏移应该为负值  
140 - var buttonsWidth = -state.buttonsWidth  
141 - instance.requestAnimationFrame(function() {  
142 - // 设置菜单主体内容  
143 - instance.setStyle({  
144 - 'transition': 'transform ' + duration,  
145 - 'transform': 'translateX(' + buttonsWidth + 'px)',  
146 - '-webkit-transform': 'translateX(' + buttonsWidth + 'px)',  
147 - })  
148 - })  
149 - setStatus('open', instance, ownerInstance)  
150 -}  
151 -  
152 -// 标记菜单的当前状态,open-已经打开,close-已经关闭  
153 -function setStatus(status, instance, ownerInstance) {  
154 - var state = instance.getState()  
155 - state.status = status  
156 - ownerInstance.callMethod('setState', status)  
157 -}  
158 -  
159 -// 一次性收起滑动菜单  
160 -function closeSwipeAction(instance, ownerInstance) {  
161 - var state = instance.getState()  
162 - // 获取所有按钮的实例,需要通过它去设置按钮的位移  
163 - var buttons = ownerInstance.selectAllComponents('.u-swipe-action-item__right__button')  
164 - var len = buttons.length  
165 - // 处理duration单位问题  
166 - var duration = getDuration(state.duration)  
167 - instance.requestAnimationFrame(function() {  
168 - // 设置菜单主体内容  
169 - instance.setStyle({  
170 - 'transition': 'transform ' + duration,  
171 - 'transform': 'translateX(0px)',  
172 - '-webkit-transform': 'translateX(0px)'  
173 - })  
174 - // 设置各个隐藏的按钮为收起的状态  
175 - for (var i = len - 1; i >= 0; i--) {  
176 - buttons[i].setStyle({  
177 - 'transition': 'transform ' + duration,  
178 - 'transform': 'translateX(0px)',  
179 - '-webkit-transform': 'translateX(0px)'  
180 - })  
181 - }  
182 - })  
183 - setStatus('close', instance, ownerInstance)  
184 -}  
185 -  
186 -// status的状态发生变化  
187 -function statusChange(newValue, oldValue, ownerInstance, instance) {  
188 - var state = instance.getState()  
189 - if (state.disabled) return  
190 - // 打开或关闭单元格  
191 - if (newValue === 'close' && state.status === 'open') {  
192 - closeSwipeAction(instance, ownerInstance)  
193 - } else if(newValue === 'open' && state.status === 'close') {  
194 - openSwipeAction(instance, ownerInstance)  
195 - }  
196 -}  
197 -  
198 -// 菜单尺寸发生变化  
199 -function sizeChange(newValue, oldValue, ownerInstance, instance) {  
200 - // wxs内的局部变量快照  
201 - var state = instance.getState()  
202 - state.disabled = newValue.disabled  
203 - state.duration = newValue.duration  
204 - state.show = newValue.show  
205 - state.threshold = newValue.threshold  
206 - state.buttons = newValue.buttons  
207 -  
208 - if (state.buttons) {  
209 - var len = state.buttons.length  
210 - var buttonsWidth = 0  
211 - var buttons = newValue.buttons  
212 - for (var i = 0; i < len; i++) {  
213 - buttonsWidth += buttons[i].width  
214 - }  
215 - }  
216 - state.buttonsWidth = buttonsWidth  
217 -}  
218 -  
219 -module.exports = {  
220 - touchstart: touchstart,  
221 - touchmove: touchmove,  
222 - touchend: touchend,  
223 - sizeChange: sizeChange,  
224 - statusChange: statusChange  
225 -}  
1 -// nvue操作dom的库,用于获取dom的尺寸信息  
2 -const dom = uni.requireNativePlugin('dom')  
3 -// nvue中用于操作元素动画的库,类似于uni.animation,只不过uni.animation不能用于nvue  
4 -const animation = uni.requireNativePlugin('animation')  
5 -  
6 -export default {  
7 - data() {  
8 - return {  
9 - // 是否滑动中  
10 - moving: false,  
11 - // 状态,open-打开状态,close-关闭状态  
12 - status: 'close',  
13 - // 开始触摸点的X和Y轴坐标  
14 - startX: 0,  
15 - startY: 0,  
16 - // 所有隐藏按钮的尺寸信息数组  
17 - buttons: [],  
18 - // 所有按钮的总宽度  
19 - buttonsWidth: 0,  
20 - // 记录上一次移动的位置值  
21 - moveX: 0,  
22 - // 记录上一次滑动的位置,用于前后两次做对比,如果移动的距离小于某一阈值,则认为前后之间没有移动,为了解决可能存在的通信阻塞问题  
23 - lastX: 0  
24 - }  
25 - },  
26 - computed: {  
27 - // 获取过渡时间  
28 - getDuratin() {  
29 - let duration = String(this.duration)  
30 - // 如果ms为单位,返回ms的数值部分  
31 - if (duration.indexOf('ms') >= 0) return parseInt(duration)  
32 - // 如果s为单位,为了得到ms的数值,需要乘以1000  
33 - if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000  
34 - // 如果值传了数值,且小于30,认为是s单位  
35 - duration = Number(duration)  
36 - return duration < 30 ? duration * 1000 : duration  
37 - }  
38 - },  
39 - watch: {  
40 - show: {  
41 - immediate: true,  
42 - handler(n) {  
43 - // if(n === true) {  
44 - // uni.$u.sleep(50).then(() => {  
45 - // this.openSwipeAction()  
46 - // })  
47 - // } else {  
48 - // this.closeSwipeAction()  
49 - // }  
50 - }  
51 - }  
52 - },  
53 - mounted() {  
54 - uni.$u.sleep(20).then(() => {  
55 - this.queryRect()  
56 - })  
57 - },  
58 - methods: {  
59 - close() {  
60 - this.closeSwipeAction()  
61 - },  
62 - // 触摸单元格  
63 - touchstart(event) {  
64 - if (this.disabled) return  
65 - this.closeOther()  
66 - const { touches } = event  
67 - // 记录触摸开始点的坐标值  
68 - this.startX = touches[0].pageX  
69 - this.startY = touches[0].pageY  
70 - },  
71 - // // 触摸滑动  
72 - touchmove(event) {  
73 - if (this.disabled) return  
74 - const { touches } = event  
75 - const { pageX } = touches[0]  
76 - const { pageY } = touches[0]  
77 - let moveX = pageX - this.startX  
78 - const moveY = pageY - this.startY  
79 - const { buttonsWidth } = this  
80 - const len = this.buttons.length  
81 -  
82 - // 判断前后两次的移动距离,如果小于一定值,则不进行移动处理  
83 - if (Math.abs(pageX - this.lastX) < 0.3) return  
84 - this.lastX = pageX  
85 -  
86 - // 移动的X轴距离大于Y轴距离,也即终点与起点位置连线,与X轴夹角小于45度时,禁止页面滚动  
87 - if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > this.threshold) {  
88 - event.stopPropagation()  
89 - }  
90 - // 如果移动的X轴距离小于Y轴距离,也即终点位置与起点位置连线,与Y轴夹角小于45度时,认为是页面上下滑动,而不是左右滑动单元格  
91 - if (Math.abs(moveX) < Math.abs(moveY)) return  
92 -  
93 - // 限制右滑的距离,不允许内容部分往右偏移,右滑会导致X轴偏移值大于0,以此做判断  
94 - // 此处不能直接return,因为滑动过程中会缺失某些关键点坐标,会导致错乱,最好的办法就是  
95 - // 在超出后,设置为0  
96 - if (this.status === 'open') {  
97 - // 在开启状态下,向左滑动,需忽略  
98 - if (moveX < 0) moveX = 0  
99 - // 想要收起菜单,最大能移动的距离为按钮的总宽度  
100 - if (moveX > buttonsWidth) moveX = buttonsWidth  
101 - // 如果是已经打开了的状态,向左滑动时,移动收起菜单  
102 - this.moveSwipeAction(-buttonsWidth + moveX)  
103 - } else {  
104 - // 关闭状态下,右滑动需忽略  
105 - if (moveX > 0) moveX = 0  
106 - // 滑动的距离不允许超过所有按钮的总宽度,此时只能是左滑,最终设置按钮的总宽度,同时为负数  
107 - if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth  
108 - // 只要是在滑过程中,就不断移动菜单的内容部分,从而使隐藏的菜单显示出来  
109 - this.moveSwipeAction(moveX)  
110 - }  
111 - },  
112 - // 单元格结束触摸  
113 - touchend(event) {  
114 - if (this.disabled) return  
115 - const touches = event.changedTouches ? event.changedTouches[0] : {}  
116 - const { pageX } = touches  
117 - const { pageY } = touches  
118 - const { buttonsWidth } = this  
119 - this.moveX = pageX - this.startX  
120 - if (this.status === 'open') {  
121 - // 在展开的状态下,继续左滑,无需操作  
122 - if (this.moveX < 0) this.moveX = 0  
123 - if (this.moveX > buttonsWidth) this.moveX = buttonsWidth  
124 - // 在开启状态下,点击一下内容区域,moveX为0,也即没有进行移动,这时执行收起菜单逻辑  
125 - if (this.moveX === 0) {  
126 - return this.closeSwipeAction()  
127 - }  
128 - // 在开启状态下,滑动距离小于阈值,则默认为不关闭,同时恢复原来的打开状态  
129 - if (Math.abs(this.moveX) < this.threshold) {  
130 - this.openSwipeAction()  
131 - } else {  
132 - // 如果滑动距离大于阈值,则执行收起逻辑  
133 - this.closeSwipeAction()  
134 - }  
135 - } else {  
136 - // 在关闭的状态下,右滑,无需操作  
137 - if (this.moveX >= 0) this.moveX = 0  
138 - if (this.moveX <= -buttonsWidth) this.moveX = -buttonsWidth  
139 - // 理由同上  
140 - if (Math.abs(this.moveX) < this.threshold) {  
141 - this.closeSwipeAction()  
142 - } else {  
143 - this.openSwipeAction()  
144 - }  
145 - }  
146 - },  
147 - // 移动滑动选择器内容区域,同时显示出其隐藏的菜单  
148 - moveSwipeAction(moveX) {  
149 - if (this.moving) return  
150 - this.moving = true  
151 -  
152 - let previewButtonsMoveX = 0  
153 - const len = this.buttons.length  
154 - animation.transition(this.$refs['u-swipe-action-item__content'].ref, {  
155 - styles: {  
156 - transform: `translateX(${moveX}px)`  
157 - },  
158 - timingFunction: 'linear'  
159 - }, () => {  
160 - this.moving = false  
161 - })  
162 - // 按钮的组的长度  
163 - for (let i = len - 1; i >= 0; i--) {  
164 - const buttonRef = this.$refs[`u-swipe-action-item__right__button-${i}`][0].ref  
165 - // 通过比例,得出元素自身该移动的距离  
166 - const translateX = this.buttons[i].width / this.buttonsWidth * moveX  
167 - // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和  
168 - const realTranslateX = translateX + previewButtonsMoveX  
169 - animation.transition(buttonRef, {  
170 - styles: {  
171 - transform: `translateX(${realTranslateX}px)`  
172 - },  
173 - duration: 0,  
174 - delay: 0,  
175 - timingFunction: 'linear'  
176 - }, () => {})  
177 - // 记录本按钮之前的所有按钮的移动距离之和  
178 - previewButtonsMoveX += translateX  
179 - }  
180 - },  
181 - // 关闭菜单  
182 - closeSwipeAction() {  
183 - if (this.status === 'close') return  
184 - this.moving = true  
185 - const { buttonsWidth } = this  
186 - animation.transition(this.$refs['u-swipe-action-item__content'].ref, {  
187 - styles: {  
188 - transform: 'translateX(0px)'  
189 - },  
190 - duration: this.getDuratin,  
191 - timingFunction: 'ease-in-out'  
192 - }, () => {  
193 - this.status = 'close'  
194 - this.moving = false  
195 - this.closeHandler()  
196 - })  
197 - // 按钮的组的长度  
198 - const len = this.buttons.length  
199 - for (let i = len - 1; i >= 0; i--) {  
200 - const buttonRef = this.$refs[`u-swipe-action-item__right__button-${i}`][0].ref  
201 - // 如果不满足边界条件,返回  
202 - if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return  
203 -  
204 - animation.transition(buttonRef, {  
205 - styles: {  
206 - transform: 'translateX(0px)'  
207 - },  
208 - duration: this.getDuratin,  
209 - timingFunction: 'ease-in-out'  
210 - }, () => {})  
211 - }  
212 - },  
213 - // 打开菜单  
214 - openSwipeAction() {  
215 - if (this.status === 'open') return  
216 - this.moving = true  
217 - const buttonsWidth = -this.buttonsWidth  
218 - let previewButtonsMoveX = 0  
219 - animation.transition(this.$refs['u-swipe-action-item__content'].ref, {  
220 - styles: {  
221 - transform: `translateX(${buttonsWidth}px)`  
222 - },  
223 - duration: this.getDuratin,  
224 - timingFunction: 'ease-in-out'  
225 - }, () => {  
226 - this.status = 'open'  
227 - this.moving = false  
228 - this.openHandler()  
229 - })  
230 - // 按钮的组的长度  
231 - const len = this.buttons.length  
232 - for (let i = len - 1; i >= 0; i--) {  
233 - const buttonRef = this.$refs[`u-swipe-action-item__right__button-${i}`][0].ref  
234 - // 如果不满足边界条件,返回  
235 - if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return  
236 - // 通过比例,得出元素自身该移动的距离  
237 - const translateX = this.buttons[i].width / this.buttonsWidth * buttonsWidth  
238 - // 最终移动的距离,是通过自身比例算出的距离,再加上在它之前所有按钮移动的距离之和  
239 - const realTranslateX = translateX + previewButtonsMoveX  
240 - animation.transition(buttonRef, {  
241 - styles: {  
242 - transform: `translateX(${realTranslateX}px)`  
243 - },  
244 - duration: this.getDuratin,  
245 - timingFunction: 'ease-in-out'  
246 - }, () => {})  
247 - previewButtonsMoveX += translateX  
248 - }  
249 - },  
250 - // 查询按钮节点信息  
251 - queryRect() {  
252 - // 历遍所有按钮数组,通过getRectByDom返回一个promise  
253 - const promiseAll = this.rightOptions.map((item, index) => this.getRectByDom(this.$refs[`u-swipe-action-item__right__button-${index}`][0]))  
254 - // 通过promise.all方法,让所有按钮的查询结果返回一个数组的形式  
255 - Promise.all(promiseAll).then((sizes) => {  
256 - this.buttons = sizes  
257 - // 计算所有按钮总宽度  
258 - this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0)  
259 - })  
260 - },  
261 - // 通过nvue的dom模块,查询节点信息  
262 - getRectByDom(ref) {  
263 - return new Promise((resolve) => {  
264 - dom.getComponentRect(ref, (res) => {  
265 - resolve(res.size)  
266 - })  
267 - })  
268 - }  
269 - }  
270 -}  
1 -// nvue操作dom的库,用于获取dom的尺寸信息  
2 -const dom = uni.requireNativePlugin('dom');  
3 -const bindingX = uni.requireNativePlugin('bindingx');  
4 -const animation = uni.requireNativePlugin('animation');  
5 -  
6 -export default {  
7 - data() {  
8 - return {  
9 - // 所有按钮的总宽度  
10 - buttonsWidth: 0,  
11 - // 是否正在移动中  
12 - moving: false  
13 - }  
14 - },  
15 - computed: {  
16 - // 获取过渡时间  
17 - getDuratin() {  
18 - let duration = String(this.duration)  
19 - // 如果ms为单位,返回ms的数值部分  
20 - if (duration.indexOf('ms') >= 0) return parseInt(duration)  
21 - // 如果s为单位,为了得到ms的数值,需要乘以1000  
22 - if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000  
23 - // 如果值传了数值,且小于30,认为是s单位  
24 - duration = Number(duration)  
25 - return duration < 30 ? duration * 1000 : duration  
26 - }  
27 - },  
28 - watch: {  
29 - show(n) {  
30 - if(n) {  
31 - this.moveCellByAnimation('open')  
32 - } else {  
33 - this.moveCellByAnimation('close')  
34 - }  
35 - }  
36 - },  
37 - mounted() {  
38 - this.initialize()  
39 - },  
40 - methods: {  
41 - initialize() {  
42 - this.queryRect()  
43 - },  
44 - // 关闭单元格,用于打开一个,自动关闭其他单元格的场景  
45 - closeHandler() {  
46 - if(this.status === 'open') {  
47 - // 如果在打开状态下,进行点击的话,直接关闭单元格  
48 - return this.moveCellByAnimation('close') && this.unbindBindingX()  
49 - }  
50 - },  
51 - // 点击单元格  
52 - clickHandler() {  
53 - // 如果在移动中被点击,进行忽略  
54 - if(this.moving) return  
55 - // 尝试关闭其他打开的单元格  
56 - this.parent && this.parent.closeOther(this)  
57 - if(this.status === 'open') {  
58 - // 如果在打开状态下,进行点击的话,直接关闭单元格  
59 - return this.moveCellByAnimation('close') && this.unbindBindingX()  
60 - }  
61 - },  
62 - // 滑动单元格  
63 - onTouchstart(e) {  
64 - // 如果当前正在移动中,或者disabled状态,则返回  
65 - if(this.moving || this.disabled) {  
66 - return this.unbindBindingX()  
67 - }  
68 - if(this.status === 'open') {  
69 - // 如果在打开状态下,进行点击的话,直接关闭单元格  
70 - return this.moveCellByAnimation('close') && this.unbindBindingX()  
71 - }  
72 - // 特殊情况下,e可能不为一个对象  
73 - e?.stopPropagation && e.stopPropagation()  
74 - e?.preventDefault && e.preventDefault()  
75 - this.moving = true  
76 - // 获取元素ref  
77 - const content = this.getContentRef()  
78 - let expression = `min(max(${-this.buttonsWidth}, x), 0)`  
79 - // 尝试关闭其他打开的单元格  
80 - this.parent && this.parent.closeOther(this)  
81 -  
82 - // 阿里为了KPI而开源的BindingX  
83 - this.panEvent = bindingX.bind({  
84 - anchor: content,  
85 - eventType: 'pan',  
86 - props: [{  
87 - element: content,  
88 - // 绑定width属性,设置其宽度值  
89 - property: 'transform.translateX',  
90 - expression  
91 - }]  
92 - }, (res) => {  
93 - this.moving = false  
94 - if (res.state === 'end' || res.state === 'exit') {  
95 - const deltaX = res.deltaX  
96 - if(deltaX <= -this.buttonsWidth || deltaX >= 0) {  
97 - // 如果触摸滑动的过程中,大于单元格的总宽度,或者大于0,意味着已经动过滑动达到了打开或者关闭的状态  
98 - // 这里直接进行状态的标记  
99 - this.$nextTick(() => {  
100 - this.status = deltaX <= -this.buttonsWidth ? 'open' : 'close'  
101 - })  
102 - } else if(Math.abs(deltaX) > uni.$u.getPx(this.threshold)) {  
103 - // 在移动大于阈值、并且小于总按钮宽度时,进行自动打开或者关闭  
104 - // 移动距离大于0时,意味着需要关闭状态  
105 - if(Math.abs(deltaX) < this.buttonsWidth) {  
106 - this.moveCellByAnimation(deltaX > 0 ? 'close' : 'open')  
107 - }  
108 - } else {  
109 - // 在小于阈值时,进行关闭操作(如果在打开状态下,将不会执行bindingX)  
110 - this.moveCellByAnimation('close')  
111 - }  
112 - }  
113 - })  
114 - },  
115 - // 释放bindingX  
116 - unbindBindingX() {  
117 - // 释放上一次的资源  
118 - if (this?.panEvent?.token != 0) {  
119 - bindingX.unbind({  
120 - token: this.panEvent?.token,  
121 - // pan为手势事件  
122 - eventType: 'pan'  
123 - })  
124 - }  
125 - },  
126 - // 查询按钮节点信息  
127 - queryRect() {  
128 - // 历遍所有按钮数组,通过getRectByDom返回一个promise  
129 - const promiseAll = this.options.map((item, index) => {  
130 - return this.getRectByDom(this.$refs[`u-swipe-action-item__right__button-${index}`][0])  
131 - })  
132 - // 通过promise.all方法,让所有按钮的查询结果返回一个数组的形式  
133 - Promise.all(promiseAll).then(sizes => {  
134 - this.buttons = sizes  
135 - // 计算所有按钮总宽度  
136 - this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0)  
137 - })  
138 - },  
139 - // 通过nvue的dom模块,查询节点信息  
140 - getRectByDom(ref) {  
141 - return new Promise(resolve => {  
142 - dom.getComponentRect(ref, res => {  
143 - resolve(res.size)  
144 - })  
145 - })  
146 - },  
147 - // 移动单元格到左边或者右边尽头  
148 - moveCellByAnimation(status = 'open') {  
149 - if(this.moving) return  
150 - // 标识当前状态  
151 - this.moveing = true  
152 - const content = this.getContentRef()  
153 - const x = status === 'open' ? -this.buttonsWidth : 0  
154 - animation.transition(content, {  
155 - styles: {  
156 - transform: `translateX(${x}px)`,  
157 - },  
158 - duration: uni.$u.getDuration(this.duration, false),  
159 - timingFunction: 'ease-in-out'  
160 - }, () => {  
161 - this.moving = false  
162 - this.status = status  
163 - this.unbindBindingX()  
164 - })  
165 - },  
166 - // 获取元素ref  
167 - getContentRef() {  
168 - return this.$refs['u-swipe-action-item__content'].ref  
169 - },  
170 - beforeDestroy() {  
171 - this.unbindBindingX()  
172 - }  
173 - }  
174 -}  
1 -export default {  
2 - props: {  
3 - // 控制打开或者关闭  
4 - show: {  
5 - type: Boolean,  
6 - default: uni.$u.props.swipeActionItem.show  
7 - },  
8 - // 标识符,如果是v-for,可用index索引值  
9 - name: {  
10 - type: [String, Number],  
11 - default: uni.$u.props.swipeActionItem.name  
12 - },  
13 - // 是否禁用  
14 - disabled: {  
15 - type: Boolean,  
16 - default: uni.$u.props.swipeActionItem.disabled  
17 - },  
18 - // 是否自动关闭其他swipe按钮组  
19 - autoClose: {  
20 - type: Boolean,  
21 - default: uni.$u.props.swipeActionItem.autoClose  
22 - },  
23 - // 滑动距离阈值,只有大于此值,才被认为是要打开菜单  
24 - threshold: {  
25 - type: Number,  
26 - default: uni.$u.props.swipeActionItem.threshold  
27 - },  
28 - // 右侧按钮内容  
29 - options: {  
30 - type: Array,  
31 - default() {  
32 - return uni.$u.props.swipeActionItem.rightOptions  
33 - }  
34 - },  
35 - // 动画过渡时间,单位ms  
36 - duration: {  
37 - type: [String, Number],  
38 - default: uni.$u.props.swipeActionItem.duration  
39 - }  
40 - }  
41 -}  
1 -<template>  
2 - <view class="u-swipe-action-item" ref="u-swipe-action-item">  
3 - <view class="u-swipe-action-item__right">  
4 - <slot name="button">  
5 - <view v-for="(item,index) in options" :key="index" class="u-swipe-action-item__right__button"  
6 - :ref="`u-swipe-action-item__right__button-${index}`" :style="[{  
7 - alignItems: item.style && item.style.borderRadius ? 'center' : 'stretch'  
8 - }]" @tap="buttonClickHandler(item, index)">  
9 - <view class="u-swipe-action-item__right__button__wrapper" :style="[{  
10 - backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',  
11 - borderRadius: item.style && item.style.borderRadius ? item.style.borderRadius : '0',  
12 - padding: item.style && item.style.borderRadius ? '0' : '0 15px',  
13 - }, item.style]">  
14 - <u-icon v-if="item.icon" :name="item.icon"  
15 - :color="item.style && item.style.color ? item.style.color : '#ffffff'"  
16 - :size="item.iconSize ? $u.addUnit(item.iconSize) : item.style && item.style.fontSize ? $u.getPx(item.style.fontSize) * 1.2 : 17"  
17 - :customStyle="{  
18 - marginRight: item.text ? '2px' : 0  
19 - }"></u-icon>  
20 - <text v-if="item.text" class="u-swipe-action-item__right__button__wrapper__text u-line-1"  
21 - :style="[{  
22 - color: item.style && item.style.color ? item.style.color : '#ffffff',  
23 - fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px',  
24 - lineHeight: item.style && item.style.fontSize ? item.style.fontSize : '16px',  
25 - }]">{{ item.text }}</text>  
26 - </view>  
27 - </view>  
28 - </slot>  
29 - </view>  
30 - <!-- #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ -->  
31 - <view class="u-swipe-action-item__content" @touchstart="wxs.touchstart" @touchmove="wxs.touchmove"  
32 - @touchend="wxs.touchend" :status="status" :change:status="wxs.statusChange" :size="size"  
33 - :change:size="wxs.sizeChange">  
34 - <!-- #endif -->  
35 - <!-- #ifdef APP-NVUE -->  
36 - <view class="u-swipe-action-item__content" ref="u-swipe-action-item__content" @panstart="onTouchstart"  
37 - @tap="clickHandler">  
38 - <!-- #endif -->  
39 - <slot />  
40 - </view>  
41 - </view>  
42 -</template>  
43 -<!-- #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ -->  
44 -<script src="./index.wxs" module="wxs" lang="wxs"></script>  
45 -<!-- #endif -->  
46 -<script>  
47 - import touch from '../../libs/mixin/touch.js'  
48 - import props from './props.js';  
49 - // #ifdef APP-NVUE  
50 - import nvue from './nvue.js';  
51 - // #endif  
52 - // #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ  
53 - import wxs from './wxs.js';  
54 - // #endif  
55 - /**  
56 - * SwipeActionItem 滑动单元格子组件  
57 - * @description 该组件一般用于左滑唤出操作菜单的场景,用的最多的是左滑删除操作  
58 - * @tutorial https://www.uviewui.com/components/swipeAction.html  
59 - * @property {Boolean} show 控制打开或者关闭(默认 false )  
60 - * @property {String | Number} index 标识符,如果是v-for,可用index索引  
61 - * @property {Boolean} disabled 是否禁用(默认 false )  
62 - * @property {Boolean} autoClose 是否自动关闭其他swipe按钮组(默认 true )  
63 - * @property {Number} threshold 滑动距离阈值,只有大于此值,才被认为是要打开菜单(默认 30 )  
64 - * @property {Array} options 右侧按钮内容  
65 - * @property {String | Number} duration 动画过渡时间,单位ms(默认 350 )  
66 - * @event {Function(index)} open 组件打开时触发  
67 - * @event {Function(index)} close 组件关闭时触发  
68 - * @example <u-swipe-action><u-swipe-action-item :options="options1" ></u-swipe-action-item></u-swipe-action>  
69 - */  
70 - export default {  
71 - name: 'u-swipe-action-item',  
72 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props, touch],  
73 - // #ifdef APP-NVUE  
74 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props, nvue, touch],  
75 - // #endif  
76 - // #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ  
77 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props, touch, wxs],  
78 - // #endif  
79 - data() {  
80 - return {  
81 - // 按钮的尺寸信息  
82 - size: {},  
83 - // 父组件u-swipe-action的参数  
84 - parentData: {  
85 - autoClose: true,  
86 - },  
87 - // 当前状态,open-打开,close-关闭  
88 - status: 'close',  
89 - }  
90 - },  
91 - watch: {  
92 - // 由于wxs无法直接读取外部的值,需要在外部值变化时,重新执行赋值逻辑  
93 - wxsInit(newValue, oldValue) {  
94 - this.queryRect()  
95 - }  
96 - },  
97 - computed: {  
98 - wxsInit() {  
99 - return [this.disabled, this.autoClose, this.threshold, this.options, this.duration]  
100 - }  
101 - },  
102 - mounted() {  
103 - this.init()  
104 - },  
105 - methods: {  
106 - init() {  
107 - // 初始化父组件数据  
108 - this.updateParentData()  
109 - // #ifndef APP-NVUE  
110 - uni.$u.sleep().then(() => {  
111 - this.queryRect()  
112 - })  
113 - // #endif  
114 - },  
115 - updateParentData() {  
116 - // 此方法在mixin中  
117 - this.getParentData('u-swipe-action')  
118 - },  
119 - // #ifndef APP-NVUE  
120 - // 查询节点  
121 - queryRect() {  
122 - this.$uGetRect('.u-swipe-action-item__right__button', true).then(buttons => {  
123 - this.size = {  
124 - buttons,  
125 - show: this.show,  
126 - disabled: this.disabled,  
127 - threshold: this.threshold,  
128 - duration: this.duration  
129 - }  
130 - })  
131 - },  
132 - // #endif  
133 - // 按钮被点击  
134 - buttonClickHandler(item, index) {  
135 - this.$emit('click', {  
136 - index,  
137 - name: this.name  
138 - })  
139 - }  
140 - },  
141 - }  
142 -</script>  
143 -  
144 -<style lang="scss" scoped>  
145 - @import "../../libs/css/components.scss";  
146 -  
147 - .u-swipe-action-item {  
148 - position: relative;  
149 - overflow: hidden;  
150 - /* #ifndef APP-NVUE || MP-WEIXIN */  
151 - touch-action: none;  
152 - /* #endif */  
153 -  
154 - &__content {  
155 - background-color: #FFFFFF;  
156 - z-index: 10;  
157 - }  
158 -  
159 - &__right {  
160 - position: absolute;  
161 - top: 0;  
162 - bottom: 0;  
163 - right: 0;  
164 - @include flex;  
165 -  
166 - &__button {  
167 - @include flex;  
168 - justify-content: center;  
169 - overflow: hidden;  
170 - align-items: center;  
171 -  
172 - &__wrapper {  
173 - @include flex;  
174 - align-items: center;  
175 - justify-content: center;  
176 - padding: 0 15px;  
177 -  
178 - &__text {  
179 - @include flex;  
180 - align-items: center;  
181 - color: #FFFFFF;  
182 - font-size: 15px;  
183 - text-align: center;  
184 - justify-content: center;  
185 - }  
186 - }  
187 - }  
188 - }  
189 - }  
190 -</style>  
1 -export default {  
2 - methods: {  
3 - // 关闭时执行  
4 - closeHandler() {  
5 - this.status = 'close'  
6 - },  
7 - setState(status) {  
8 - this.status = status  
9 - },  
10 - closeOther() {  
11 - // 尝试关闭其他打开的单元格  
12 - this.parent && this.parent.closeOther(this)  
13 - }  
14 - }  
15 -}  
1 -export default {  
2 - props: {  
3 - // 是否自动关闭其他swipe按钮组  
4 - autoClose: {  
5 - type: Boolean,  
6 - default: uni.$u.props.swipeAction.autoClose  
7 - }  
8 - }  
9 -}  
1 -<template>  
2 - <view class="u-swipe-action">  
3 - <slot></slot>  
4 - </view>  
5 -</template>  
6 -  
7 -<script>  
8 - import props from './props.js';  
9 - /**  
10 - * SwipeAction 滑动单元格  
11 - * @description 该组件一般用于左滑唤出操作菜单的场景,用的最多的是左滑删除操作  
12 - * @tutorial https://www.uviewui.com/components/swipeAction.html  
13 - * @property {Boolean} autoClose 是否自动关闭其他swipe按钮组  
14 - * @event {Function(index)} click 点击组件时触发  
15 - * @example <u-swipe-action><u-swipe-action-item :rightOptions="options1" ></u-swipe-action-item></u-swipe-action>  
16 - */  
17 - export default {  
18 - name: 'u-swipe-action',  
19 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
20 - data() {  
21 - return {}  
22 - },  
23 - provide() {  
24 - return {  
25 - swipeAction: this  
26 - }  
27 - },  
28 - computed: {  
29 - // 这里computed的变量,都是子组件u-swipe-action-item需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化  
30 - // 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-swipe-action-item)  
31 - // 拉取父组件新的变化后的参数  
32 - parentData() {  
33 - return [this.autoClose]  
34 - }  
35 - },  
36 - watch: {  
37 - // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件  
38 - parentData() {  
39 - if (this.children.length) {  
40 - this.children.map(child => {  
41 - // 判断子组件(u-swipe-action-item)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)  
42 - typeof(child.updateParentData) === 'function' && child.updateParentData()  
43 - })  
44 - }  
45 - },  
46 - },  
47 - created() {  
48 - this.children = []  
49 - },  
50 - methods: {  
51 - closeOther(child) {  
52 - if (this.autoClose) {  
53 - // 历遍所有的单元格,找出非当前操作中的单元格,进行关闭  
54 - this.children.map((item, index) => {  
55 - if (child !== item) {  
56 - item.closeHandler()  
57 - }  
58 - })  
59 - }  
60 - }  
61 - }  
62 - }  
63 -</script>  
64 -  
65 -<style lang="scss" scoped>  
66 -  
67 -</style>  
1 -export default {  
2 - props: {  
3 - // 轮播的长度  
4 - length: {  
5 - type: [String, Number],  
6 - default: uni.$u.props.swiperIndicator.length  
7 - },  
8 - // 当前处于活动状态的轮播的索引  
9 - current: {  
10 - type: [String, Number],  
11 - default: uni.$u.props.swiperIndicator.current  
12 - },  
13 - // 指示器非激活颜色  
14 - indicatorActiveColor: {  
15 - type: String,  
16 - default: uni.$u.props.swiperIndicator.indicatorActiveColor  
17 - },  
18 - // 指示器的激活颜色  
19 - indicatorInactiveColor: {  
20 - type: String,  
21 - default: uni.$u.props.swiperIndicator.indicatorInactiveColor  
22 - },  
23 - // 指示器模式,line-线型,dot-点型  
24 - indicatorMode: {  
25 - type: String,  
26 - default: uni.$u.props.swiperIndicator.indicatorMode  
27 - }  
28 - }  
29 -}  
1 -<template>  
2 - <view class="u-swiper-indicator">  
3 - <view  
4 - class="u-swiper-indicator__wrapper"  
5 - v-if="indicatorMode === 'line'"  
6 - :class="[`u-swiper-indicator__wrapper--${indicatorMode}`]"  
7 - :style="{  
8 - width: $u.addUnit(lineWidth * length),  
9 - backgroundColor: indicatorInactiveColor  
10 - }"  
11 - >  
12 - <view  
13 - class="u-swiper-indicator__wrapper--line__bar"  
14 - :style="[lineStyle]"  
15 - ></view>  
16 - </view>  
17 - <view  
18 - class="u-swiper-indicator__wrapper"  
19 - v-if="indicatorMode === 'dot'"  
20 - >  
21 - <view  
22 - class="u-swiper-indicator__wrapper__dot"  
23 - v-for="(item, index) in length"  
24 - :key="index"  
25 - :class="[index === current && 'u-swiper-indicator__wrapper__dot--active']"  
26 - :style="[dotStyle(index)]"  
27 - >  
28 -  
29 - </view>  
30 - </view>  
31 - </view>  
32 -</template>  
33 -  
34 -<script>  
35 - import props from './props.js';  
36 - /**  
37 - * SwiperIndicator 轮播图指示器  
38 - * @description 该组件一般用于导航轮播,广告展示等场景,可开箱即用,  
39 - * @tutorial https://www.uviewui.com/components/swiper.html  
40 - * @property {String | Number} length 轮播的长度(默认 0 )  
41 - * @property {String | Number} current 当前处于活动状态的轮播的索引(默认 0 )  
42 - * @property {String} indicatorActiveColor 指示器非激活颜色  
43 - * @property {String} indicatorInactiveColor 指示器的激活颜色  
44 - * @property {String} indicatorMode 指示器模式(默认 'line' )  
45 - * @example <u-swiper :list="list4" indicator keyName="url" :autoplay="false"></u-swiper>  
46 - */  
47 - export default {  
48 - name: 'u-swiper-indicator',  
49 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
50 - data() {  
51 - return {  
52 - lineWidth: 22  
53 - }  
54 - },  
55 - computed: {  
56 - // 指示器为线型的样式  
57 - lineStyle() {  
58 - let style = {}  
59 - style.width = uni.$u.addUnit(this.lineWidth)  
60 - style.transform = `translateX(${ uni.$u.addUnit(this.current * this.lineWidth) })`  
61 - style.backgroundColor = this.indicatorActiveColor  
62 - return style  
63 - },  
64 - // 指示器为点型的样式  
65 - dotStyle() {  
66 - return index => {  
67 - let style = {}  
68 - style.backgroundColor = index === this.current ? this.indicatorActiveColor : this.indicatorInactiveColor  
69 - return style  
70 - }  
71 - }  
72 - },  
73 - }  
74 -</script>  
75 -  
76 -<style lang="scss" scoped>  
77 - @import "../../libs/css/components.scss";  
78 -  
79 - .u-swiper-indicator {  
80 -  
81 - &__wrapper {  
82 - @include flex;  
83 -  
84 - &--line {  
85 - border-radius: 100px;  
86 - height: 4px;  
87 -  
88 - &__bar {  
89 - width: 22px;  
90 - height: 4px;  
91 - border-radius: 100px;  
92 - background-color: #FFFFFF;  
93 - transition: transform 0.3s;  
94 - }  
95 - }  
96 -  
97 - &__dot {  
98 - width: 5px;  
99 - height: 5px;  
100 - border-radius: 100px;  
101 - margin: 0 4px;  
102 -  
103 - &--active {  
104 - width: 12px;  
105 - }  
106 - }  
107 -  
108 - }  
109 - }  
110 -</style>  
1 -export default {  
2 - props: {  
3 - // 列表数组,元素可为字符串,如为对象可通过keyName指定目标属性名  
4 - list: {  
5 - type: Array,  
6 - default: uni.$u.props.swiper.list  
7 - },  
8 - // 是否显示面板指示器  
9 - indicator: {  
10 - type: Boolean,  
11 - default: uni.$u.props.swiper.indicator  
12 - },  
13 - // 指示器非激活颜色  
14 - indicatorActiveColor: {  
15 - type: String,  
16 - default: uni.$u.props.swiper.indicatorActiveColor  
17 - },  
18 - // 指示器的激活颜色  
19 - indicatorInactiveColor: {  
20 - type: String,  
21 - default: uni.$u.props.swiper.indicatorInactiveColor  
22 - },  
23 - // 指示器样式,可通过bottom,left,right进行定位  
24 - indicatorStyle: {  
25 - type: [String, Object],  
26 - default: uni.$u.props.swiper.indicatorStyle  
27 - },  
28 - // 指示器模式,line-线型,dot-点型  
29 - indicatorMode: {  
30 - type: String,  
31 - default: uni.$u.props.swiper.indicatorMode  
32 - },  
33 - // 是否自动切换  
34 - autoplay: {  
35 - type: Boolean,  
36 - default: uni.$u.props.swiper.autoplay  
37 - },  
38 - // 当前所在滑块的 index  
39 - current: {  
40 - type: [String, Number],  
41 - default: uni.$u.props.swiper.current  
42 - },  
43 - // 当前所在滑块的 item-id ,不能与 current 被同时指定  
44 - currentItemId: {  
45 - type: String,  
46 - default: uni.$u.props.swiper.currentItemId  
47 - },  
48 - // 滑块自动切换时间间隔  
49 - interval: {  
50 - type: [String, Number],  
51 - default: uni.$u.props.swiper.interval  
52 - },  
53 - // 滑块切换过程所需时间  
54 - duration: {  
55 - type: [String, Number],  
56 - default: uni.$u.props.swiper.duration  
57 - },  
58 - // 播放到末尾后是否重新回到开头  
59 - circular: {  
60 - type: Boolean,  
61 - default: uni.$u.props.swiper.circular  
62 - },  
63 - // 前边距,可用于露出前一项的一小部分,nvue和支付宝不支持  
64 - previousMargin: {  
65 - type: [String, Number],  
66 - default: uni.$u.props.swiper.previousMargin  
67 - },  
68 - // 后边距,可用于露出后一项的一小部分,nvue和支付宝不支持  
69 - nextMargin: {  
70 - type: [String, Number],  
71 - default: uni.$u.props.swiper.nextMargin  
72 - },  
73 - // 当开启时,会根据滑动速度,连续滑动多屏,支付宝不支持  
74 - acceleration: {  
75 - type: Boolean,  
76 - default: uni.$u.props.swiper.acceleration  
77 - },  
78 - // 同时显示的滑块数量,nvue、支付宝小程序不支持  
79 - displayMultipleItems: {  
80 - type: Number,  
81 - default: uni.$u.props.swiper.displayMultipleItems  
82 - },  
83 - // 指定swiper切换缓动动画类型,有效值:default、linear、easeInCubic、easeOutCubic、easeInOutCubic  
84 - // 只对微信小程序有效  
85 - easingFunction: {  
86 - type: String,  
87 - default: uni.$u.props.swiper.easingFunction  
88 - },  
89 - // list数组中指定对象的目标属性名  
90 - keyName: {  
91 - type: String,  
92 - default: uni.$u.props.swiper.keyName  
93 - },  
94 - // 图片的裁剪模式  
95 - imgMode: {  
96 - type: String,  
97 - default: uni.$u.props.swiper.imgMode  
98 - },  
99 - // 组件高度  
100 - height: {  
101 - type: [String, Number],  
102 - default: uni.$u.props.swiper.height  
103 - },  
104 - // 背景颜色  
105 - bgColor: {  
106 - type: String,  
107 - default: uni.$u.props.swiper.bgColor  
108 - },  
109 - // 组件圆角,数值或带单位的字符串  
110 - radius: {  
111 - type: [String, Number],  
112 - default: uni.$u.props.swiper.radius  
113 - },  
114 - // 是否加载中  
115 - loading: {  
116 - type: Boolean,  
117 - default: uni.$u.props.swiper.loading  
118 - },  
119 - // 是否显示标题,要求数组对象中有title属性  
120 - showTitle: {  
121 - type: Boolean,  
122 - default: uni.$u.props.swiper.showTitle  
123 - }  
124 - }  
125 -}  
1 -<template>  
2 - <view  
3 - class="u-swiper"  
4 - :style="{  
5 - backgroundColor: bgColor,  
6 - height: $u.addUnit(height),  
7 - borderRadius: $u.addUnit(radius)  
8 - }"  
9 - >  
10 - <view  
11 - class="u-swiper__loading"  
12 - v-if="loading"  
13 - >  
14 - <u-loading-icon mode="circle"></u-loading-icon>  
15 - </view>  
16 - <swiper  
17 - v-else  
18 - class="u-swiper__wrapper"  
19 - :style="{  
20 - height: $u.addUnit(height),  
21 - }"  
22 - @change="change"  
23 - :circular="circular"  
24 - :interval="interval"  
25 - :duration="duration"  
26 - :autoplay="autoplay"  
27 - :current="current"  
28 - :currentItemId="currentItemId"  
29 - :previousMargin="$u.addUnit(previousMargin)"  
30 - :nextMargin="$u.addUnit(nextMargin)"  
31 - :acceleration="acceleration"  
32 - :displayMultipleItems="displayMultipleItems"  
33 - :easingFunction="easingFunction"  
34 - >  
35 - <swiper-item  
36 - class="u-swiper__wrapper__item"  
37 - v-for="(item, index) in list"  
38 - :key="index"  
39 - >  
40 - <view  
41 - class="u-swiper__wrapper__item__wrapper"  
42 - :style="[itemStyle(index)]"  
43 - >  
44 - <!-- nvue中,image图片的宽度默认为屏幕宽度,需要通过flex:1撑开,另外必须设置高度才能显示图片 -->  
45 - <image  
46 - class="u-swiper__wrapper__item__wrapper__image"  
47 - v-if="$u.test.image(getSource(item))"  
48 - :src="getSource(item)"  
49 - :mode="imgMode"  
50 - @tap="clickHandler(index)"  
51 - :style="{  
52 - height: $u.addUnit(height),  
53 - borderRadius: $u.addUnit(radius)  
54 - }"  
55 - ></image>  
56 - <video  
57 - class="u-swiper__wrapper__item__wrapper__video"  
58 - v-if="$u.test.video(getSource(item))"  
59 - :id="`video-${index}`"  
60 - :enable-progress-gesture="false"  
61 - :src="getSource(item)"  
62 - :poster="getPoster(item)"  
63 - :title="showTitle && $u.test.object(item) && item.title ? item.title : ''"  
64 - :style="{  
65 - height: $u.addUnit(height)  
66 - }"  
67 - controls  
68 - @tap="clickHandler(index)"  
69 - ></video>  
70 - <text  
71 - v-if="showTitle && $u.test.object(item) && item.title && $u.test.image(getSource(item))"  
72 - class="u-swiper__wrapper__item__wrapper__title u-line-1"  
73 - >{{ item.title }}</text>  
74 - </view>  
75 - </swiper-item>  
76 - </swiper>  
77 - <view class="u-swiper__indicator" :style="[$u.addStyle(indicatorStyle)]">  
78 - <slot name="indicator">  
79 - <u-swiper-indicator  
80 - v-if="!loading && indicator && !showTitle"  
81 - :indicatorActiveColor="indicatorActiveColor"  
82 - :indicatorInactiveColor="indicatorInactiveColor"  
83 - :length="list.length"  
84 - :current="currentIndex"  
85 - :indicatorMode="indicatorMode"  
86 - ></u-swiper-indicator>  
87 - </slot>  
88 - </view>  
89 - </view>  
90 -</template>  
91 -  
92 -<script>  
93 - import props from './props.js';  
94 - /**  
95 - * Swiper 轮播图  
96 - * @description 该组件一般用于导航轮播,广告展示等场景,可开箱即用,  
97 - * @tutorial https://www.uviewui.com/components/swiper.html  
98 - * @property {Array} list 轮播图数据  
99 - * @property {Boolean} indicator 是否显示面板指示器(默认 false )  
100 - * @property {String} indicatorActiveColor 指示器非激活颜色(默认 '#FFFFFF' )  
101 - * @property {String} indicatorInactiveColor 指示器的激活颜色(默认 'rgba(255, 255, 255, 0.35)' )  
102 - * @property {String | Object} indicatorStyle 指示器样式,可通过bottom,left,right进行定位  
103 - * @property {String} indicatorMode 指示器模式(默认 'line' )  
104 - * @property {Boolean} autoplay 是否自动切换(默认 true )  
105 - * @property {String | Number} current 当前所在滑块的 index(默认 0 )  
106 - * @property {String} currentItemId 当前所在滑块的 item-id ,不能与 current 被同时指定  
107 - * @property {String | Number} interval 滑块自动切换时间间隔(ms)(默认 3000 )  
108 - * @property {String | Number} duration 滑块切换过程所需时间(ms)(默认 300 )  
109 - * @property {Boolean} circular 播放到末尾后是否重新回到开头(默认 false )  
110 - * @property {String | Number} previousMargin 前边距,可用于露出前一项的一小部分,nvue和支付宝不支持(默认 0 )  
111 - * @property {String | Number} nextMargin 后边距,可用于露出后一项的一小部分,nvue和支付宝不支持(默认 0 )  
112 - * @property {Boolean} acceleration 当开启时,会根据滑动速度,连续滑动多屏,支付宝不支持(默认 false )  
113 - * @property {Number} displayMultipleItems 同时显示的滑块数量,nvue、支付宝小程序不支持(默认 1 )  
114 - * @property {String} easingFunction 指定swiper切换缓动动画类型, 只对微信小程序有效(默认 'default' )  
115 - * @property {String} keyName list数组中指定对象的目标属性名(默认 'url' )  
116 - * @property {String} imgMode 图片的裁剪模式(默认 'aspectFill' )  
117 - * @property {String | Number} height 组件高度(默认 130 )  
118 - * @property {String} bgColor 背景颜色(默认 '#f3f4f6' )  
119 - * @property {String | Number} radius 组件圆角,数值或带单位的字符串(默认 4 )  
120 - * @property {Boolean} loading 是否加载中(默认 false )  
121 - * @property {Boolean} showTitle 是否显示标题,要求数组对象中有title属性(默认 false )  
122 - * @event {Function(index)} click 点击轮播图时触发 index:点击了第几张图片,从0开始  
123 - * @event {Function(index)} change 轮播图切换时触发(自动或者手动切换) index:切换到了第几张图片,从0开始  
124 - * @example <u-swiper :list="list4" keyName="url" :autoplay="false"></u-swiper>  
125 - */  
126 - export default {  
127 - name: 'u-swiper',  
128 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
129 - data() {  
130 - return {  
131 - currentIndex: 0  
132 - }  
133 - },  
134 - watch: {  
135 - current(val, preVal) {  
136 - if(val === preVal) return;  
137 - this.currentIndex = val; // 和上游数据关联上  
138 - }  
139 - },  
140 - computed: {  
141 - itemStyle() {  
142 - return index => {  
143 - const style = {}  
144 - // #ifndef APP-NVUE || MP-TOUTIAO  
145 - // 左右流出空间的写法不支持nvue和头条  
146 - // 只有配置了此二值,才加上对应的圆角,以及缩放  
147 - if (this.nextMargin && this.previousMargin) {  
148 - style.borderRadius = uni.$u.addUnit(this.radius)  
149 - if (index !== this.currentIndex) style.transform = 'scale(0.92)'  
150 - }  
151 - // #endif  
152 - return style  
153 - }  
154 - }  
155 - },  
156 - methods: {  
157 - // 获取目标路径,可能数组中为字符串,对象的形式,额外可指定对象的目标属性名keyName  
158 - getSource(item) {  
159 - if (typeof item === 'string') return item  
160 - if (typeof item === 'object' && this.keyName) return item[this.keyName]  
161 - else uni.$u.error('请按格式传递列表参数')  
162 - return ''  
163 - },  
164 - // 轮播切换事件  
165 - change(e) {  
166 - // 当前的激活索引  
167 - const {  
168 - current  
169 - } = e.detail  
170 - this.pauseVideo(this.currentIndex)  
171 - this.currentIndex = current  
172 - this.$emit('change', e.detail)  
173 - },  
174 - // 切换轮播时,暂停视频播放  
175 - pauseVideo(index) {  
176 - const lastItem = this.getSource(this.list[index])  
177 - if (uni.$u.test.video(lastItem)) {  
178 - // 当视频隐藏时,暂停播放  
179 - const video = uni.createVideoContext(`video-${index}`, this)  
180 - video.pause()  
181 - }  
182 - },  
183 - // 当一个轮播item为视频时,获取它的视频海报  
184 - getPoster(item) {  
185 - return typeof item === 'object' && item.poster ? item.poster : ''  
186 - },  
187 - // 点击某个item  
188 - clickHandler(index) {  
189 - this.$emit('click', index)  
190 - }  
191 - },  
192 - }  
193 -</script>  
194 -  
195 -<style lang="scss" scoped>  
196 - @import "../../libs/css/components.scss";  
197 -  
198 - .u-swiper {  
199 - @include flex;  
200 - justify-content: center;  
201 - align-items: center;  
202 - position: relative;  
203 - overflow: hidden;  
204 -  
205 - &__wrapper {  
206 - flex: 1;  
207 -  
208 - &__item {  
209 - flex: 1;  
210 -  
211 - &__wrapper {  
212 - @include flex;  
213 - position: relative;  
214 - overflow: hidden;  
215 - transition: transform 0.3s;  
216 - flex: 1;  
217 -  
218 - &__image {  
219 - flex: 1;  
220 - }  
221 -  
222 - &__video {  
223 - flex: 1;  
224 - }  
225 -  
226 - &__title {  
227 - position: absolute;  
228 - background-color: rgba(0, 0, 0, 0.3);  
229 - bottom: 0;  
230 - left: 0;  
231 - right: 0;  
232 - font-size: 28rpx;  
233 - padding: 12rpx 24rpx;  
234 - color: #FFFFFF;  
235 - flex: 1;  
236 - }  
237 - }  
238 - }  
239 - }  
240 -  
241 - &__indicator {  
242 - position: absolute;  
243 - bottom: 10px;  
244 - }  
245 - }  
246 -</style>  
1 -## 3.0.1(2021-05-13)  
2 -1. 跳转颜色和图标配置  
3 -2. 新增静默更新  
4 -## 3.0.0(2021-05-12)  
5 -1. 支持uni_modules  
1 -// #ifdef APP-PLUS  
2 -import componentConfig from "@/config/componentConfig"  
3 -const platform = uni.getSystemInfoSync().platform;  
4 -// 主颜色  
5 -const $mainColor = componentConfig.appUpdateColor ? componentConfig.appUpdateColor : "FF5B78";  
6 -// 弹窗图标url  
7 -const $iconUrl = componentConfig.appUpdateIcon ? componentConfig.appUpdateIcon : "/uni_modules/zhouWei-APPUpdate/static/ic_ar.png";  
8 -  
9 -// 获取当前应用的版本号  
10 -export const getCurrentNo = function(callback) {  
11 - // 获取本地应用资源版本号  
12 - plus.runtime.getProperty(plus.runtime.appid, function(inf) {  
13 - callback && callback({  
14 - versionCode: inf.versionCode,  
15 - versionName: inf.version  
16 - });  
17 - });  
18 -}  
19 -// 从服务器下载应用资源包(wgt文件)  
20 -const getDownload = function(data) {  
21 - let dtask;  
22 - if(data.updateType == 'forcibly' || data.updateType == 'solicit'){  
23 - let popupData = {  
24 - progress: true,  
25 - buttonNum: 2  
26 - };  
27 - if(data.updateType == 'forcibly'){  
28 - popupData.buttonNum = 0;  
29 - }  
30 - let lastProgressValue = 0;  
31 - let popupObj = downloadPopup(popupData);  
32 - dtask = plus.downloader.createDownload(data.downloadUrl, {  
33 - filename: "_doc/update/"  
34 - }, function(download, status) {  
35 - if (status == 200) {  
36 - popupObj.change({  
37 - progressValue: 100,  
38 - progressTip:"正在安装文件...",  
39 - progress: true,  
40 - buttonNum: 0  
41 - });  
42 - plus.runtime.install(download.filename, {}, function() {  
43 - popupObj.change({  
44 - contentText: "应用资源更新完成!",  
45 - buttonNum: 1,  
46 - progress: false  
47 - });  
48 - }, function(e) {  
49 - popupObj.cancel();  
50 - plus.nativeUI.alert("安装文件失败[" + e.code + "]:" + e.message);  
51 - });  
52 - } else {  
53 - popupObj.change({  
54 - contentText: "文件下载失败...",  
55 - buttonNum: 1,  
56 - progress: false  
57 - });  
58 - }  
59 - });  
60 - dtask.start();  
61 - dtask.addEventListener("statechanged", function(task, status) {  
62 - switch (task.state) {  
63 - case 1: // 开始  
64 - popupObj.change({  
65 - progressValue:0,  
66 - progressTip:"准备下载...",  
67 - progress: true  
68 - });  
69 - break;  
70 - case 2: // 已连接到服务器  
71 - popupObj.change({  
72 - progressValue:0,  
73 - progressTip:"开始下载...",  
74 - progress: true  
75 - });  
76 - break;  
77 - case 3:  
78 - const progress = parseInt(task.downloadedSize / task.totalSize * 100);  
79 - if(progress - lastProgressValue >= 2){  
80 - lastProgressValue = progress;  
81 - popupObj.change({  
82 - progressValue:progress,  
83 - progressTip: "已下载" + progress + "%",  
84 - progress: true  
85 - });  
86 - }  
87 - break;  
88 - }  
89 - });  
90 - // 取消下载  
91 - popupObj.cancelDownload = function(){  
92 - dtask && dtask.abort();  
93 - uni.showToast({  
94 - title: "已取消下载",  
95 - icon:"none"  
96 - });  
97 - }  
98 - // 重启APP  
99 - popupObj.reboot = function(){  
100 - plus.runtime.restart();  
101 - }  
102 - } else if(data.updateType == "silent"){  
103 - dtask = plus.downloader.createDownload(data.downloadUrl, {  
104 - filename: "_doc/update/"  
105 - }, function(download, status) {  
106 - if (status == 200) {  
107 - plus.runtime.install(download.filename, {}, function() {  
108 - console.log("应用资源更新完成");  
109 - }, function(e) {  
110 - plus.nativeUI.alert("安装文件失败[" + e.code + "]:" + e.message);  
111 - });  
112 - } else {  
113 - plus.nativeUI.alert("文件下载失败...");  
114 - }  
115 - });  
116 - dtask.start();  
117 - }  
118 -}  
119 -// 文字换行  
120 -function drawtext(text, maxWidth) {  
121 - let textArr = text.split("");  
122 - let len = textArr.length;  
123 - // 上个节点  
124 - let previousNode = 0;  
125 - // 记录节点宽度  
126 - let nodeWidth = 0;  
127 - // 文本换行数组  
128 - let rowText = [];  
129 - // 如果是字母,侧保存长度  
130 - let letterWidth = 0;  
131 - // 汉字宽度  
132 - let chineseWidth = 14;  
133 - // otherFont宽度  
134 - let otherWidth = 7;  
135 - for (let i = 0; i < len; i++) {  
136 - if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {  
137 - if(letterWidth > 0){  
138 - if(nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth){  
139 - rowText.push({  
140 - type: "text",  
141 - content: text.substring(previousNode, i)  
142 - });  
143 - previousNode = i;  
144 - nodeWidth = chineseWidth;  
145 - letterWidth = 0;  
146 - } else {  
147 - nodeWidth += chineseWidth + letterWidth * otherWidth;  
148 - letterWidth = 0;  
149 - }  
150 - } else {  
151 - if(nodeWidth + chineseWidth > maxWidth){  
152 - rowText.push({  
153 - type: "text",  
154 - content: text.substring(previousNode, i)  
155 - });  
156 - previousNode = i;  
157 - nodeWidth = chineseWidth;  
158 - }else{  
159 - nodeWidth += chineseWidth;  
160 - }  
161 - }  
162 - } else {  
163 - if(/\n/g.test(textArr[i])){  
164 - rowText.push({  
165 - type: "break",  
166 - content: text.substring(previousNode, i)  
167 - });  
168 - previousNode = i + 1;  
169 - nodeWidth = 0;  
170 - letterWidth = 0;  
171 - }else if(textArr[i] == "\\" && textArr[i + 1] == "n"){  
172 - rowText.push({  
173 - type: "break",  
174 - content: text.substring(previousNode, i)  
175 - });  
176 - previousNode = i + 2;  
177 - nodeWidth = 0;  
178 - letterWidth = 0;  
179 - }else if(/[a-zA-Z0-9]/g.test(textArr[i])){  
180 - letterWidth += 1;  
181 - if(nodeWidth + letterWidth * otherWidth > maxWidth){  
182 - rowText.push({  
183 - type: "text",  
184 - content: text.substring(previousNode, i + 1 - letterWidth)  
185 - });  
186 - previousNode = i + 1 - letterWidth;  
187 - nodeWidth = letterWidth * otherWidth;  
188 - letterWidth = 0;  
189 - }  
190 - } else{  
191 - if(nodeWidth + otherWidth > maxWidth){  
192 - rowText.push({  
193 - type: "text",  
194 - content: text.substring(previousNode, i)  
195 - });  
196 - previousNode = i;  
197 - nodeWidth = otherWidth;  
198 - }else{  
199 - nodeWidth += otherWidth;  
200 - }  
201 - }  
202 - }  
203 - }  
204 - if (previousNode < len) {  
205 - rowText.push({  
206 - type: "text",  
207 - content: text.substring(previousNode, len)  
208 - });  
209 - }  
210 - return rowText;  
211 -}  
212 -// 是否更新弹窗  
213 -function updatePopup(data, callback) {  
214 - // 弹窗遮罩层  
215 - let maskLayer = new plus.nativeObj.View("maskLayer", { //先创建遮罩层  
216 - top: '0px',  
217 - left: '0px',  
218 - height: '100%',  
219 - width: '100%',  
220 - backgroundColor: 'rgba(0,0,0,0.5)'  
221 - });  
222 -  
223 - // 以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心  
224 - const screenWidth = plus.screen.resolutionWidth;  
225 - const screenHeight = plus.screen.resolutionHeight;  
226 - //弹窗容器宽度  
227 - const popupViewWidth = screenWidth * 0.7;  
228 - // 弹窗容器的Padding  
229 - const viewContentPadding = 20;  
230 - // 弹窗容器的宽度  
231 - const viewContentWidth = parseInt(popupViewWidth - (viewContentPadding * 2));  
232 - // 描述的列表  
233 - const descriptionList = drawtext(data.versionInfo, viewContentWidth);  
234 - // 弹窗容器高度  
235 - let popupViewHeight = 80 + 20 + 20 + 90 + 10;  
236 -  
237 - let popupViewContentList = [{  
238 - src: $iconUrl,  
239 - id: "logo",  
240 - tag: "img",  
241 - position: {  
242 - top: "0px",  
243 - left: (popupViewWidth - 124) / 2 + "px",  
244 - width: "124px",  
245 - height: "80px",  
246 - }  
247 - },  
248 - {  
249 - tag: 'font',  
250 - id: 'title',  
251 - text: "发现新版本" + data.versionName,  
252 - textStyles: {  
253 - size: '18px',  
254 - color: "#333",  
255 - weight: "bold",  
256 - whiteSpace: "normal"  
257 - },  
258 - position: {  
259 - top: '90px',  
260 - left: viewContentPadding + "px",  
261 - width: viewContentWidth + "px",  
262 - height: "30px",  
263 - }  
264 - }];  
265 - const textHeight = 18;  
266 - let contentTop = 130;  
267 - descriptionList.forEach((item,index) => {  
268 - if(index > 0){  
269 - popupViewHeight += textHeight;  
270 - contentTop += textHeight;  
271 - }  
272 - popupViewContentList.push({  
273 - tag: 'font',  
274 - id: 'content' + index + 1,  
275 - text: item.content,  
276 - textStyles: {  
277 - size: '14px',  
278 - color: "#666",  
279 - lineSpacing: "50%",  
280 - align: "left"  
281 - },  
282 - position: {  
283 - top: contentTop + "px",  
284 - left: viewContentPadding + "px",  
285 - width: viewContentWidth + "px",  
286 - height: textHeight + "px",  
287 - }  
288 - });  
289 - if(item.type == "break"){  
290 - contentTop += 10;  
291 - popupViewHeight += 10;  
292 - }  
293 - });  
294 -  
295 - if(data.updateType == "forcibly"){  
296 - popupViewContentList.push({  
297 - tag: 'rect', //绘制底边按钮  
298 - rectStyles:{  
299 - radius: "6px",  
300 - color: $mainColor  
301 - },  
302 - position:{  
303 - bottom: viewContentPadding + 'px',  
304 - left: viewContentPadding + "px",  
305 - width: viewContentWidth + "px",  
306 - height: "30px"  
307 - }  
308 - });  
309 - popupViewContentList.push({  
310 - tag: 'font',  
311 - id: 'confirmText',  
312 - text: "立即升级",  
313 - textStyles: {  
314 - size: '14px',  
315 - color: "#FFF",  
316 - lineSpacing: "0%",  
317 - },  
318 - position: {  
319 - bottom: viewContentPadding + 'px',  
320 - left: viewContentPadding + "px",  
321 - width: viewContentWidth + "px",  
322 - height: "30px"  
323 - }  
324 - });  
325 - } else {  
326 - // 绘制底边按钮  
327 - popupViewContentList.push({  
328 - tag: 'rect',  
329 - id: 'cancelBox',  
330 - rectStyles: {  
331 - radius: "3px",  
332 - borderColor: "#f1f1f1",  
333 - borderWidth: "1px",  
334 - },  
335 - position: {  
336 - bottom: viewContentPadding + 'px',  
337 - left: viewContentPadding + "px",  
338 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
339 - height: "30px",  
340 - }  
341 - });  
342 - popupViewContentList.push({  
343 - tag: 'rect',  
344 - id: 'confirmBox',  
345 - rectStyles: {  
346 - radius: "3px",  
347 - color: $mainColor,  
348 - },  
349 - position: {  
350 - bottom: viewContentPadding + 'px',  
351 - left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",  
352 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
353 - height: "30px",  
354 - }  
355 - });  
356 - popupViewContentList.push({  
357 - tag: 'font',  
358 - id: 'cancelText',  
359 - text: "暂不升级",  
360 - textStyles: {  
361 - size: '14px',  
362 - color: "#666",  
363 - lineSpacing: "0%",  
364 - whiteSpace: "normal"  
365 - },  
366 - position: {  
367 - bottom: viewContentPadding + 'px',  
368 - left: viewContentPadding + "px",  
369 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
370 - height: "30px",  
371 - }  
372 - });  
373 - popupViewContentList.push({  
374 - tag: 'font',  
375 - id: 'confirmText',  
376 - text: "立即升级",  
377 - textStyles: {  
378 - size: '14px',  
379 - color: "#FFF",  
380 - lineSpacing: "0%",  
381 - whiteSpace: "normal"  
382 - },  
383 - position: {  
384 - bottom: viewContentPadding + 'px',  
385 - left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",  
386 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
387 - height: "30px",  
388 - }  
389 - });  
390 - }  
391 - // 弹窗内容  
392 - let popupView = new plus.nativeObj.View("popupView", { //创建底部图标菜单  
393 - tag: "rect",  
394 - top: (screenHeight - popupViewHeight) / 2 + "px",  
395 - left: '15%',  
396 - height: popupViewHeight + "px",  
397 - width: "70%"  
398 - });  
399 - // 绘制白色背景  
400 - popupView.drawRect({  
401 - color: "#FFFFFF",  
402 - radius: "8px"  
403 - }, {  
404 - top: "40px",  
405 - height: popupViewHeight - 40 + "px",  
406 - });  
407 -  
408 - popupView.draw(popupViewContentList);  
409 - popupView.addEventListener("click", function(e) {  
410 - let maxTop = popupViewHeight - viewContentPadding;  
411 - let maxLeft = popupViewWidth - viewContentPadding;  
412 - let buttonWidth = (viewContentWidth - viewContentPadding) / 2;  
413 - if (e.clientY > maxTop - 30 && e.clientY < maxTop) {  
414 - if(data.updateType == "forcibly"){  
415 - if(e.clientX > viewContentPadding && e.clientX < maxLeft){  
416 - // 立即升级  
417 - maskLayer.hide();  
418 - popupView.hide();  
419 - callback && callback();  
420 - }  
421 - } else {  
422 - // 暂不升级  
423 - if (e.clientX > viewContentPadding && e.clientX < maxLeft - buttonWidth - viewContentPadding) {  
424 - maskLayer.hide();  
425 - popupView.hide();  
426 - } else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {  
427 - // 立即升级  
428 - maskLayer.hide();  
429 - popupView.hide();  
430 - callback && callback();  
431 - }  
432 - }  
433 -  
434 - }  
435 - });  
436 - if(data.updateType == "solicit"){  
437 - // 点击遮罩层  
438 - maskLayer.addEventListener("click", function() { //处理遮罩层点击  
439 - maskLayer.hide();  
440 - popupView.hide();  
441 - });  
442 - }  
443 - // 显示弹窗  
444 - maskLayer.show();  
445 - popupView.show();  
446 -}  
447 -// 文件下载的弹窗绘图  
448 -function downloadPopupDrawing(data){  
449 - // 以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心  
450 - const screenWidth = plus.screen.resolutionWidth;  
451 - const screenHeight = plus.screen.resolutionHeight;  
452 - //弹窗容器宽度  
453 - const popupViewWidth = screenWidth * 0.7;  
454 - // 弹窗容器的Padding  
455 - const viewContentPadding = 20;  
456 - // 弹窗容器的宽度  
457 - const viewContentWidth = popupViewWidth - (viewContentPadding * 2);  
458 - // 弹窗容器高度  
459 - let popupViewHeight = viewContentPadding * 3 + 60;  
460 - let progressTip = data.progressTip || "准备下载...";  
461 - let contentText = data.contentText || "正在为您更新,请耐心等待";  
462 - let elementList = [  
463 - {  
464 - tag: 'rect', //背景色  
465 - color: '#FFFFFF',  
466 - rectStyles:{  
467 - radius: "8px"  
468 - }  
469 - },  
470 - {  
471 - tag: 'font',  
472 - id: 'title',  
473 - text: "升级APP",  
474 - textStyles: {  
475 - size: '16px',  
476 - color: "#333",  
477 - weight: "bold",  
478 - verticalAlign: "middle",  
479 - whiteSpace: "normal"  
480 - },  
481 - position: {  
482 - top: viewContentPadding + 'px',  
483 - height: "30px",  
484 - }  
485 - },  
486 - {  
487 - tag: 'font',  
488 - id: 'content',  
489 - text: contentText,  
490 - textStyles: {  
491 - size: '14px',  
492 - color: "#333",  
493 - verticalAlign: "middle",  
494 - whiteSpace: "normal"  
495 - },  
496 - position: {  
497 - top: viewContentPadding * 2 + 30 + 'px',  
498 - height: "20px",  
499 - }  
500 - }  
501 - ];  
502 - // 是否有进度条  
503 - if(data.progress){  
504 - popupViewHeight += viewContentPadding + 40;  
505 - elementList = elementList.concat([  
506 - {  
507 - tag: 'font',  
508 - id: 'progressValue',  
509 - text: progressTip,  
510 - textStyles: {  
511 - size: '14px',  
512 - color: $mainColor,  
513 - whiteSpace: "normal"  
514 - },  
515 - position: {  
516 - top: viewContentPadding * 4 + 20 + 'px',  
517 - height: "30px"  
518 - }  
519 - },  
520 - {  
521 - tag: 'rect', //绘制进度条背景  
522 - id: 'progressBg',  
523 - rectStyles:{  
524 - radius: "4px",  
525 - borderColor: "#f1f1f1",  
526 - borderWidth: "1px",  
527 - },  
528 - position:{  
529 - top: viewContentPadding * 4 + 60 + 'px',  
530 - left: viewContentPadding + "px",  
531 - width: viewContentWidth + "px",  
532 - height: "8px"  
533 - }  
534 - },  
535 - ]);  
536 - }  
537 - if (data.buttonNum == 2) {  
538 - popupViewHeight += viewContentPadding + 30;  
539 - elementList = elementList.concat([  
540 - {  
541 - tag: 'rect', //绘制底边按钮  
542 - rectStyles:{  
543 - radius: "3px",  
544 - borderColor: "#f1f1f1",  
545 - borderWidth: "1px",  
546 - },  
547 - position:{  
548 - bottom: viewContentPadding + 'px',  
549 - left: viewContentPadding + "px",  
550 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
551 - height: "30px"  
552 - }  
553 - },  
554 - {  
555 - tag: 'rect', //绘制底边按钮  
556 - rectStyles:{  
557 - radius: "3px",  
558 - color: $mainColor  
559 - },  
560 - position:{  
561 - bottom: viewContentPadding + 'px',  
562 - left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",  
563 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
564 - height: "30px"  
565 - }  
566 - },  
567 - {  
568 - tag: 'font',  
569 - id: 'cancelText',  
570 - text: "取消下载",  
571 - textStyles: {  
572 - size: '14px',  
573 - color: "#666",  
574 - lineSpacing: "0%",  
575 - whiteSpace: "normal"  
576 - },  
577 - position: {  
578 - bottom: viewContentPadding + 'px',  
579 - left: viewContentPadding + "px",  
580 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
581 - height: "30px",  
582 - }  
583 - },  
584 - {  
585 - tag: 'font',  
586 - id: 'confirmText',  
587 - text: "后台下载",  
588 - textStyles: {  
589 - size: '14px',  
590 - color: "#FFF",  
591 - lineSpacing: "0%",  
592 - whiteSpace: "normal"  
593 - },  
594 - position: {  
595 - bottom: viewContentPadding + 'px',  
596 - left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",  
597 - width: (viewContentWidth - viewContentPadding) / 2 + "px",  
598 - height: "30px",  
599 - }  
600 - }  
601 - ]);  
602 - }  
603 - if (data.buttonNum == 1) {  
604 - popupViewHeight += viewContentPadding + 40;  
605 - elementList = elementList.concat([  
606 - {  
607 - tag: 'rect', //绘制底边按钮  
608 - rectStyles:{  
609 - radius: "6px",  
610 - color: $mainColor  
611 - },  
612 - position:{  
613 - bottom: viewContentPadding + 'px',  
614 - left: viewContentPadding + "px",  
615 - width: viewContentWidth + "px",  
616 - height: "40px"  
617 - }  
618 - },  
619 - {  
620 - tag: 'font',  
621 - id: 'confirmText',  
622 - text: "关闭",  
623 - textStyles: {  
624 - size: '14px',  
625 - color: "#FFF",  
626 - lineSpacing: "0%",  
627 - },  
628 - position: {  
629 - bottom: viewContentPadding + 'px',  
630 - left: viewContentPadding + "px",  
631 - width: viewContentWidth + "px",  
632 - height: "40px"  
633 - }  
634 - }  
635 - ]);  
636 - }  
637 - return {  
638 - popupViewHeight:popupViewHeight,  
639 - popupViewWidth:popupViewWidth,  
640 - screenHeight:screenHeight,  
641 - viewContentWidth:viewContentWidth,  
642 - viewContentPadding:viewContentPadding,  
643 - elementList: elementList  
644 - };  
645 -}  
646 -// 文件下载的弹窗  
647 -function downloadPopup(data) {  
648 - // 弹窗遮罩层  
649 - let maskLayer = new plus.nativeObj.View("maskLayer", { //先创建遮罩层  
650 - top: '0px',  
651 - left: '0px',  
652 - height: '100%',  
653 - width: '100%',  
654 - backgroundColor: 'rgba(0,0,0,0.5)'  
655 - });  
656 - let popupViewData = downloadPopupDrawing(data);  
657 - // 弹窗内容  
658 - let popupView = new plus.nativeObj.View("popupView", { //创建底部图标菜单  
659 - tag: "rect",  
660 - top: (popupViewData.screenHeight - popupViewData.popupViewHeight) / 2 + "px",  
661 - left: '15%',  
662 - height: popupViewData.popupViewHeight + "px",  
663 - width: "70%",  
664 - });  
665 - let progressValue = 0;  
666 - let progressTip = 0;  
667 - let contentText = 0;  
668 - let buttonNum = 2;  
669 - if(data.buttonNum >= 0){  
670 - buttonNum = data.buttonNum;  
671 - }  
672 - popupView.draw(popupViewData.elementList);  
673 - let callbackData = {  
674 - change: function(res) {  
675 - let progressElement = [];  
676 - if(res.progressValue){  
677 - progressValue = res.progressValue;  
678 - // 绘制进度条  
679 - progressElement.push({  
680 - tag: 'rect', //绘制进度条背景  
681 - id: 'progressValueBg',  
682 - rectStyles:{  
683 - radius: "4px",  
684 - color: $mainColor  
685 - },  
686 - position:{  
687 - top: popupViewData.viewContentPadding * 4 + 60 + 'px',  
688 - left: popupViewData.viewContentPadding + "px",  
689 - width: popupViewData.viewContentWidth * (res.progressValue / 100) + "px",  
690 - height: "8px"  
691 - }  
692 - });  
693 - }  
694 - if(res.progressTip){  
695 - progressTip = res.progressTip;  
696 - progressElement.push({  
697 - tag: 'font',  
698 - id: 'progressValue',  
699 - text: res.progressTip,  
700 - textStyles: {  
701 - size: '14px',  
702 - color: $mainColor,  
703 - whiteSpace: "normal"  
704 - },  
705 - position: {  
706 - top: popupViewData.viewContentPadding * 4 + 20 + 'px',  
707 - height: "30px"  
708 - }  
709 - });  
710 - }  
711 - if(res.contentText){  
712 - contentText = res.contentText;  
713 - progressElement.push({  
714 - tag: 'font',  
715 - id: 'content',  
716 - text: res.contentText,  
717 - textStyles: {  
718 - size: '16px',  
719 - color: "#333",  
720 - whiteSpace: "normal"  
721 - },  
722 - position: {  
723 - top: popupViewData.viewContentPadding * 2 + 30 + 'px',  
724 - height: "30px",  
725 - }  
726 - });  
727 - }  
728 - if(res.buttonNum >= 0 && buttonNum != res.buttonNum){  
729 - buttonNum = res.buttonNum;  
730 - popupView.reset();  
731 - popupViewData = downloadPopupDrawing(Object.assign({  
732 - progressValue:progressValue,  
733 - progressTip:progressTip,  
734 - contentText:contentText,  
735 - },res));  
736 - let newElement = [];  
737 - popupViewData.elementList.map((item,index) => {  
738 - let have = false;  
739 - progressElement.forEach((childItem,childIndex) => {  
740 - if(item.id == childItem.id){  
741 - have = true;  
742 - }  
743 - });  
744 - if(!have){  
745 - newElement.push(item);  
746 - }  
747 - });  
748 - progressElement = newElement.concat(progressElement);  
749 - popupView.setStyle({  
750 - tag: "rect",  
751 - top: (popupViewData.screenHeight - popupViewData.popupViewHeight) / 2 + "px",  
752 - left: '15%',  
753 - height: popupViewData.popupViewHeight + "px",  
754 - width: "70%",  
755 - });  
756 - popupView.draw(progressElement);  
757 - }else{  
758 - popupView.draw(progressElement);  
759 - }  
760 - },  
761 - cancel: function() {  
762 - maskLayer.hide();  
763 - popupView.hide();  
764 - }  
765 - }  
766 - popupView.addEventListener("click", function(e) {  
767 - let maxTop = popupViewData.popupViewHeight - popupViewData.viewContentPadding;  
768 - let maxLeft = popupViewData.popupViewWidth - popupViewData.viewContentPadding;  
769 - if (e.clientY > maxTop - 40 && e.clientY < maxTop) {  
770 - if(buttonNum == 1){  
771 - // 单按钮  
772 - if (e.clientX > popupViewData.viewContentPadding && e.clientX < maxLeft) {  
773 - maskLayer.hide();  
774 - popupView.hide();  
775 - callbackData.reboot();  
776 - }  
777 - }else if(buttonNum == 2){  
778 - // 双按钮  
779 - let buttonWidth = (popupViewData.viewContentWidth - popupViewData.viewContentPadding) / 2;  
780 - if (e.clientX > popupViewData.viewContentPadding && e.clientX < maxLeft - buttonWidth - popupViewData.viewContentPadding) {  
781 - maskLayer.hide();  
782 - popupView.hide();  
783 - callbackData.cancelDownload();  
784 - } else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {  
785 - maskLayer.hide();  
786 - popupView.hide();  
787 - }  
788 - }  
789 - }  
790 - });  
791 - // 显示弹窗  
792 - maskLayer.show();  
793 - popupView.show();  
794 - // 改变进度条  
795 - return callbackData;  
796 -}  
797 -export default function(isPrompt = false) {  
798 - getCurrentNo(versionInfo => {  
799 - componentConfig.getServerNo(versionInfo, isPrompt, res => {  
800 - if (res.updateType == "forcibly" || res.updateType == "silent") {  
801 - if (/\.wgt$/i.test(res.downloadUrl)) {  
802 - getDownload(res);  
803 - } else if(/\.html$/i.test(res.downloadUrl)){  
804 - plus.runtime.openURL(res.downloadUrl);  
805 - } else {  
806 - if (platform == "android") {  
807 - getDownload(res);  
808 - } else {  
809 - plus.runtime.openURL(res.downloadUrl);  
810 - }  
811 - }  
812 - } else if(res.updateType == "solicit"){  
813 - updatePopup(res, function() {  
814 - if (/\.wgt$/i.test(res.downloadUrl)) {  
815 - getDownload(res);  
816 - } else if(/\.html$/i.test(res.downloadUrl)){  
817 - plus.runtime.openURL(res.downloadUrl);  
818 - } else {  
819 - if (platform == "android") {  
820 - getDownload(res);  
821 - } else {  
822 - plus.runtime.openURL(res.downloadUrl);  
823 - }  
824 - }  
825 - });  
826 - }  
827 - });  
828 - });  
829 -}  
830 -// #endif  
1 -{  
2 - "id": "zhouWei-APPUpdate",  
3 - "displayName": "APP版本更新、强制更新、静默更新、下载进度(wgt更新)",  
4 - "version": "3.0.1",  
5 - "description": "APP版本更新、强制更新、静默更新、漂亮弹窗、下载进度(wgt更新)",  
6 - "keywords": [  
7 - "APP版本更新",  
8 - "强制更新",  
9 - "版本更新",  
10 - "静默更新"  
11 -],  
12 - "repository": "https://github.com/zhouwei1994/uni-app-demo",  
13 - "engines": {  
14 - "HBuilderX": "^3.1.0"  
15 - },  
16 - "dcloudext": {  
17 - "category": [  
18 - "JS SDK",  
19 - "通用 SDK"  
20 - ],  
21 - "sale": {  
22 - "regular": {  
23 - "price": "0.00"  
24 - },  
25 - "sourcecode": {  
26 - "price": "0.00"  
27 - }  
28 - },  
29 - "contact": {  
30 - "qq": "465081029"  
31 - },  
32 - "declaration": {  
33 - "ads": "无",  
34 - "data": "无",  
35 - "permissions": "<uses-permission android:name=\\\"android.permission.INSTALL_PACKAGES\\\"/> \n<uses-permission android:name=\\\"android.permission.REQUEST_INSTALL_PACKAGES\\\"/>"  
36 - },  
37 - "npmurl": ""  
38 - },  
39 - "uni_modules": {  
40 - "dependencies": [],  
41 - "encrypt": [],  
42 - "platforms": {  
43 - "cloud": {  
44 - "tcb": "y",  
45 - "aliyun": "y"  
46 - },  
47 - "client": {  
48 - "App": {  
49 - "app-vue": "y",  
50 - "app-nvue": "y"  
51 - },  
52 - "H5-mobile": {  
53 - "Safari": "n",  
54 - "Android Browser": "n",  
55 - "微信浏览器(Android)": "n",  
56 - "QQ浏览器(Android)": "n"  
57 - },  
58 - "H5-pc": {  
59 - "Chrome": "n",  
60 - "IE": "n",  
61 - "Edge": "n",  
62 - "Firefox": "n",  
63 - "Safari": "n"  
64 - },  
65 - "小程序": {  
66 - "微信": "n",  
67 - "阿里": "n",  
68 - "百度": "n",  
69 - "字节跳动": "n",  
70 - "QQ": "n"  
71 - },  
72 - "快应用": {  
73 - "华为": "n",  
74 - "联盟": "n"  
75 - }  
76 - }  
77 - }  
78 - }  
79 -}  
1 -### 常见问题  
2 -1.安卓apk下载完成后没有更新APP?  
3 -  
4 -答:问题是因为没有添加APP安装应用的权限,解决方法在`manifest.json`文件里面`APP模块权限配置`的`Android打包权限配置`勾选以下权限  
5 -```  
6 -<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>  
7 -<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>  
8 -```  
9 -若还有问题请看[安装apk无法执行的解决方案](https://ask.dcloud.net.cn/article/35703 "安装apk无法执行的解决方案")  
10 -  
11 -2.APP更新后版本号没变,还是之前的版本号?  
12 -  
13 -答:可能是更新的安装包没有升级版本号,`manifest.json`文件里面基本设置`应用版本号`和`应用版本名称`需要升高(保持一直减少问题)  
14 -  
15 -3.APP更新后没有覆盖之前的APP?  
16 -  
17 -答:可能是更新的安装包`包名`和APP的`包名`不一样  
18 -  
19 -4.弹窗的图标不显示?  
20 -  
21 -答:检查图片是不是放项目资源文件`static`,然后重新运行项目  
22 -  
23 -5.版本号是在前端对比还是在后端接口对比?  
24 -  
25 -答:当前案例是本地的版本号通过接口传递给后台,是后台对比的,若需要前端对比,请在接口返回数据的地方修改,不更新就不要调用`callback`方法  
26 -  
27 -6.本地的版本号比接口的版本号高还弹窗升级窗口?  
28 -  
29 -答:当前案例是本地的版本号通过接口传递给后台,后台对比是否需要升级,不需要升级就不要返回数据(特别是需要wgt更新的,建议这种方式)  
30 -  
31 -### 第一步`关键`配置APP更新接口(可以参考上面的示例)  
32 -在项目目录下`config/componentConfig.js`里面如下配置  
33 -```  
34 -// 此方法是接口请求方法  
35 -import $http from '@/config/requestConfig'  
36 -export default {  
37 - // 发起ajax请求获取服务端版本号  
38 - getServerNo: (version, isPrompt = false, callback) => {  
39 - let httpData = {  
40 - version: version.versionCode,  
41 - // 版本名称  
42 - versionName: version.versionName,  
43 - // setupPage参数说明(判断用户是不是从设置页面点击的更新,如果是设置页面点击的更新,有不要用静默更新了,不然用户点击没反应很奇怪的)  
44 - setupPage: isPrompt  
45 - };  
46 - if (platform == "android") {  
47 - httpData.type = 1101;  
48 - } else {  
49 - httpData.type = 1102;  
50 - }  
51 - /* 接口入参说明  
52 - * version: 应用当前版本号(已自动获取)  
53 - * versionName: 应用当前版本名称(已自动获取)  
54 - * type:平台(1101是安卓,1102是IOS)  
55 - */  
56 - /****************以下是示例*******************/  
57 - // 可以用自己项目的请求方法(接口自己找后台要,插件不提供)  
58 - $http.get("api/common/v1/app_version", httpData,{  
59 - isPrompt: isPrompt  
60 - }).then(res => {  
61 - /* res的数据说明  
62 - * | 参数名称 | 一定返回 | 类型 | 描述  
63 - * | -------------|--------- | --------- | ------------- |  
64 - * | versionCode | y | int | 版本号 |  
65 - * | versionName | y | String | 版本名称 |  
66 - * | versionInfo | y | String | 版本信息 |  
67 - * | updateType | y | String | forcibly = 强制更新, solicit = 弹窗确认更新, silent = 静默更新 |  
68 - * | downloadUrl | y | String | 版本下载链接(IOS安装包更新请放跳转store应用商店链接,安卓apk和wgt文件放文件下载链接) |  
69 - */  
70 - if (res && res.downloadUrl) {  
71 - // 兼容之前的版本(updateType是新版才有的参数)  
72 - if(res.updateType){  
73 - callback && callback(res);  
74 - } else {  
75 - if(res.forceUpdate){  
76 - res.updateType = "forcibly";  
77 - } else {  
78 - res.updateType = "solicit";  
79 - }  
80 - callback && callback(res);  
81 - }  
82 - } else if (isPrompt) {  
83 - uni.showToast({  
84 - title: "暂无新版本",  
85 - icon: "none"  
86 - });  
87 - }  
88 - });  
89 - /****************以上是示例*******************/  
90 - },  
91 - // 弹窗主颜色(不填默认粉色)  
92 - appUpdateColor: "f00",  
93 - // 弹窗图标(不填显示默认图标,链接配置示例如: '/static/demo/ic_attention.png')  
94 - appUpdateIcon: ''  
95 -}  
96 -```  
97 -  
98 -### 第二步 使用方法  
99 -```  
100 -// App.vue页面  
101 -  
102 -// #ifdef APP-PLUS  
103 -import APPUpdate from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';  
104 -// #endif  
105 -  
106 -onLaunch: function(e) {  
107 - // #ifdef APP-PLUS  
108 - APPUpdate();  
109 - // #endif  
110 -}  
111 -```  
112 -  
113 -### 第三步 添加APP安装应用的权限  
114 -`manifest.json`文件里面`APP模块权限配置`的`Android打包权限配置`勾选以下权限  
115 -```  
116 -<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>  
117 -<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>  
118 -```  
119 -  
120 -### 修改弹窗的主题色或弹窗图标  
121 -`APPUpdate/index.js`里面上面`$mainColor`常量中定义主题颜色,`$iconUrl`常量中定义图标地址  
122 -  
123 -### 检查APP是否有新版本(一般在设置页面使用)  
124 -```  
125 -// #ifdef APP-PLUS  
126 -import APPUpdate, { getCurrentNo } from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';  
127 -// #endif  
128 -export default {  
129 - data() {  
130 - return {  
131 - version: "" // 版本号  
132 - };  
133 - },  
134 - //第一次加载  
135 - onLoad(e) {  
136 - // #ifdef APP-PLUS  
137 - getCurrentNo(res => {  
138 - // 进页面获取当前APP版本号(用于页面显示)  
139 - this.version = res.version;  
140 - });  
141 - // #endif  
142 - },  
143 - //方法  
144 - methods: {  
145 - // 检查APP是否有新版本  
146 - onAPPUpdate() {  
147 - // true 没有新版本的时候有提示,默认:false  
148 - APPUpdate(true);  
149 - }  
150 - }  
151 -}  
152 -```