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

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>
export default {
onLaunch: function () {
this.$store.dispatch("system/initConfig");
globalData: {
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 () {},
onHide: function () {},
@ -160,4 +178,41 @@ export default {
justify-content: space-between;
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>

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

View File

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

View File

@ -1,7 +1,24 @@
const apis = {
member: {
info: "/member/info"
}
user: {
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

View File

@ -1,6 +1,8 @@
const config = {
name: "熊熊安装",
root: "http://127.0.0.1/api.php"
storagePrefix: "worker_",
appId: "wx2401c65b68a6c9b5",
root: "http://xiongxiong.vipwjf.com/api.php"
}
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() {
return parseInt(Math.round(new Date() / 1000));
};
@ -143,29 +145,68 @@ function debounce(func, wait = 500, immediate = false) {
}
function px2rpx(px) {
let { windowWidth } = uni.getStorageSync('system_config');
let { windowWidth } = $storage.get('system_config');
windowWidth = (windowWidth > 750) ? 750 : windowWidth;
return 750 * (px / windowWidth);
}
function rpx2px(rpx) {
let { windowWidth } = uni.getStorageSync('system_config');
let { windowWidth } = $storage.get('system_config');
windowWidth = (windowWidth > 750) ? 750 : windowWidth;
return (rpx / 750) * windowWidth;
}
function toPage(url, options) {
uni.navigateTo({
function toPage(url, options, type) {
if (typeof type === "undefined") {
type = "navigate";
}
let params = {
...{ url: url, },
...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) {
if (typeof options === "undefined") {
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) {
@ -176,7 +217,7 @@ function formatNumber(num, limit) {
function serviceActions() {
uni.showActionSheet({
itemList: ['电话客服', '微信客服', '微信客服二'],
itemList: ['电话客服', '微信客服'],
success(res) {
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 {
time,
datetime,
@ -200,4 +282,5 @@ export default {
toast,
formatNumber,
serviceActions,
chooseImage,
}

View File

@ -1,60 +1,187 @@
import $store from "@/store/index"
import Vue from "vue"
let prototype = Vue.prototype;
export default {
/**
* 获取平台用户信息
* 登录平台
*/
platformInfo() {
platformLogin() {
return new Promise((resolve, reject) => {
// 获取用户信息
uni.getUserProfile({
provider: 'weixin',
desc: "获取用户信息",
success: function (info) {
console.log(info);
// #ifdef MP-WEIXIN
uni.login({
provider: "weixin",
success: (result) => {
resolve({
code: result.code,
userInfo: {
avatarUrl: info.userInfo.avatarUrl,
city: info.userInfo.city,
country: info.userInfo.country,
gender: info.userInfo.gender,
language: info.userInfo.language,
nickName: info.userInfo.nickName,
province: info.userInfo.province
success(result) {
prototype.$request({
api: 'user.openId',
data: {
code: result.code
}
// encryptedData: info.encryptedData,
// iv: info.iv,
});
},
fail: e => {
reject(e);
},
});
},
fail: e => {
reject(e);
},
});
});
},
register() {
this.platformInfo().then(platfromUser => {
console.log(platfromUser);
}).then((response) => {
this.$storage.set("open_id", response.data.openid);
return resolve(response.data);
}).catch(e => { });
},
login() {
uni.navigateTo({
url: '/pages/auth/login'
}
});
// #endif
// #ifdef H5
return resolve({
openid: "mobile_000000000000000000"
});
// #endif
});
},
getInfo() {
/**
* 初始化用户
*/
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);
},
/**
* 发送验证码
*/
sendVerificationCode(mobile) {
return new Promise((resolve, reject) => {
resolve({
id: 123,
name: '李四'
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 => { });
});
},
/**
* 获取信息
*/
info(refresh) {
return new Promise((resolve, reject) => {
if (refresh === true) {
prototype.$storage.remove('userinfo');
}
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 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 utils from './core/utils'
import utils from './core/libs/utils'
import config from './core/config'
import apis from './core/apis'
import models from './core/models'
@ -12,7 +14,9 @@ import './static/iconfont/iconfont.css'
Vue.use({
install(Vue, options) {
Vue.prototype.$storage = storage
Vue.prototype.$request = request
Vue.prototype.$test = test
Vue.prototype.$event = event
Vue.prototype.$utils = utils
Vue.prototype.$config = config

View File

@ -13,12 +13,11 @@
"autoclose": true,
"delay": 0
},
"modules": { /* */
},
"modules": { /* */},
"distribute": { /* */
"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.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
@ -42,29 +41,23 @@
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios": { /* ios */
},
"sdkConfigs": { /* SDK */
}
"ios": { /* ios */},
"sdkConfigs": { /* SDK */}
}
},
"quickapp": { /* */
},
"quickapp": { /* */},
"mp-weixin": { /* */
"appid": "wx239055764f21ba10",
"appid": "wx2401c65b68a6c9b5",
"setting": {
"urlCheck": false,
"es6" : true,
"minified" : true,
"postcss" : true
"es6": true,
"minified": true,
"postcss": true
},
"usingComponents": true,
"permission" : {
"scope.userLocation" : {
"desc" : "请求获取您的位置信息"
"permission": {
"scope.userLocation": {
"desc": "请求获取您的位置信息"
}
},
"requiredPrivateInfos": [
@ -72,24 +65,24 @@
"chooseLocation"
]
},
"mp-alipay" : {
"usingComponents" : true
"mp-alipay": {
"usingComponents": true
},
"mp-baidu" : {
"usingComponents" : true
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao" : {
"usingComponents" : true
"mp-toutiao": {
"usingComponents": true
},
"mp-qq" : {
"usingComponents" : true
"mp-qq": {
"usingComponents": true
},
"h5": {
"sdkConfigs": {
"maps" : {
"qqmap" : {
"maps": {
"qqmap": {
// 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": "登录"
}
},
{
"path": "pages/auth/find-password",
"style": {
"navigationBarTitleText": "找回密码"
}
},
{
"path": "pages/member/service-info",
"style": {

View File

@ -7,7 +7,7 @@
<view class="immerse-main" :style="{ paddingTop: safePt + utils.rpx2px(20) + 'px' }">
<view class="head-title">
<text class="title">熊熊建材安装<text class="color">师傅版</text></text>
<text class="desc">将好师傅交给用户让好服务走进万家 </text>
<text class="desc">将好师傅交给用户让好服务走进万家</text>
</view>
<view class="section">
<view class="select-group">
@ -63,7 +63,7 @@
<input
class="input"
type="number"
v-model="mobile"
v-model="verificationCode"
placeholder="请输入验证码"
placeholder-class="placeholder-style-3"
/>
@ -102,6 +102,7 @@
<script>
import AppLayout from "@/components/layout/layout";
import AppAgreement from "@/components/auth/agreement";
import { mapState } from "vuex";
export default {
name: "auth",
data() {
@ -115,6 +116,7 @@ export default {
tabIndex: 0,
mobile: "",
password: "",
verificationCode: "",
isAgree: false,
};
},
@ -122,43 +124,113 @@ export default {
AppLayout,
AppAgreement,
},
computed: {
...mapState({
openId: (state) => state.user.openId,
}),
},
onLoad() {},
onShow() {},
onReady() {},
onReachBottom() {},
onPullDownRefresh() {},
methods: {
/**
* 忘记密码
*/
forgetPassword() {
this.$utils.toast("正在开发中");
this.$utils.toPage("/pages/auth/find-password");
},
/**
* 获取验证码
*/
getVerifyCode() {
if (this.canUse) {
if (true) {
this.parseTime(10);
}
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;
that.timeTask = setInterval(() => {
clearInterval(this.timeTask);
this.timeTask = setInterval(() => {
that.sec -= 1;
if (that.sec <= 0) {
that.canUse = true;
that.sec = 0;
clearInterval(that.timeTask);
}
}, 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() {
const that = this;
if (!this.isAgree) {
this.$utils.toast("请先阅读并同意《服务协议》《隐私政策》");
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;
border-bottom: 2rpx solid #d2d1d1;
.input {
position: relative;
width: 100%;
font-size: 32rpx;
color: #666666;
@ -235,6 +308,7 @@ export default {
}
}
.get-code {
z-index: 10;
position: absolute;
top: 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,18 +6,21 @@
</view>
<view class="immerse-main" :style="{ paddingTop: safePt + utils.rpx2px(20) + 'px' }">
<view class="head">
<block v-if="isLogin">
<view class="headimg">
<image class="image" :src="userInfo.headimg" mode="aspectFill" />
<image class="image" :src="userInfo.avatar" mode="aspectFill" />
</view>
<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>
<text
class="type"
:style="{ color: models.worker.getWorkerTypeTextColor(userInfo.workerType) }"
>{{ models.worker.getWorkerTypeText(userInfo.workerType) }}</text
>
</view>
<view class="line id">ID{{ userInfo.id }}</view>
<view class="line">注册时间{{ userInfo.registerAt }}</view>
<view class="line">注册时间{{ userInfo.createTime }}</view>
</view>
<view class="accept-switch">
<widget-switch
@ -28,8 +31,15 @@
/>
<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>
<view class="order-desc">
</block>
</view>
<view v-if="isLogin" class="order-desc">
<view class="service-data">
<view class="section-text">
<text>服务</text>
@ -58,7 +68,7 @@
</view>
</view>
<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="iconfont icon-jinru"></text>
</view>
@ -76,7 +86,7 @@
</view>
</view>
<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="iconfont icon-jinru"></text>
</view>
@ -84,11 +94,11 @@
<text class="title limit-line clamp-1">我的评价</text>
<text class="iconfont icon-jinru"></text>
</view>
<view class="widget-item">
<view class="widget-item" @click="utils.serviceActions()">
<text class="title limit-line clamp-1">在线客服</text>
<text class="iconfont icon-jinru"></text>
</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="iconfont icon-jinru"></text>
</view>
@ -101,6 +111,7 @@
<script>
import AppLayout from "@/components/layout/layout";
import WidgetSwitch from "@/components/widgets/switch";
import { mapGetters, mapState } from "vuex";
export default {
name: "member",
data() {
@ -109,13 +120,6 @@ export default {
models: this.$models,
safePt: 0,
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,
};
},
@ -123,12 +127,32 @@ export default {
AppLayout,
WidgetSwitch,
},
computed: {
...mapGetters({
isLogin: "user/isLogin",
finishInfo: "user/finishInfo",
}),
...mapState({
userInfo: (state) => state.user.info,
}),
},
onLoad() {},
onShow() {},
onShow() {
if (this.isLogin && !this.finishInfo) {
this.$utils.toPage("/pages/member/service-info");
}
},
onReady() {},
onReachBottom() {},
onPullDownRefresh() {},
methods: {},
methods: {
toPage(url) {
if (!this.isLogin) {
return this.$store.commit("user/showLoginModal", true);
}
this.$utils.toPage(url);
},
},
};
</script>
@ -139,6 +163,20 @@ export default {
.member-container {
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 {
width: 100%;
display: flex;

View File

@ -1,34 +1,7 @@
export default {
namespaced: true,
state: {
config: {},
},
getters: {
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);
}
}
state: {},
getters: {},
mutations: {},
actions: {}
}

View File

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