完成师傅注册登录、部分基础功能

This commit is contained in:
TOP糯米 2023-03-12 21:57:00 +08:00
parent bedeacc239
commit 9917390e9b
19 changed files with 910 additions and 219 deletions

View File

@ -1,7 +1,25 @@
<script> <script>
export default { export default {
onLaunch: function () { globalData: {
this.$store.dispatch("system/initConfig"); pageConfig: {},
},
onLaunch: async function () {
let pageConfig = this.$storage.get("system_config");
if (!pageConfig) {
const { windowWidth, windowHeight, statusBarHeight, safeAreaInsets } = uni.getSystemInfoSync();
// #ifndef H5
const { height, top } = uni.getMenuButtonBoundingClientRect();
const headerHeight = height + (top - statusBarHeight) * 2;
// #endif
// #ifdef H5
const headerHeight = 40; // 2使rpx2pxpx使
// #endif
pageConfig = { windowWidth, windowHeight, statusBarHeight, headerHeight, safeAreaInsets };
this.$storage.set("system_config", pageConfig);
}
this.globalData.pageConfig = pageConfig;
//
this.$models.user.initUser();
}, },
onShow: function () {}, onShow: function () {},
onHide: function () {}, onHide: function () {},
@ -160,4 +178,41 @@ export default {
justify-content: space-between; justify-content: space-between;
background-color: #ffffff; background-color: #ffffff;
} }
//
.common-form-container {
width: 710rpx;
background-color: #fff;
margin: 20rpx auto 0 auto;
.input-item {
width: 100%;
box-sizing: border-box;
height: 105rpx;
border-bottom: 2rpx solid #e8e7e7;
display: flex;
align-items: center;
padding: 0 30rpx;
line-height: 30rpx;
// input
.input-box {
width: 500rpx;
position: relative;
padding: 25rpx 0;
}
.input {
font-size: 28rpx;
}
.title-box {
width: 150rpx;
font-size: 30rpx;
font-weight: bold;
line-height: 30rpx;
color: #2d2d2d;
}
.desc {
font-size: 28rpx;
color: #999999;
}
}
}
</style> </style>

View File

@ -0,0 +1,74 @@
<template>
<view class="auth-login-box">
<widget-modal v-show="showLoginModal" title="该操作需要登录" @close="closeModal" :showClose="false">
<view class="login-box">
<view class="btn" @click="toLogin">去登录</view>
</view>
</widget-modal>
</view>
</template>
<script>
import WidgetModal from "@/components/widgets/modal";
import { mapState } from "vuex";
export default {
name: "auth-login-box",
data() {
return {};
},
components: {
WidgetModal,
},
computed: {
...mapState({
showLoginModal: (state) => state.user.showLoginModal,
}),
},
created() {},
mounted() {},
destroyed() {},
methods: {
/**
* 关闭弹窗
* 如果在tabBar页面则relaunch否则返回
*/
closeModal() {
this.$store.commit("user/showLoginModal", false);
if (getCurrentPages().length <= 1) {
this.$utils.toPage("/pages/index/index", {}, "relaunch");
} else {
this.$utils.toPage("", {}, "back");
}
},
/**
* 登录页面
*/
toLogin() {
this.$store.commit("user/showLoginModal", false);
this.$utils.toPage("/pages/auth/auth");
},
},
};
</script>
<style lang="less" scoped>
.auth-login-box {
.login-box {
width: 100%;
display: flex;
justify-content: center;
margin-top: 20rpx;
}
.btn {
width: 100%;
background: #7286f1;
// border-radius: 50rpx;
padding: 20rpx 100rpx;
color: #ffffff;
font-size: 28rpx;
line-height: 28rpx;
text-align: center;
box-sizing: border-box;
}
}
</style>

View File

@ -29,11 +29,14 @@
<slot></slot> <slot></slot>
</view> </view>
<view class="page-footer"></view> <view class="page-footer"></view>
<!-- 组件 -->
<auth-login-box />
</view> </view>
</template> </template>
<script> <script>
import { mapState } from "vuex"; import AuthLoginBox from "@/components/auth/login-box";
import { mapGetters, mapState } from "vuex";
export default { export default {
name: "component-layout", name: "component-layout",
data() { data() {
@ -43,7 +46,9 @@ export default {
bodyPaddingTop: 0, bodyPaddingTop: 0,
}; };
}, },
components: {}, components: {
AuthLoginBox,
},
props: { props: {
minHeight: { minHeight: {
type: String, type: String,
@ -79,12 +84,12 @@ export default {
}, },
}, },
computed: { computed: {
...mapState({ ...mapGetters({
config: (state) => state.system.config, isLogin: "user/isLogin",
}), }),
}, },
mounted() { mounted() {
const { statusBarHeight, headerHeight } = this.config; const { statusBarHeight, headerHeight } = getApp().globalData.pageConfig;
// #ifndef H5 // #ifndef H5
this.statusBarHeight = statusBarHeight; this.statusBarHeight = statusBarHeight;
this.headerHeight = headerHeight; this.headerHeight = headerHeight;
@ -98,6 +103,9 @@ export default {
if (this.showHeader) { if (this.showHeader) {
this.bodyPaddingTop = safePaddingTop; this.bodyPaddingTop = safePaddingTop;
} }
if (this.isLogin) {
this.$store.dispatch("user/info");
}
}, },
methods: { methods: {
onClick() { onClick() {

View File

@ -6,7 +6,7 @@
<text class="title"> <text class="title">
{{ title }} {{ title }}
</text> </text>
<text class="iconfont icon-guanbi close" @click="close"></text> <text class="iconfont icon-guanbi close" v-if="showClose" @click="close"></text>
</view> </view>
<view class="content-box"> <view class="content-box">
<slot></slot> <slot></slot>
@ -30,6 +30,10 @@ export default {
type: String, type: String,
default: "650rpx", default: "650rpx",
}, },
showClose: {
type: Boolean,
default: true,
},
}, },
components: {}, components: {},
created() {}, created() {},
@ -52,7 +56,7 @@ export default {
right: 0; right: 0;
max-width: 750px; max-width: 750px;
width: 100%; width: 100%;
height: 100vh; height: 100%;
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -94,7 +98,7 @@ export default {
} }
} }
.content-box { .content-box {
// padding-top: 15rpx; padding-top: 15rpx;
} }
} }
</style> </style>

View File

@ -1,7 +1,24 @@
const apis = { const apis = {
member: { user: {
info: "/member/info" sendCode: {
} url: "/wxapp/public/send",
},
openId: {
url: "/wxapp/public/getopenid",
},
register: {
url: "/wxapp/public/registerb",
},
login: {
url: "/wxapp/public/loginb",
},
resetPassword: {
url: "/wxapp/public/passwordReset",
},
info: {
url: "/user/workerinfo/getuserinfo",
},
},
} }
export default apis export default apis

View File

@ -1,6 +1,8 @@
const config = { const config = {
name: "熊熊安装", name: "熊熊安装",
root: "http://127.0.0.1/api.php" storagePrefix: "worker_",
appId: "wx2401c65b68a6c9b5",
root: "http://xiongxiong.vipwjf.com/api.php"
} }
export default config export default config

View File

@ -1,17 +0,0 @@
const request = async (args) => {
const header = {
'X-Requested-With': 'XMLHttpRequest',
'content-type': 'application/x-www-form-urlencoded',
};
const [error, response] = await uni.request({
url: args.url,
method: args.method || 'get',
data: args.data,
header: header
});
return Promise.resolve(response);
};
export default request

View File

@ -1,3 +1,5 @@
import $storage from '@/core/storage'
function time() { function time() {
return parseInt(Math.round(new Date() / 1000)); return parseInt(Math.round(new Date() / 1000));
}; };
@ -143,29 +145,68 @@ function debounce(func, wait = 500, immediate = false) {
} }
function px2rpx(px) { function px2rpx(px) {
let { windowWidth } = uni.getStorageSync('system_config'); let { windowWidth } = $storage.get('system_config');
windowWidth = (windowWidth > 750) ? 750 : windowWidth; windowWidth = (windowWidth > 750) ? 750 : windowWidth;
return 750 * (px / windowWidth); return 750 * (px / windowWidth);
} }
function rpx2px(rpx) { function rpx2px(rpx) {
let { windowWidth } = uni.getStorageSync('system_config'); let { windowWidth } = $storage.get('system_config');
windowWidth = (windowWidth > 750) ? 750 : windowWidth; windowWidth = (windowWidth > 750) ? 750 : windowWidth;
return (rpx / 750) * windowWidth; return (rpx / 750) * windowWidth;
} }
function toPage(url, options) { function toPage(url, options, type) {
uni.navigateTo({ if (typeof type === "undefined") {
type = "navigate";
}
let params = {
...{ url: url, }, ...{ url: url, },
...options ...options
}); };
switch (type) {
case "reload":
let pages = getCurrentPages();
currentPage = pages[pages.length - 1];
currentPage.onShow(currentPage.options);
break;
case "back":
uni.navigateBack({ ...{ delta: 1 }, ...options });
break;
case "relaunch":
uni.reLaunch(params);
break;
case "redirect":
uni.redirectTo(params);
break;
case "switch":
uni.switchTab(params);
break;
case "navigate":
default:
uni.navigateTo(params);
break;
}
} }
let toastTimer;
function toast(title, options) { function toast(title, options) {
uni.showToast({ if (typeof options === "undefined") {
...{ title: title, icon: "none" }, options = {};
...options }
}); return new Promise((resolve, reject) => {
if (!options.duration) {
options.duration = 1500;
}
uni.showToast({
...{ title: title, icon: "none" },
...options
});
clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
resolve();
}, options.duration);
})
} }
function formatNumber(num, limit) { function formatNumber(num, limit) {
@ -176,7 +217,7 @@ function formatNumber(num, limit) {
function serviceActions() { function serviceActions() {
uni.showActionSheet({ uni.showActionSheet({
itemList: ['电话客服', '微信客服', '微信客服二'], itemList: ['电话客服', '微信客服'],
success(res) { success(res) {
console.log('选中了第' + (res.tapIndex + 1) + '个按钮'); console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
}, },
@ -186,6 +227,47 @@ function serviceActions() {
}); });
} }
function chooseImage(count) {
return new Promise((resolve, reject) => {
let tempFiles = [];
// #ifdef H5
uni.chooseImage({
count: count,
success(r) {
r.tempFiles.forEach((item, index) => {
tempFiles.push({
path: r.tempFilePaths[index],
size: item.size,
});
});
resolve(tempFiles);
},
fail(e) {
reject(e);
}
});
// #endif
// #ifdef MP-WEIXIN
uni.chooseMedia({
count: count,
mediaType: ["image"],
success(r) {
r.tempFiles.forEach(item => {
tempFiles.push({
path: item.tempFilePath,
size: item.size,
});
});
resolve(tempFiles);
},
fail(e) {
reject(e);
}
});
// #endif
});
}
export default { export default {
time, time,
datetime, datetime,
@ -200,4 +282,5 @@ export default {
toast, toast,
formatNumber, formatNumber,
serviceActions, serviceActions,
chooseImage,
} }

View File

@ -1,60 +1,187 @@
import $store from "@/store/index"
import Vue from "vue"
let prototype = Vue.prototype;
export default { export default {
/** /**
* 获取平台用户信息 * 登录平台
*/ */
platformInfo() { platformLogin() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 获取用户信息 // #ifdef MP-WEIXIN
uni.getUserProfile({ uni.login({
provider: 'weixin', provider: "weixin",
desc: "获取用户信息", success(result) {
success: function (info) { prototype.$request({
console.log(info); api: 'user.openId',
uni.login({ data: {
provider: "weixin", code: result.code
success: (result) => { }
resolve({ }).then((response) => {
code: result.code, this.$storage.set("open_id", response.data.openid);
userInfo: { return resolve(response.data);
avatarUrl: info.userInfo.avatarUrl, }).catch(e => { });
city: info.userInfo.city, }
country: info.userInfo.country,
gender: info.userInfo.gender,
language: info.userInfo.language,
nickName: info.userInfo.nickName,
province: info.userInfo.province
}
// encryptedData: info.encryptedData,
// iv: info.iv,
});
},
fail: e => {
reject(e);
},
});
},
fail: e => {
reject(e);
},
}); });
// #endif
// #ifdef H5
return resolve({
openid: "mobile_000000000000000000"
});
// #endif
}); });
}, },
register() { /**
this.platformInfo().then(platfromUser => { * 初始化用户
console.log(platfromUser); */
}).catch(e => { }); async initUser() {
// openid
let openId = prototype.$storage.get("open_id");
if (!openId) {
await this.platformLogin().then((response) => {
openId = response.openid;
});
}
$store.commit("user/openId", openId);
// token
let token = prototype.$storage.get("user_access_token");
$store.commit('user/token', token);
}, },
login() { /**
uni.navigateTo({ * 发送验证码
url: '/pages/auth/login' */
sendVerificationCode(mobile) {
return new Promise((resolve, reject) => {
if (!prototype.$test.mobile(mobile)) {
return reject('请输入正确的手机号码');
}
prototype.$request({
api: 'user.sendCode',
data: {
username: mobile,
},
}).then((res) => {
if (res.code == 1) {
return resolve();
} else {
return reject(response.msg);
}
}).catch(e => { });
}); });
}, },
getInfo() { /**
* 获取信息
*/
info(refresh) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
resolve({ if (refresh === true) {
id: 123, prototype.$storage.remove('userinfo');
name: '李四' }
}); let cacheUser = prototype.$storage.get('userinfo');
if (cacheUser) {
return resolve(cacheUser);
}
prototype.$request({
api: 'user.info',
}).then(response => {
if (response.code == 1) {
let user = {
id: response.data.id,
avatar: response.data.avatar,
nickname: response.data.user_nickname,
openid: response.data.openid,
mobile: response.data.mobile,
createTime: response.data.create_time,
finishInfo: response.data.worker != null,
};
prototype.$storage.set('userinfo', user);
return resolve(user);
} else {
return reject(response.msg);
}
}).catch(e => { });
});
},
/**
* 用户注册
*/
register(user, verificationCode) {
return new Promise((resolve, reject) => {
if (!prototype.$test.mobile(user.mobile)) {
return reject('请输入正确的手机号码');
}
if (user.password.length < 6 || user.password.length > 16) {
return reject('密码在6至16位字符之间');
}
if (!user.openId) {
return reject('缺少OpenId请重启应用');
}
prototype.$request({
api: 'user.register',
data: {
username: user.mobile,
password: user.password,
openid: user.openId,
verification_code: verificationCode,
types: 2,
}
}).then((response) => {
if (response.code == 1) {
return resolve(response);
} else {
return reject(response.msg);
}
}).catch(e => { });
});
},
/**
* 登录用户
*/
login(user) {
return new Promise((resolve, reject) => {
if (!prototype.$test.mobile(user.mobile)) {
return reject('请输入正确的手机号码');
}
if (user.password.length < 6 || user.password.length > 16) {
return reject('密码在6至16位字符之间');
}
prototype.$request({
api: 'user.login',
data: {
username: user.mobile,
password: user.password,
}
}).then(async response => {
if (response.code == 1) {
prototype.$storage.set('user_access_token', response.data.token);
// 提交token到store
await this.initUser();
return resolve(response);
} else {
return reject(response.msg);
}
}).catch(e => { });
});
},
/**
* 找回密码
*/
resetPassword(data, verificationCode) {
return new Promise((resolve, reject) => {
prototype.$request({
api: "user.resetPassword",
data: {
username: data.username,
password: data.password,
verification_code: verificationCode,
types: 2,
},
}).then(response => {
if (response.code == 1) {
return resolve(response.msg);
}
return reject(response.msg);
}).catch(e => { });
}); });
} }
} }

70
src/core/request.js Normal file
View File

@ -0,0 +1,70 @@
import $store from "@/store/index";
import Vue from "vue"
let prototype = Vue.prototype;
function findApi(name) {
let pos = name.indexOf('.');
if (pos > 0) {
let temp, arr = name.split('.');
for (let i = 0; i < arr.length; i++) {
if (i == 0) {
temp = prototype.$apis[arr[i]] || {};
} else {
temp = temp[arr[i]] || {};
}
}
return temp;
}
return name;
}
const request = async (args) => {
const rule = findApi(args.api || '');
if (JSON.stringify(rule) === "{}") {
throw "找不到API" + args.api;
}
const query = (args.query) ? '?' + args.query : '';
if (typeof rule.auth !== "undefined" && rule.auth === true && !$store.state.user.token) {
$store.commit("user/showLoginModal", true);
throw "登录态失效";
}
(rule.showLoading) && uni.showLoading({
title: "加载中"
});
const contentType = (args.contentType) ? args.contentType : 'application/json';
const [error, response] = await uni.request({
url: prototype.$config.root + rule.url + query,
method: rule.method || 'post',
data: args.data,
header: {
"XX-Wxapp-AppId": prototype.$config.appId,
'XX-Token': $store.state.user.token,
'XX-Device-Type': 'wxapp',
'X-Requested-With': 'XMLHttpRequest',
'content-type': contentType,
}
});
(rule.showLoading) && uni.hideLoading();
if (error) {
prototype.$utils.toast('网络错误');
throw "网络错误";
}
if (response.data.code == 10001) {
$store.dispatch("user/logout");
$store.commit("user/showLoginModal", true);
throw "登录态失效";
}
return Promise.resolve(response.data);
};
export default request

17
src/core/storage.js Normal file
View File

@ -0,0 +1,17 @@
import config from '@/core/config';
export default {
prefix: config.storagePrefix,
set(key, value) {
uni.setStorageSync(this.prefix + key, value);
},
get(key) {
return uni.getStorageSync(this.prefix + key);
},
remove(key) {
uni.removeStorageSync(this.prefix + key);
},
clear(key, value) {
uni.clearStorageSync();
}
}

View File

@ -2,9 +2,11 @@ import Vue from 'vue'
import App from './App' import App from './App'
import store from "./store/index" import store from "./store/index"
import request from './core/libs/request' import storage from './core/storage'
import request from './core/request'
import test from './core/libs/test'
import event from './core/libs/event' import event from './core/libs/event'
import utils from './core/utils' import utils from './core/libs/utils'
import config from './core/config' import config from './core/config'
import apis from './core/apis' import apis from './core/apis'
import models from './core/models' import models from './core/models'
@ -12,7 +14,9 @@ import './static/iconfont/iconfont.css'
Vue.use({ Vue.use({
install(Vue, options) { install(Vue, options) {
Vue.prototype.$storage = storage
Vue.prototype.$request = request Vue.prototype.$request = request
Vue.prototype.$test = test
Vue.prototype.$event = event Vue.prototype.$event = event
Vue.prototype.$utils = utils Vue.prototype.$utils = utils
Vue.prototype.$config = config Vue.prototype.$config = config

View File

@ -13,12 +13,11 @@
"autoclose": true, "autoclose": true,
"delay": 0 "delay": 0
}, },
"modules": { /* */ "modules": { /* */},
},
"distribute": { /* */ "distribute": { /* */
"android": { /* android */ "android": { /* android */
"permissions": ["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>", "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
@ -42,56 +41,50 @@
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
] ]
}, },
"ios": { /* ios */ "ios": { /* ios */},
"sdkConfigs": { /* SDK */}
},
"sdkConfigs": { /* SDK */
}
} }
}, },
"quickapp": { /* */ "quickapp": { /* */},
},
"mp-weixin": { /* */ "mp-weixin": { /* */
"appid": "wx239055764f21ba10", "appid": "wx2401c65b68a6c9b5",
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,
"es6" : true, "es6": true,
"minified" : true, "minified": true,
"postcss" : true "postcss": true
}, },
"usingComponents": true, "usingComponents": true,
"permission" : { "permission": {
"scope.userLocation" : { "scope.userLocation": {
"desc" : "请求获取您的位置信息" "desc": "请求获取您的位置信息"
} }
}, },
"requiredPrivateInfos": [ "requiredPrivateInfos": [
"chooseAddress", "chooseAddress",
"chooseLocation" "chooseLocation"
] ]
}, },
"mp-alipay" : { "mp-alipay": {
"usingComponents" : true "usingComponents": true
}, },
"mp-baidu" : { "mp-baidu": {
"usingComponents" : true "usingComponents": true
}, },
"mp-toutiao" : { "mp-toutiao": {
"usingComponents" : true "usingComponents": true
}, },
"mp-qq" : { "mp-qq": {
"usingComponents" : true "usingComponents": true
}, },
"h5": { "h5": {
"sdkConfigs": { "sdkConfigs": {
"maps" : { "maps": {
"qqmap" : { "qqmap": {
// https://lbs.qq.com/dev/console/key/manage // https://lbs.qq.com/dev/console/key/manage
"key" : "PB3BZ-PB76J-HRSF2-KJ2QJ-CI2Z2-5TFTJ" "key": "PB3BZ-PB76J-HRSF2-KJ2QJ-CI2Z2-5TFTJ"
} }
} }
} }
} }
} }

View File

@ -12,6 +12,12 @@
"navigationBarTitleText": "登录" "navigationBarTitleText": "登录"
} }
}, },
{
"path": "pages/auth/find-password",
"style": {
"navigationBarTitleText": "找回密码"
}
},
{ {
"path": "pages/member/service-info", "path": "pages/member/service-info",
"style": { "style": {

View File

@ -7,7 +7,7 @@
<view class="immerse-main" :style="{ paddingTop: safePt + utils.rpx2px(20) + 'px' }"> <view class="immerse-main" :style="{ paddingTop: safePt + utils.rpx2px(20) + 'px' }">
<view class="head-title"> <view class="head-title">
<text class="title">熊熊建材安装<text class="color">师傅版</text></text> <text class="title">熊熊建材安装<text class="color">师傅版</text></text>
<text class="desc">将好师傅交给用户让好服务走进万家 </text> <text class="desc">将好师傅交给用户让好服务走进万家</text>
</view> </view>
<view class="section"> <view class="section">
<view class="select-group"> <view class="select-group">
@ -63,7 +63,7 @@
<input <input
class="input" class="input"
type="number" type="number"
v-model="mobile" v-model="verificationCode"
placeholder="请输入验证码" placeholder="请输入验证码"
placeholder-class="placeholder-style-3" placeholder-class="placeholder-style-3"
/> />
@ -102,6 +102,7 @@
<script> <script>
import AppLayout from "@/components/layout/layout"; import AppLayout from "@/components/layout/layout";
import AppAgreement from "@/components/auth/agreement"; import AppAgreement from "@/components/auth/agreement";
import { mapState } from "vuex";
export default { export default {
name: "auth", name: "auth",
data() { data() {
@ -115,6 +116,7 @@ export default {
tabIndex: 0, tabIndex: 0,
mobile: "", mobile: "",
password: "", password: "",
verificationCode: "",
isAgree: false, isAgree: false,
}; };
}, },
@ -122,43 +124,113 @@ export default {
AppLayout, AppLayout,
AppAgreement, AppAgreement,
}, },
computed: {
...mapState({
openId: (state) => state.user.openId,
}),
},
onLoad() {}, onLoad() {},
onShow() {}, onShow() {},
onReady() {}, onReady() {},
onReachBottom() {}, onReachBottom() {},
onPullDownRefresh() {}, onPullDownRefresh() {},
methods: { methods: {
/**
* 忘记密码
*/
forgetPassword() { forgetPassword() {
this.$utils.toast("正在开发中"); this.$utils.toPage("/pages/auth/find-password");
}, },
/**
* 获取验证码
*/
getVerifyCode() { getVerifyCode() {
if (this.canUse) { if (this.canUse) {
if (true) { this.$models.user
this.parseTime(10); .sendVerificationCode(this.mobile)
} .then((response) => {
this.parseTime(60);
})
.catch((e) => {
this.$utils.toast(e);
});
} else { } else {
this.$utils.toast("请稍后再试"); this.$utils.toast("请稍后再试");
} }
}, },
/**
* 倒计时
*/
parseTime(sec) { parseTime(sec) {
const that = this; const that = this;
this.canUse = false; this.canUse = false;
this.sec = sec; this.sec = sec;
that.timeTask = setInterval(() => { clearInterval(this.timeTask);
this.timeTask = setInterval(() => {
that.sec -= 1; that.sec -= 1;
if (that.sec <= 0) { if (that.sec <= 0) {
that.canUse = true; that.canUse = true;
that.sec = 0; that.sec = 0;
clearInterval(that.timeTask);
} }
}, 1000); }, 1000);
}, },
login() {}, /**
* 登录
*/
login() {
this.$models.user
.login({
mobile: this.mobile,
password: this.password,
})
.then((response) => {
this.$store.dispatch("user/info");
this.$utils.toPage(
"",
{
complete() {
let pages = getCurrentPages();
let refer = pages[pages.length - 2];
if (typeof refer !== "undefined") {
if (typeof refer.initPage !== "undefined") {
refer.initPage(refer.options);
}
}
},
},
"back"
);
})
.catch((e) => {
this.$utils.toast(e);
});
},
/**
* 注册
*/
register() { register() {
const that = this;
if (!this.isAgree) { if (!this.isAgree) {
this.$utils.toast("请先阅读并同意《服务协议》《隐私政策》"); this.$utils.toast("请先阅读并同意《服务协议》《隐私政策》");
return; return;
} }
this.$models.user
.register(
{
mobile: this.mobile,
password: this.password,
openId: this.openId,
},
this.verificationCode
)
.then((response) => {
this.$utils.toast(response.msg).then(() => {
this.tabIndex = 0;
});
})
.catch((e) => {
this.$utils.toast(e);
});
}, },
}, },
}; };
@ -206,6 +278,7 @@ export default {
margin-top: 45rpx; margin-top: 45rpx;
border-bottom: 2rpx solid #d2d1d1; border-bottom: 2rpx solid #d2d1d1;
.input { .input {
position: relative;
width: 100%; width: 100%;
font-size: 32rpx; font-size: 32rpx;
color: #666666; color: #666666;
@ -235,6 +308,7 @@ export default {
} }
} }
.get-code { .get-code {
z-index: 10;
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;

View File

@ -0,0 +1,148 @@
<template>
<app-layout title="找回密码">
<view class="common-form-container">
<view class="input-item">
<view class="title-box">
<text>手机号</text>
</view>
<view class="input-box">
<input class="input" v-model="mobile" placeholder="请输入手机号码" placeholder-class="placeholder-style-3" />
</view>
</view>
<view class="input-item">
<view class="title-box">
<text>验证码</text>
</view>
<view class="input-box">
<input
class="input"
v-model="verificationCode"
placeholder="请输入验证码"
placeholder-class="placeholder-style-3"
/>
<view class="get-code" @click="getVerifyCode">
<text class="text active" v-if="canUse">获取验证码</text>
<text class="text" v-else>{{ sec }}s后重新获取</text>
</view>
</view>
</view>
<view class="input-item">
<view class="title-box">
<text>新密码</text>
</view>
<view class="input-box">
<input class="input" v-model="password" placeholder="请输入新密码" placeholder-class="placeholder-style-3" />
</view>
</view>
</view>
<view class="common-save-form-btn">
<view class="btn" @click="submit">立即找回</view>
</view>
</app-layout>
</template>
<script>
import AppLayout from "@/components/layout/layout";
export default {
name: "member-password",
data() {
return {
timeTask: null,
canUse: true,
sec: 0,
mobile: "",
password: "",
verificationCode: "",
};
},
components: {
AppLayout,
},
onLoad() {},
onShow() {},
onReady() {},
onReachBottom() {},
onPullDownRefresh() {},
methods: {
/**
* 获取验证码
*/
getVerifyCode() {
if (this.canUse) {
this.$models.user
.sendVerificationCode(this.mobile)
.then((response) => {
this.parseTime(60);
})
.catch((e) => {
this.$utils.toast(e);
});
} else {
this.$utils.toast("请稍后再试");
}
},
/**
* 倒计时
*/
parseTime(sec) {
const that = this;
this.canUse = false;
this.sec = sec;
clearInterval(this.timeTask);
this.timeTask = setInterval(() => {
that.sec -= 1;
if (that.sec <= 0) {
that.canUse = true;
that.sec = 0;
}
}, 1000);
},
/**
* 找回密码
*/
submit() {
this.$models.user
.resetPassword(
{
username: this.mobile,
password: this.password,
},
this.verificationCode
)
.then((message) => {
this.$utils.toast(message).then(() => {
this.$utils.toPage("/pages/auth/auth");
});
})
.catch((e) => {
this.$utils.toast(e);
});
},
},
};
</script>
<style lang="less" scoped>
.common-form-container {
.input-item {
position: relative;
}
.get-code {
position: absolute;
top: 0;
right: 0;
display: inline-block;
padding: 24rpx 0;
.text {
font-size: 28rpx;
color: #999999;
}
.text.active {
color: #ffa800;
}
}
.title-box {
font-weight: normal;
}
}
</style>

View File

@ -6,30 +6,40 @@
</view> </view>
<view class="immerse-main" :style="{ paddingTop: safePt + utils.rpx2px(20) + 'px' }"> <view class="immerse-main" :style="{ paddingTop: safePt + utils.rpx2px(20) + 'px' }">
<view class="head"> <view class="head">
<view class="headimg"> <block v-if="isLogin">
<image class="image" :src="userInfo.headimg" mode="aspectFill" /> <view class="headimg">
</view> <image class="image" :src="userInfo.avatar" mode="aspectFill" />
<view class="detail">
<view class="name">
<text>{{ userInfo.username }}</text>
<text class="type" :style="{ color: models.worker.getWorkerTypeTextColor(userInfo.type) }">{{
models.worker.getWorkerTypeText(userInfo.type)
}}</text>
</view> </view>
<view class="line id">ID{{ userInfo.id }}</view> <view class="detail">
<view class="line">注册时间{{ userInfo.registerAt }}</view> <view class="name">
</view> <text>{{ userInfo.username }}</text>
<view class="accept-switch"> <text
<widget-switch class="type"
v-model="acceptOrderState" :style="{ color: models.worker.getWorkerTypeTextColor(userInfo.workerType) }"
:color="['#ffffff', '#ffffff']" >{{ models.worker.getWorkerTypeText(userInfo.workerType) }}</text
:size="54" >
:open="acceptOrderState" </view>
/> <view class="line id">ID{{ userInfo.id }}</view>
<text class="current-state">{{ acceptOrderState ? "正在" : "暂停" }}接单</text> <view class="line">注册时间{{ userInfo.createTime }}</view>
</view> </view>
<view class="accept-switch">
<widget-switch
v-model="acceptOrderState"
:color="['#ffffff', '#ffffff']"
:size="54"
:open="acceptOrderState"
/>
<text class="current-state">{{ acceptOrderState ? "正在" : "暂停" }}接单</text>
</view>
</block>
<block v-else>
<view class="login-tips" @click="utils.toPage('/pages/auth/auth')">
<view class="title"> 立即登录 </view>
<view class="desc">需要登录后操作</view>
</view>
</block>
</view> </view>
<view class="order-desc"> <view v-if="isLogin" class="order-desc">
<view class="service-data"> <view class="service-data">
<view class="section-text"> <view class="section-text">
<text>服务</text> <text>服务</text>
@ -58,7 +68,7 @@
</view> </view>
</view> </view>
<view class="common-form-widget-group"> <view class="common-form-widget-group">
<view class="widget-item" @click="utils.toPage('/pages/member/cash-withdraw')"> <view class="widget-item" @click="toPage('/pages/member/cash-withdraw')">
<text class="title limit-line clamp-1">我要提现</text> <text class="title limit-line clamp-1">我要提现</text>
<text class="iconfont icon-jinru"></text> <text class="iconfont icon-jinru"></text>
</view> </view>
@ -76,7 +86,7 @@
</view> </view>
</view> </view>
<view class="common-form-widget-group"> <view class="common-form-widget-group">
<view class="widget-item" @click="utils.toPage('/pages/member/service-info')"> <view class="widget-item" @click="toPage('/pages/member/service-info')">
<text class="title limit-line clamp-1">设置服务信息</text> <text class="title limit-line clamp-1">设置服务信息</text>
<text class="iconfont icon-jinru"></text> <text class="iconfont icon-jinru"></text>
</view> </view>
@ -84,11 +94,11 @@
<text class="title limit-line clamp-1">我的评价</text> <text class="title limit-line clamp-1">我的评价</text>
<text class="iconfont icon-jinru"></text> <text class="iconfont icon-jinru"></text>
</view> </view>
<view class="widget-item"> <view class="widget-item" @click="utils.serviceActions()">
<text class="title limit-line clamp-1">在线客服</text> <text class="title limit-line clamp-1">在线客服</text>
<text class="iconfont icon-jinru"></text> <text class="iconfont icon-jinru"></text>
</view> </view>
<view class="widget-item" @click="utils.toPage('/pages/member/setting')"> <view class="widget-item" @click="toPage('/pages/member/setting')">
<text class="title limit-line clamp-1">设置</text> <text class="title limit-line clamp-1">设置</text>
<text class="iconfont icon-jinru"></text> <text class="iconfont icon-jinru"></text>
</view> </view>
@ -101,6 +111,7 @@
<script> <script>
import AppLayout from "@/components/layout/layout"; import AppLayout from "@/components/layout/layout";
import WidgetSwitch from "@/components/widgets/switch"; import WidgetSwitch from "@/components/widgets/switch";
import { mapGetters, mapState } from "vuex";
export default { export default {
name: "member", name: "member",
data() { data() {
@ -109,13 +120,6 @@ export default {
models: this.$models, models: this.$models,
safePt: 0, safePt: 0,
backgroundImage: require("@/static/temp/1.png"), backgroundImage: require("@/static/temp/1.png"),
userInfo: {
headimg: require("@/static/temp/member/2.png"),
username: "李师傅",
id: "212121212",
registerAt: "2022-11-1",
type: 2,
},
acceptOrderState: false, acceptOrderState: false,
}; };
}, },
@ -123,12 +127,32 @@ export default {
AppLayout, AppLayout,
WidgetSwitch, WidgetSwitch,
}, },
computed: {
...mapGetters({
isLogin: "user/isLogin",
finishInfo: "user/finishInfo",
}),
...mapState({
userInfo: (state) => state.user.info,
}),
},
onLoad() {}, onLoad() {},
onShow() {}, onShow() {
if (this.isLogin && !this.finishInfo) {
this.$utils.toPage("/pages/member/service-info");
}
},
onReady() {}, onReady() {},
onReachBottom() {}, onReachBottom() {},
onPullDownRefresh() {}, onPullDownRefresh() {},
methods: {}, methods: {
toPage(url) {
if (!this.isLogin) {
return this.$store.commit("user/showLoginModal", true);
}
this.$utils.toPage(url);
},
},
}; };
</script> </script>
@ -139,6 +163,20 @@ export default {
.member-container { .member-container {
width: 100%; width: 100%;
} }
.login-tips {
width: 100%;
text-align: center;
color: #ffffff;
margin-bottom: 50rpx;
.title {
font-size: 40rpx;
font-weight: bold;
}
.desc {
margin-top: 20rpx;
font-size: 32rpx;
}
}
.head { .head {
width: 100%; width: 100%;
display: flex; display: flex;

View File

@ -1,34 +1,7 @@
export default { export default {
namespaced: true, namespaced: true,
state: { state: {},
config: {}, getters: {},
}, mutations: {},
getters: { actions: {}
config(state) {
return state.config;
},
},
mutations: {
setConfig(state, data) {
state.config = { ...state.config, ...data };
},
},
actions: {
initConfig(context) {
let config = uni.getStorageSync('system_config');
if (!config) {
const { windowWidth, windowHeight, statusBarHeight, safeAreaInsets } = uni.getSystemInfoSync();
// #ifndef H5
const { height, top } = uni.getMenuButtonBoundingClientRect();
const headerHeight = height + ((top - statusBarHeight) * 2);
// #endif
// #ifdef H5
const headerHeight = 40; // 乘2再使用rpx2px转px使用
// #endif
config = { windowWidth, windowHeight, statusBarHeight, headerHeight, safeAreaInsets };
uni.setStorageSync('system_config', config);
}
context.commit('setConfig', config);
}
}
} }

View File

@ -1,35 +1,50 @@
import user from '@/core/models/user' import user from "@/core/models/user";
export default { export default {
namespaced: true, namespaced: true,
state: { state: {
showLoginModal: false, showLoginModal: false,
userInfo: null, openId: "",
token: "",
info: {
id: 0,
avatar: "",
nickname: "",
openid: "",
mobile: "",
createTime: 0,
finishInfo: false,
},
}, },
getters: { getters: {
showLoginModal(state) { isLogin(state) {
return state.showLoginModal; return state.token.length > 0;
},
userInfo(state) {
return state.userInfo;
}, },
finishInfo(state) {
return state.info.finishInfo;
}
}, },
mutations: { mutations: {
showLoginModal(state, data) { showLoginModal(state, data) {
state.showLoginModal = data; state.showLoginModal = data;
}, },
userInfo(state, data) { openId(state, data) {
state.userInfo = data; state.openId = data;
},
token(state, data) {
state.token = data;
},
info(state, data) {
state.info = data;
} }
}, },
actions: { actions: {
logout(context) { info(context) {
context.commit('userInfo', null); user.info().then(info => {
}, context.commit('info', info);
userInfo(context) {
user.getInfo().then(info => {
context.commit('userInfo', info);
}); });
} },
logout(context) {
context.commit('info', null);
},
} }
} }