Browse Source

feat: 添加登录,修改密码页面

develop
song 4 years ago
parent
commit
8d53e63934
  1. 3
      CHANGELOG.md
  2. BIN
      public/img/avatar.jpg
  3. 3
      src/apis/tall.js
  4. 4
      src/common/styles/tailwind.scss
  5. 25
      src/components/Projects/Projects.vue
  6. 149
      src/components/change-password/change-password.vue
  7. 143
      src/components/login/login.vue
  8. 8
      src/pages.json
  9. 9
      src/pages/index/index.vue
  10. 27
      src/pages/login/login.vue
  11. 17
      src/pages/right-window/right-window.vue
  12. 15
      src/pages/top-window/top-window.vue
  13. 9
      src/store/user/mutations.js
  14. 1
      src/store/user/state.js

3
CHANGELOG.md

@ -1,4 +1,4 @@
# 0.1.0 (2021-10-19)
# 0.1.0 (2021-10-20)
### 🌟 新功能
范围|描述|commitId
@ -51,6 +51,7 @@
- | 添加 环境变量,动态控制webview project的path | 8a40481
- | 添加子任务插件 子项目插件 | 7bda7e2
- | 添加时间轴上下滚动 | 2b81bbc
- | 添加顶部导航栏和详情页 | 2a63485
- | 添加项目排序 | a0b491b
- | 点击日历日期查询项目列表 | c458385
- | 登录提示是否合并账号 | 6a9b054

BIN
public/img/avatar.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

3
src/apis/tall.js

@ -36,6 +36,9 @@ const install = (Vue, vm) => {
// 修改用户信息
vm.$u.api.updateUserInfo = params => vm.$u.http.post(`${tall}/users/userInfo`, params);
// 通过账号密码修改密码
vm.$u.api.changePasswordByAccount = params => vm.$u.http.post(`${tall}/users/password/account`, params);
// 获取项目列表
vm.$u.api.getProjects = (startTime, endTime) => vm.$u.post(`${tall}/project/query`, { startTime, endTime });
// 查询日历是否有小红点

4
src/common/styles/tailwind.scss

@ -2275,6 +2275,10 @@
flex-grow: 1;
}
.object-center {
object-position: center;
}
@keyframes spin {
to {
transform: rotate(360deg);

25
src/components/Projects/Projects.vue

@ -6,6 +6,7 @@
<script>
import PrettyExchange from '../PrettyExchange/PrettyExchange.vue';
import { mapState, mapGetters, mapMutations } from 'vuex';
export default {
components: { PrettyExchange },
@ -13,7 +14,15 @@ export default {
return {};
},
computed: {
...mapGetters('user', ['userId']),
...mapState('project', ['projects']),
},
methods: {
...mapMutations('project', ['setProject']),
...mapMutations('user', ['setFirstInter']),
change(options) {
if (options instanceof Array) {
let projectIdList = [];
@ -60,6 +69,22 @@ export default {
}
this.$emit('getProjects');
},
//
openProject() {
this.setFirstInter(false);
if (!this.projects.length) return;
this.setProject(this.projects[0]);
const { name, id, url } = this.projects[0];
url && (uni.$t.domain = url);
this.$u.route('pages/project-webview/project-webview', {
u: this.userId,
p: id,
pname: name,
url: encodeURIComponent(url),
});
},
},
};
</script>

149
src/components/change-password/change-password.vue

@ -0,0 +1,149 @@
<template>
<view class="wrap flex justify-center items-center">
<view class="wrap-con">
<h1 class="text-3xl text-center mb-10">修改密码</h1>
<u-form :model="form" ref="uForm" :errorType="errorType">
<!-- 手机号 -->
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" prop="account" label-width="160" class="bg-white">
<u-input type="text" placeholder="账户" :border="border" v-model="form.account" />
</u-form-item>
<view class="mt-1 text-sm text-red-500" v-if="showAccountTips">{{ accountTips }}</view>
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" prop="passwordOld" label-width="160" class="bg-white mt-6">
<u-input type="password" placeholder="旧密码" :border="border" v-model="form.passwordOld" />
</u-form-item>
<view class="mt-1 text-sm text-red-500" v-if="showPasswordOldTips">{{ passwordOldTips }}</view>
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" prop="passwordNew" label-width="160" class="bg-white mt-6">
<u-input type="password" placeholder="新密码" :border="border" v-model="form.passwordNew" />
</u-form-item>
<view class="mt-1 text-sm text-red-500" v-if="showPasswordNewTips">{{ passwordNewTips }}</view>
</u-form>
<view class="flex justify-end my-8 text-sm">
<text class="text-blue cursor-pointer" @click="$emit('changeShow')">返回登录</text>
</view>
<u-button @click="submit" type="primary" class="btn">确认修改</u-button>
</view>
</view>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
data() {
return {
border: true,
form: {
account: '', //
passwordOld: '', //
passwordNew: '', //
},
accountTips: '',
passwordOldTips: '',
passwordNewTips: '',
showAccountTips: false,
showPasswordOldTips: false,
showPasswordNewTips: false,
checked: false,
errorType: ['message'],
};
},
methods: {
...mapMutations('user', ['setToken', 'setUser', 'setFirstInter']),
async submit() {
//
if (this.verifyAccount() && this.verifyPasswordOld() && this.verifyPasswordNew()) {
try {
await this.$u.api.changePasswordByAccount(this.form);
this.$t.ui.showToast('密码修改成功, 即将返回登录');
setTimeout(() => this.$emit('changeShow'), 2000);
} catch (error) {
console.error('error: ', error);
this.$t.ui.showToast(error.msg || '密码修改失败');
}
}
},
//
verifyAccount() {
if (!this.form.account) {
this.showAccountTips = true;
this.accountTips = '请输入账号';
return false;
} else {
this.showAccountTips = false;
return true;
}
},
//
verifyPasswordOld() {
if (!this.form.passwordOld) {
this.showPasswordOldTips = true;
this.passwordOldTips = '请输入旧密码';
return false;
}
const reg = /^[a-zA-Z0-9._-]{6,20}$/;
if (!reg.test(this.form.passwordOld)) {
this.passwordOldTips = '请输入6-20位字母、数字、汉字或字符"_ - ."';
return false;
}
this.showPasswordOldTips = false;
return true;
},
//
verifyPasswordNew() {
if (!this.form.passwordNew) {
this.showPasswordNewTips = true;
this.passwordNewTips = '请输入新密码';
return false;
}
const reg = /^[a-zA-Z0-9._-]{6,20}$/;
if (!reg.test(this.form.passwordNew)) {
this.passwordNewTips = '请输入6-20位字母、数字、汉字或字符"_ - ."';
return false;
}
this.showPasswordNewTips = false;
return true;
},
/**
* 没有手机号 跳转绑定手机号的界面
* @param {string} phone
*/
async noPhone(phone) {
if (!phone) {
this.$u.route('/pages/phone-bind/phone-bind');
}
},
},
};
</script>
<style lang="scss" scoped>
.wrap {
width: 100%;
height: 100%;
}
.wrap-con {
width: 400px;
}
.text-blue {
color: #2979ff;
}
.btn {
line-height: 35px;
font-size: 1rem;
}
</style>

143
src/components/login/login.vue

@ -0,0 +1,143 @@
<template>
<view class="wrap flex justify-center items-center">
<view class="wrap-con">
<h1 class="text-3xl text-center mb-10">{{ project && project.id ? project.name : '时物链条' }}</h1>
<u-form :model="form" ref="uForm" :errorType="errorType">
<!-- 手机号 -->
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" prop="account" label-width="160" class="bg-white">
<u-input type="text" placeholder="账户" :border="border" v-model="form.account" />
</u-form-item>
<view class="mt-1 text-sm text-red-500" v-if="showAccountTips">{{ accountTips }}</view>
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" prop="password" label-width="160" class="bg-white mt-6">
<u-input type="password" placeholder="密码" :border="border" v-model="form.password" />
</u-form-item>
<view class="mt-1 text-sm text-red-500" v-if="showPasswordTips">{{ passwordTips }}</view>
</u-form>
<view class="flex justify-between my-8 text-sm">
<u-checkbox-group>
<u-checkbox v-model="checked"><text class="pl-2">自动登录</text></u-checkbox>
</u-checkbox-group>
<text class="text-blue cursor-pointer" @click="$emit('changeShow')">修改密码</text>
</view>
<!-- TODO: 报错 -->
<u-button @click="submit" type="primary" class="btn"> </u-button>
</view>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
data() {
return {
border: true,
form: {
account: '', //
password: '', //
},
accountTips: '',
passwordTips: '',
showAccountTips: false,
showPasswordTips: false,
checked: false,
errorType: ['message'],
};
},
computed: mapState('project', ['project']),
methods: {
...mapMutations('user', ['setToken', 'setUser', 'setFirstInter']),
async submit() {
//
if (this.verifyAccount() && this.verifyPassword()) {
try {
const { account, password } = this.form;
const params = {
client: this.$t.user.clients['h5'],
type: this.$t.user.types['username'],
data: { identifier: account, credential: password },
};
const data = await this.$u.api.signin(params);
if (data && data.token) {
this.setUser(data);
this.setToken(data.token);
this.noPhone(data.phone);
this.setFirstInter(true);
this.$t.ui.showToast('登录成功');
} else {
this.$t.ui.showToast('返回数据异常');
}
} catch (error) {
console.error('error: ', error);
this.$t.ui.showToast(error || '登录失败');
}
}
},
//
verifyAccount() {
if (!this.form.account) {
this.showAccountTips = true;
this.accountTips = '请输入账号';
return false;
} else {
this.showAccountTips = false;
return true;
}
},
//
verifyPassword() {
if (!this.form.password) {
this.showPasswordTips = true;
this.passwordTips = '请输入密码';
return false;
}
const reg = /^[a-zA-Z0-9._-]{6,20}$/;
if (!reg.test(this.form.password)) {
this.passwordTips = '请输入6-20位字母、数字、汉字或字符"_ - ."';
return false;
}
this.showPasswordTips = false;
return true;
},
/**
* 没有手机号 跳转绑定手机号的界面
* @param {string} phone
*/
async noPhone(phone) {
if (!phone) {
this.$u.route('/pages/phone-bind/phone-bind');
}
},
},
};
</script>
<style lang="scss" scoped>
.wrap {
width: 100%;
height: 100%;
}
.wrap-con {
width: 400px;
}
.text-blue {
color: #2979ff;
}
.btn {
line-height: 35px;
font-size: 1rem;
}
</style>

8
src/pages.json

@ -1,14 +1,6 @@
{
"pages": [
{
"path": "pages/login/login",
"style": {
"navigationBarText": "登录",
"topWindow": false,
"rightWindow": false
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarText": "TALL"

9
src/pages/index/index.vue

@ -10,7 +10,7 @@
</view>
<!-- 项目列表 -->
<Projects @getProjects="getProjects" class="flex-1 overflow-y-auto" />
<Projects ref="projects" @getProjects="getProjects" class="flex-1 overflow-y-auto" />
<!-- 全局提示框 -->
<u-top-tips ref="uTips"></u-top-tips>
@ -32,7 +32,7 @@ export default {
};
},
computed: mapState('user', ['token', 'user']),
computed: mapState('user', ['token', 'user', 'firstInter']),
watch: {
token(value) {
@ -66,6 +66,11 @@ export default {
item.show = false;
});
this.setProjects(data);
if (this.firstInter) {
setTimeout(() => {
this.$refs.projects.openProject();
}, 1000);
}
}
});
},

27
src/pages/login/login.vue

@ -1,27 +0,0 @@
<template>
<view>
<u-button size="mini" @click="openPage">登录</u-button>
</view>
</template>
<script>
export default {
data() {
return {};
},
watch: {},
methods: {
//
openPage() {
this.$u.route('pages/index/index', {
u: '1218763410024566784',
p: '1435920484033372160',
});
},
},
};
</script>
<style lang="scss" scoped></style>

17
src/pages/right-window/right-window.vue

@ -1,7 +1,13 @@
<template>
<view class="h-full bg-gray-50">
<view v-if="project && project.id">{{ project.name }}</view>
<view v-else>详情页</view>
<view class="w-full h-full" v-if="!user || !token">
<login v-if="!show" @changeShow="show = true"></login>
<change-password v-if="show" @changeShow="show = false"></change-password>
</view>
<view v-else>
<view v-if="project && project.id">{{ project.name }}</view>
<view v-else>详情页</view>
</view>
</view>
</template>
@ -10,10 +16,13 @@ import { mapState } from 'vuex';
export default {
data() {
return {};
return { show: false };
},
computed: mapState('project', ['project']),
computed: {
...mapState('project', ['project']),
...mapState('user', ['user', 'token']),
},
onLoad(options) {
console.log('options: ', options);

15
src/pages/top-window/top-window.vue

@ -1,17 +1,24 @@
<template>
<view class="w-full h-full bg-black flex justify-between items-center">
<view class="font-bold text-xl text-gray-300 m-3">智能大气腐蚀检测平台</view>
<view class="font-bold text-xl text-gray-300 m-3">{{ project && project.id ? project.name : '时物链条' }}</view>
<view class="flex items-center">
<u-avatar :src="src" :size="56"></u-avatar>
<text class="ml-3 mr-5 text-gray-400 text-sm"> Luckyºº</text>
<u-avatar :src="user && user.wxInfo && user.wxInfo.headImgUrl ? user.wxInfo.headImgUrl : src" :size="56"></u-avatar>
<text class="ml-3 mr-5 text-gray-400 text-sm">{{ user && user.account ? user.account : '未登录' }}</text>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex';
export default {
data() {
return { src: 'http://cnv14.55.la//uploads/img/tmp/1634635205221/6f768018369a1daadb125cbbb18815fc_1.png' };
return { src: '../../../public/img/avatar.jpg' };
},
computed: {
...mapState('project', ['project']),
...mapState('user', ['user']),
},
onLoad(options) {

9
src/store/user/mutations.js

@ -19,6 +19,15 @@ const mutations = {
state.user = { ...user };
uni.$t.storage.setStorageSync('user', JSON.stringify(user));
},
/**
* 设置是不是第一次进入系统
* @param {object} state
* @param {boolean} show
*/
setFirstInter(state, show) {
state.firstInter = show;
},
};
export default mutations;

1
src/store/user/state.js

@ -1,5 +1,6 @@
const state = {
token: '',
user: null,
firstInter: false,
};
export default state;

Loading…
Cancel
Save