ソースを参照

运营看板小程序登录页、图标页

zuy 2 年 前
コミット
3723b3dc03

+ 1 - 1
package.json

@@ -1,5 +1,5 @@
 {
-  "name": "快与慢运营看板",
+  "name": "kuaiyuman",
   "version": "1.0.1",
   "scripts": {
     "dev:h5": "uni",

ファイルの差分が大きいため隠しています
+ 17 - 0
src/assets/u-charts.min.js


+ 190 - 0
src/assets/utils.js

@@ -0,0 +1,190 @@
+const env = process.env.NODE_ENV==="development"?"dev":"prd";
+let apis = {
+    dev: {
+        serverUrl: "http://localhost:8080/admin/",
+        fileUrl: "https://zyp-1258963180.cos.ap-guangzhou.myqcloud.com/"
+    },
+    uat: {
+        serverUrl: "http://npt.free.idcfengye.com/",
+        fileUrl: "https://zyp-1258963180.cos.ap-guangzhou.myqcloud.com/"
+    },
+    prd: {
+        serverUrl: "https://npww.net.cn/cms/",
+        fileUrl: "https://zyp-1258963180.cos.ap-guangzhou.myqcloud.com/",
+    },
+};
+const cfg = {
+    key: {
+        token: 'kuaiyuman.token',
+        account:'kuaiyuman.account',
+    },
+    env: env,
+    api: {
+        serverUrl: apis[env].serverUrl,
+        fileUrl: apis[env].fileUrl,
+        uploadUrl: apis[env].serverUrl + "file/upload"
+    }
+};
+
+const serverUrl = cfg.api.serverUrl;
+const fileUrl = cfg.api.fileUrl;
+
+const isEmptyOrNull = function (exp) {
+    return !exp || typeof (exp) == "undefined" || exp.length === 0 || exp === '' || JSON.stringify(exp) === "{}";
+};
+
+
+/**
+ * get请求封装
+ * @param url
+ * @param param
+ */
+const get = (url, param = {}) => {
+    let token = uni.getStorageSync(cfg.key.token) || "";
+    if (!isEmptyOrNull(param)) {
+        var params = [];
+        for (var key in param) {
+            params.push(encodeURIComponent(key) + "=" + encodeURIComponent(param[key]));
+        }
+        param = params.join("&")
+    }
+    let options = {
+        url: fillUrl(url) + (isEmptyOrNull(param) ? "" : "?" + param),
+        data: param,
+        method: 'GET',
+        header: {
+            "Accept": "application/json",
+            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
+            "satoken": token,
+        },
+    };
+    return request(options)
+};
+
+
+const post = (url, param = {}) => {
+    let token = uni.getStorageSync(cfg.key.token) || "";
+    let options = {
+        url: fillUrl(url),
+        data: param,
+        method: 'POST',
+        header: {
+            'X-Requested-With': 'XMLHttpRequest',
+            "Accept": "application/json",
+            "Content-Type": "application/json; charset=UTF-8",
+            "satoken": token,
+        },
+        dataType: 'json'
+    };
+    return request(options);
+};
+
+
+const request = (options) => {
+    return new Promise((resolve, reject) => {
+        uni.request({
+            url: options.url,
+            data: options.data,
+            method: options.method,
+            header: options.header,
+            dataType: options.dataType
+        }).then(res => {
+            let response = res[1].data;
+            if (response.code !== 200) {
+                if (response.code == 10001) {
+                    uni.showToast({
+                        title: response.message,
+                        icon: 'none'
+                    });
+                    setTimeout(() => {
+                        uni.navigateTo({
+                            url: `/pages/login/login`
+                        })
+                    }, 300)
+
+                } else {
+                    let errMsg = response.message || '网络异常,请稍后重试';
+                    uni.showToast({
+                        title: errMsg,
+                        icon: 'none'
+                    });
+                    reject(errMsg);
+                }
+            } else {
+                resolve(response.data);
+            }
+        }).catch(error => {
+            uni.hideLoading();
+            uni.showToast({
+                title: '网络异常,请稍后重试',
+                icon: 'none'
+            });
+            console.error("error=>", error);
+            reject(error.msg);
+        })
+    });
+};
+
+const upload = opt => {
+    opt = opt || {};
+    opt.url = opt.url || '';
+    opt.filePath = opt.filePath || null;//要上传文件资源的路径。
+    opt.name = opt.name || null;//文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容
+
+    opt.filePath = opt.filePath || null;
+    opt.success = opt.success || function () {
+    };
+
+
+    uni.uploadFile({
+        url: fillUrl(opt.url),
+        filePath: opt.filePath,
+        name: opt.name,
+        success: function (res) {
+            console.log("upload file=>", res)
+            opt.success(res);
+        },
+        fail: function () {
+            uni.showToast({
+                title: '请稍后重试'
+            });
+        }
+    })
+};
+
+
+const fillUrl = function (url) {
+    if (url.indexOf("http") === 0) {
+        return url;
+    } else {
+        return serverUrl + url;
+    }
+};
+
+const formatUrl = v => {
+    if (v == null || v == "") {
+        return "/static/missing-face.png";
+    }
+    if (v.indexOf("http") === 0) {
+        return v;
+    }
+    return fileUrl + v.replace(/\\/g, "/");
+};
+
+
+const msg = (title, icon = 'none', duration = 1800, mask = false) => {
+    //统一提示方便全局修改
+    if (Boolean(title) === false) {
+        return;
+    }
+    uni.showToast({
+        title,
+        duration,
+        mask,
+        icon
+    });
+};
+
+export {
+    get, post, upload, cfg, serverUrl, fileUrl,formatUrl,msg
+}

+ 7 - 1
src/pages.json

@@ -3,7 +3,13 @@
 		{
 			"path": "pages/index/index",
 			"style": {
-				"navigationBarTitleText": "uni-app"
+				"navigationBarTitleText": "运营看板"
+			}
+		},
+		{
+			"path": "pages/login/index",
+			"style": {
+				"navigationBarTitleText": "登录"
 			}
 		}
 	],

+ 99 - 12
src/pages/index/index.vue

@@ -1,22 +1,109 @@
 <template>
   <view class="content">
-    <image class="logo" src="/static/logo.png"></image>
-    <view class="text-area">
-      <text class="title">{{ title }}</text>
+    <!--    <image class="logo" src="/static/logo.png"></image>
+        <view class="text-area">
+          <text class="title">{{ state.title }}</text>
+        </view>-->
+    <div class="header">
+      <view class="header-left">站点选择</view>
+      <view class="header-right">用户XXX</view>
+    </div>
+    <view class="content">
+      <view class="content-summary">
+        <view v-for="item in state.statList" class="content-summary-item">
+          <view>{{item.label}}</view>
+          <view>{{item.value}}</view>
+        </view>
+      </view>
+
+      <view>
+        <text>运营数据</text>
+        <button>7天</button>
+        <button>30天</button>
+        <button>90天</button>
+      </view>
+
+      <view>
+        <canvas id="charge-order-num" canvas-id="charge-ele-total" class="charts" @tap="tap"></canvas>
+      </view>
+      <view>
+        <canvas id="charge-order-num" canvas-id="charge-order-money" class="charts" @tap="tap"></canvas>
+      </view>
+      <view>
+        <canvas id="charge-order-num" canvas-id="charge-ele-fee" class="charts" @tap="tap"></canvas>
+      </view>
+      <view>
+        <canvas id="charge-order-num" canvas-id="charge-service-money" class="charts" @tap="tap"></canvas>
+      </view>
+      <view>
+        <canvas id="charge-order-num" canvas-id="charge-order-user" class="charts" @tap="tap"></canvas>
+      </view>
+      <view>
+        <canvas id="charge-order-num" canvas-id="charge-order-num" class="charts" @tap="tap"></canvas>
+      </view>
     </view>
   </view>
 </template>
 
-<script>
-export default {
-  data() {
-    return {
-      title: '快与慢运营看板小程序',
+<script setup>
+import {reactive} from 'vue';
+import {onLoad} from '@dcloudio/uni-app'
+
+import uCharts from "../../assets/u-charts.min";
+
+const uChartsInstance = {};
+
+const state = reactive({
+  title: '快与慢运营看板小程序',
+  cWidth:750,
+  cHeight:500,
+  statList: [
+    {label: '今日充电量', value: '100'},
+    {label: '今日订单总金额', value: '100'},
+    {label: '今日总电费', value: '100'},
+    {label: '今日实付总服务费', value: '100'},
+    {label: '今日充电人数', value: '100'},
+    {label: '今日充电订单数', value: '100'},
+  ]
+})
+
+
+onLoad(()=>{
+  //这里的 750 对应 css .charts 的 width
+  state.cWidth = uni.upx2px(750);
+  //这里的 500 对应 css .charts 的 height
+  state.cHeight = uni.upx2px(500);
+})
+
+const tap = (e) => {
+  uChartsInstance[e.target.id].touchLegend(e);
+  uChartsInstance[e.target.id].showToolTip(e);
+}
+
+const  drawCharts = (canvasId, data) => {
+  const ctx = uni.createCanvasContext(canvasId, this);
+  uChartsInstance[canvasId] = new uCharts({
+    type: "column",
+    context: ctx,
+    width: state.cWidth,
+    height: state.cHeight,
+    categories: data.categories,
+    series: data.series,
+    xAxis: {
+      disableGrid: true
+    },
+    yAxis: {
+      data: [ { min: 0 } ]
+    },
+    extra: {
+      column: {
+        type: "group"
+      }
     }
-  },
-  onLoad() {},
-  methods: {},
+  });
+
 }
+
 </script>
 
 <style>
@@ -33,7 +120,7 @@ export default {
   margin-top: 200rpx;
   margin-left: auto;
   margin-right: auto;
-  margin-bottom: 50rpx;
+  margin-bottom: 5 rpx;
 }
 
 .text-area {

+ 208 - 0
src/pages/login/index.vue

@@ -0,0 +1,208 @@
+<style scoped>
+.header {
+  margin: 90rpx 0 90rpx 50rpx;
+  border-bottom: 1px solid #ccc;
+  text-align: center;
+  width: 650rpx;
+  height: 300rpx;
+  line-height: 450rpx;
+}
+
+.header image {
+  width: 200rpx;
+  height: 200rpx;
+}
+
+.content {
+  margin-left: 50rpx;
+  margin-bottom: 90rpx;
+}
+
+.content text {
+  display: block;
+  color: #9d9d9d;
+  margin-top: 40rpx;
+}
+
+.bottom {
+  border-radius: 60rpx;
+  margin: 20rpx 50rpx;
+  font-size: 35rpx;
+}
+
+.login {
+  background-color: #ccc;
+}
+</style>
+<template>
+  <view>
+    <!-- #ifdef MP-WEIXIN -->
+    <view v-if="state.isCanUse">
+      <view>
+        <view class='header'>
+          <image src='../../static/weichat.svg'></image>
+        </view>
+        <view class='content'>
+          <view>申请获取以下权限</view>
+          <text>获得你的公开信息(昵称,头像、地区等)</text>
+        </view>
+
+        <!--        <button class='bottom' type='primary' open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="handleGetUserInfo">
+                  微信授权登录
+                </button>-->
+        <button v-if="state.requireMobile"  class='bottom' type='primary' open-type="getPhoneNumber" withCredentials="true" lang="zh_CN" @getuserinfo="handleRequestPhoneNumber">
+          获取手机号
+        </button>
+      </view>
+    </view>
+    <!-- #endif -->
+  </view>
+</template>
+<script setup>
+import {onLoad, onUnload} from '@dcloudio/uni-app';
+import {reactive} from 'vue';
+import {msg, cfg, post} from '../../assets/utils.js'
+// import {
+//     mapMutations
+// } from 'vuex';
+
+const state = reactive({
+  sessionKey: '',
+  unionid: '',
+  phoneNumber: '',
+  nickName: null,
+  avatarUrl: null,
+  isCanUse: uni.getStorageSync('isCanUse') || true,//默认为true,
+  requireMobile:false
+})
+
+/**
+ * 微信登录
+ */
+const initLogin = () => {
+  uni.showLoading({
+    title: '登录中...'
+  });
+
+  // 1.wx获取登录用户code
+  uni.login({
+    provider: 'weixin',
+    success: function (res) {
+      let code = res.code;
+      /* if (!state.isCanUse) {
+
+       }*/
+      //2.将用户登录code传递到后台置换用户SessionKey、OpenId等信息
+      post("wx/getUnionId", {code: code}).then(res => {
+        console.error(res)
+        state.unionid = res.unionid;
+        state.sessionKey = res.session_key;
+        // state.loginSign = res.sign;
+        //尝试unionid登录
+        uni.hideLoading();
+        loginByUnion();
+      }).catch(error => {
+        console.error("login error", error)
+        msg("登录失败");
+      });
+    },
+    fail(e) {
+      console.error("provider fail,", e)
+      msg("请开启登录授权");
+      openSetting();
+    }
+  });
+
+}
+
+const loginByUnion=()=>{
+  post(`wx/loginByUnion`,{unionId:state.unionid}).then(res => {
+    let user = res;
+    if(!res||!res.user||!res.user.mobilePhone){
+      state.requireMobile = true;
+    }else{
+      loginSuccess(res);
+    }
+  })
+}
+
+const openSetting = () => {
+  uni.openSetting({
+    success: (setting) => {
+      console.log(setting.authSetting)
+    }
+  })
+}
+
+const handleGetUserInfo = () => {
+  uni.getUserInfo({
+    provider: 'weixin',
+    success: function (res) {
+      try {
+        uni.setStorageSync('isCanUse', false);//记录是否第一次授权  false:表示不是第一次授权
+        updateUserInfo(res.userInfo);
+      } catch (e) {
+        console.error("wxGetUserInfo ERR,", e)
+      }
+    },
+    fail(e) {
+      console.error("wxGetUserInfo fail,", e)
+      msg("请开启登录授权");
+      openSetting();
+    }
+  });
+}
+
+
+const handleRequestPhoneNumber = (e) => {
+  console.log(e)
+  get(`wx/getPhoneNumber?code=${e.detail.code}`).then(res => {
+    state.phoneNumber = res.phoneNumber;
+    post(`wx/login`,{unionId:state.unionid,mobilePhone:res.phoneNumber}).then(res1 => {
+      loginSuccess(res1);
+    })
+  })
+}
+
+const updateUserInfo = (userInfo) => {
+  this.nickName = userInfo.nickName;
+  this.avatarUrl = userInfo.avatarUrl;
+  userInfo['openId'] = state.openId;
+  post("wx/updateAdminUser", userInfo).then(res => {
+    loginSuccess(res);
+  }).catch(error => {
+    console.error("updateUserInfo Err", error);
+    msg("系统繁忙,请稍后再试", "none")
+  });
+
+}
+
+const loginSuccess = (res)=>{
+  let {user, satoken} = res;
+  uni.setStorageSync(//缓存用户登陆状态
+      cfg.key.account,
+      user
+  );
+  uni.setStorageSync(//缓存用户登陆状态
+      cfg.key.token,
+      satoken
+  );
+  msg("登录成功");
+  // login(res);
+  // _this.$store.commit("login",res.account)
+  // uni.reLaunch({//信息更新成功后跳转到小程序首页
+  //     url: '/pages/index/index'
+  // });
+  uni.navigateBack();
+}
+
+onLoad((Option) => {
+  console.log(Option)
+  initLogin();
+  // accountLogin();
+})
+
+onUnload(() => {
+  uni.navigateBack();
+})
+</script>

BIN
src/static/logo.png


ファイルの差分が大きいため隠しています
+ 0 - 0
src/static/weichat.svg


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません