通讯录,我的

This commit is contained in:
hayu 2024-12-30 20:46:34 +08:00
parent b75a564910
commit 23542f9779
7 changed files with 773 additions and 18 deletions

View File

@ -626,6 +626,22 @@
}
},
{
//--
"path": "pages/realName/workbench/myOrg/index",
"style": {
"navigationStyle": "custom"
}
},
{
//
"path": "pages/realName/workbench/myOrg/addressBook",
"style": {
"navigationStyle": "custom"
}
},
{
//退-退
"path": "pages/realName/workbench/outPerson/outList",

View File

@ -242,7 +242,7 @@ export default {
return {
selectTab: 1,
loginForm: {
phone: '14769014289', // 18955734761 18700000001 17681010134 15955147005 15656751631
phone: '19388390926', // 18955734761 18700000001 17681010134 15955147005 15656751631
pd: 'Lphd@123456' //YNsbd@123456 Lv@200018
},
loginForm0: {
@ -431,6 +431,7 @@ export default {
if (res.data.code == 200) {
uni.setStorageSync('realNameToken', res.data.data.access_token)
uni.setStorageSync('realNameUser', res.data.data.loginUser.sysUser)
uni.setStorageSync('realNamePermissions', res.data.data.loginUser.permissions)
setTimeout(() => {
uni.reLaunch({
url: '/pages/realName/index/index'

View File

@ -18,10 +18,10 @@
<image class="imgBox" src="../../../static/realName/news.png" mode=""></image>
<text class="textBox">我的消息</text>
</view>
<!-- <view class="view-item">
<view class="view-item" @click="restPwd">
<image class="imgBox" src="../../../static/realName/reset_pass.png" mode=""></image>
<text class="textBox">修改密码</text>
</view> -->
</view>
<!-- <view class="view-item">
<image class="imgBox" src="../../../static/realName/my_upload.png" mode=""></image>
<text class="textBox">上传情况</text>
@ -44,10 +44,50 @@
</view>
<view class="view-item" @click=outLogin>
<image class="imgBox" src="../../../static/realName/icon_logout.png" mode=""></image>
<text class="textBox">退出</text>
<text class="textBox">退出登录</text>
</view>
</scroll-view>
<uni-popup ref="popup" background-color="#fff">
<view style="width:600rpx;height: auto;">密码修改</view>
<view class="popup-content">
<u--form :model="restForm" ref="uForm3" :rules="rules3" labelWidth="60">
<u-form-item label="新密码" prop="password">
<u-input class="login-input" :type="isOpen?'text':'password'" placeholder="请输入密码" prefixIcon="lock"
v-model="restForm.password" save="false" autocomplete="new-password">
<template slot="suffix">
<image @click="isOpen=!isOpen"
style="width: 40rpx;height: 40rpx;margin-right: 10rpx; z-index: 999;"
:src="isOpen?'../../static/images/design_ic_visibility.png':'../../static/images/design_ic_visibility_off.png'">
</image>
</template>
</u-input>
</u-form-item>
<u-form-item label="再次确认" prop="passwordA">
<u-input class="login-input" :type="isOpen2?'text':'password'" placeholder="请再次输入密码" prefixIcon="lock"
v-model="restForm.passwordA" save="false" autocomplete="new-password">
<template slot="suffix">
<image @click="isOpen2=!isOpen2"
style="width: 40rpx;height: 40rpx;margin-right: 10rpx; z-index: 999;"
:src="isOpen2?'../../static/images/design_ic_visibility.png':'../../static/images/design_ic_visibility_off.png'">
</image>
</template>
</u-input>
</u-form-item>
<view style="color: red;line-height: 30rpx;font-size: 24rpx;padding-top: 20rpx;">
密码必须至少包含一个大写字母一个小写字母一个数字和一个特殊符号并且长度在8到16个字符之间
</view>
<view style="display: flex;">
<u-button class="loginBtn" style="margin-top: 30rpx;width: 30%;color: black;"
@click="closePwd" color="#d0d2d5">退出</u-button>
<u-button class="loginBtn" style="margin-top: 30rpx;width: 30%;" @click="submit"
color="#00367a">确认</u-button>
</view>
</u--form>
</view>
</uni-popup>
<u-popup :show="showPopup" mode="center" @close="closePopup">
<view style="width:600rpx;height: auto;position: relative;background-color: #fff;">
<view style="width: 100%;height: auto;background-color: #fff;">
@ -55,10 +95,10 @@
版权
</view>
<view style="width: 96%;margin: 20rpx auto;padding:10rpx 0;">
Facial Technology by ArcSoft?
Facial Technology by ArcSoft®
</view>
<view style="width: 96%;margin: 20rpx auto;padding:10rpx 0;">
Copyright by Bonus@
Copyright by Bonus®
</view>
<view style="width: 96%;margin: 20rpx auto;padding:10rpx 0;">
Website http://www.ahbonus.cn/
@ -84,12 +124,68 @@ import config from '@/config'
export default {
data() {
const equalToPassword = (rule, value, callback) => {
if (this.restForm.password !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
// 816,
var ISPWD =
/^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*,\._\+(){}])[0-9a-zA-Z!@#$%^&*,\\._\+(){}]{8,16}$/;
//
const validatePassword = (rule, value, callback) => {
if (!ISPWD.test(this.restForm.password)) {
callback(new Error("用户密码必须包含大写字母、小写字母、数字和特殊符号"));
} else {
callback();
}
}
return {
tabbar: TabbarConfig,
userData:uni.getStorageSync('realNameUser'),
proId:uni.getStorageSync('realNameUser').proId,
subId: uni.getStorageSync('realNameUser').subId,
type:uni.getStorageSync('realNameUser').type,
proName:"",
showPopup:false
showPopup:false,
restForm: {
password: "",
passwordA: ""
},
rules3: {
password: [{
required: true,
trigger: "blur",
message: "请输入您的密码"
},
{
min: 8,
max: 16,
message: '用户密码长度必须介于 8 和 16 之间',
trigger: 'blur'
},
{
required: true,
validator: validatePassword,
trigger: 'blur'
}
],
passwordA: [{
required: true,
message: '请再次输入新密码',
trigger: ['blur', 'change']
},
{
required: true,
validator: equalToPassword,
trigger: "blur"
}
]
},
isOpen:false,
isOpen2:false,
// userName: uni.getStorageSync('userName'),
// className: uni.getStorageSync('className'),
// facePath: config.fileUrl + uni.getStorageSync('facePath'),
@ -103,12 +199,21 @@ export default {
methods: {
//
getPro(){
let param={
let param;
if (this.type.indexOf('3')>-1){
param={
id:this.proId,
subId:-1
}
} else if (this.type.indexOf('4')>-1){
param={
id:-1,
subId:this.subId
}
}
uni.request({
url: config.realAppUrl + '/offLine/getPro',
url: config.lpAppUrl + '/offLine/getPro',
method: 'post',
data: param,
header: {
@ -140,9 +245,62 @@ export default {
closePopup(){
this.showPopup=false;
},
restPwd() {
this.restForm.password=''
this.restForm.passwordA=''
// open uni-popup type
this.$refs.popup.open("center")
},
closePwd() {
// open uni-popup type
this.$refs.popup.close("center")
},
submit() {
let _this = this
this.$refs.uForm3.validate().then(res => {
let form = {
userId: uni.getStorageSync('realNameUser').userId,
password: this.restForm.password
}
console.log("form:",form)
uni.request({
url: config.lpAppUrl + '/offLine/updatePassword',
method: 'post',
data: form,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
res = res.data;
if(res.code==200){
console.log(res)
this.closePwd()
uni.showToast({ title: '密码修改成功', icon: 'none' })
} else {
uni.$u.toast("修改失败")
}
},
fail: err => {
console.log(err)
}
})
}).catch(errors => {
// uni.$u.toast('')
})
},
outLogin(){
uni.navigateTo({
url: `/pages/gzt/index`
uni.showModal({
title: '提示',
content: '确定退出登录吗?',
success: res => {
if (res.confirm) {
uni.reLaunch({
url: '/pages/login'
})
}
}
})
}
}
@ -193,4 +351,21 @@ export default {
}
}
.popup-content {
@include flex;
align-items: center;
justify-content: center;
padding: 15px;
height: 480rpx;
background-color: #fff;
max-width: 600rpx;
}
image {
width: 60rpx;
height: 60rpx;
margin-right: 20rpx;
margin-left: 20rpx;
}
</style>

View File

@ -40,7 +40,7 @@ export default {
}
console.log(param)
uni.request({
url: config.realAppUrl + '/offLine/getNews',
url: config.lpAppUrl + '/offLine/getNews',
method: 'post',
data: param,
header: {

View File

@ -91,6 +91,14 @@
<!-- <view style="font-size: 26rpx;">安全教育培训</view>-->
<!-- </view>-->
<!-- <view class="view-item" @click="goMyOrg" v-if="type.indexOf('3')>-1">-->
<!-- <view>-->
<!-- <image class="img1" src="@/static/realName/out_person.png"-->
<!-- style="width: 80rpx;height: 80rpx;" alt="">-->
<!-- </view>-->
<!-- <view style="font-size: 28rpx;">我的组织</view>-->
<!-- </view>-->
</view>
</scroll-view>
</view>
@ -280,6 +288,10 @@
uni.navigateTo({
url: `/pages/realName/workbench/cutToPlace/index`
})
} else if (name=='我的组织'){
uni.navigateTo({
url: `/pages/realName/workbench/myOrg/index`
})
}
},
@ -317,6 +329,12 @@
})
},
goMyOrg() {
uni.navigateTo({ //
url: `/pages/realName/workbench/myOrg/index`
})
},
goDailyPlanManagement() {
uni.navigateTo({ //
url: `/pages/realName/workbench/dailyPlanManagement/index`

View File

@ -0,0 +1,288 @@
<template>
<view class="contact-page">
<u-navbar class="u-navbar" title="通讯录" placeholder @leftClick="leftClick" leftIconColor="#fff"
bgColor="#00337A" :titleStyle="{ color: '#FFF', fontSize: '32rpx' }"/>
<!-- 搜索框 -->
<view class="search-box">
<view class="search-input">
<uni-icons type="search" size="16" color="#999"></uni-icons>
<input
type="text"
v-model="searchText"
placeholder="搜索"
placeholder-class="placeholder"
/>
</view>
<text class="cancel-btn" @tap="onCancel">取消</text>
</view>
<!-- 联系人列表 -->
<scroll-view
class="contact-list"
scroll-y
:scroll-into-view="scrollIntoView"
>
<block v-for="letter in Object.keys(showList)" :key="letter">
<view class="letter-title" :id="'index-'+letter">{{letter}}</view>
<view
class="contact-item"
v-for="item in showList[letter]"
:key="item.id"
@tap="selectHandler(item)"
>
{{item.name}}
</view>
</block>
</scroll-view>
<!-- 字母导航 -->
<view class="index-list">
<text
v-for="letter in indexList"
:key="letter"
class="index-item"
@tap="scrollTo(letter)"
>
{{letter}}
</text>
</view>
<!-- 加载提示 -->
<view v-if="loading" class="loading">
<uni-icons type="spinner-cycle" size="24" color="#999"></uni-icons>
<text>加载中...</text>
</view>
</view>
</template>
<script>
import config from '@/config'
import { pinyin } from "@/api/convertPinyin.js"
export default {
data() {
return {
searchText: '',
indexList: [],
txlList: {},
loading: false,
scrollIntoView: '',
type: '',
value: ''
}
},
onLoad(options) {
if (options.type) {
this.type = decodeURIComponent(options.type)
}
if (options.value) {
this.value = decodeURIComponent(options.value)
}
console.log('接收到的数据:', { type: this.type, value: this.value })
// type value
},
computed: {
showList() {
if (!this.searchText) return this.txlList
const result = {}
Object.keys(this.txlList).forEach(letter => {
const filtered = this.txlList[letter].filter(item =>
item.name.toLowerCase().includes(this.searchText.toLowerCase()) ||
item.phone.includes(this.searchText)
)
if (filtered.length) {
result[letter] = filtered
}
})
return result
}
},
onShow() {
this.indexList = "ABCDEFGHIJKLMNOPQRSTUVWXYZ#".split("")
this.getAddressList()
},
methods: {
selectHandler(item) {
uni.makePhoneCall({
phoneNumber: item.phone,
success: () => {
console.log('拨打电话成功')
},
fail: () => {
console.log('拨打电话失败')
}
})
},
onCancel() {
this.searchText = ''
},
scrollTo(letter) {
this.scrollIntoView = 'index-' + letter
},
getAddressList() {
this.loading = true
let param = {
type: this.type,
value: this.value
}
uni.request({
url: config.lpAppUrl + '/offLine/selectMailContent',
method: 'post',
data: JSON.stringify(param),
header: {
'content-type': 'application/json',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
if (res.data.code == 200) {
console.log("res.data:",res.data)
if (res.data.data.length>0) {
this.txlList = this.sortContacts(res.data.data, "name")
}else {
uni.showToast({
title: '暂无数据',
icon: 'none'
})
}
} else {
uni.showToast({
title: '获取通讯录失败',
icon: 'none'
})
}
this.loading = false
},
fail: () => {
uni.showToast({
title: '获取通讯录失败',
icon: 'none'
})
this.loading = false
}
})
},
sortContacts(arrList, char = "name") {
if (!String.prototype.localeCompare) return null
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ#".split("")
const result = {}
//
letters.forEach(letter => {
result[letter] = []
})
//
arrList.forEach((item, index) => {
const initial = item[char].trim().charAt(0)
const firstLetter = pinyin.getFullChars(initial).charAt(0).toUpperCase()
item.id = index
if (letters.includes(firstLetter)) {
result[firstLetter].push(item)
} else {
result['#'].push(item)
}
})
//
Object.keys(result).forEach(key => {
if (result[key].length === 0) {
delete result[key]
}
})
return result
},
//
leftClick() {
console.log('返回')
uni.navigateBack({
delta: 1 //
});
},
}
}
</script>
<style lang="scss">
.contact-page {
min-height: 100vh;
background-color: #fff;
position: relative;
.search-box {
padding: 10px 15px;
background-color: #fff;
display: flex;
align-items: center;
position: sticky;
top: 0;
z-index: 100;
.search-input {
flex: 1;
height: 36px;
background: #f5f5f5;
border-radius: 18px;
display: flex;
align-items: center;
padding: 0 12px;
input {
flex: 1;
margin-left: 8px;
font-size: 14px;
}
.placeholder {
color: #999;
}
}
.cancel-btn {
padding-left: 15px;
font-size: 14px;
color: #007AFF;
}
}
.contact-list {
height: calc(100vh - 56px);
.letter-title {
padding: 4px 15px;
background-color: #f5f5f5;
color: #666;
font-size: 14px;
}
.contact-item {
padding: 12px 15px;
border-bottom: 1px solid #f5f5f5;
font-size: 16px;
color: #333;
}
}
.index-list {
position: fixed;
right: 0;
top: 50%;
transform: translateY(-50%);
padding: 10px 4px;
background-color: transparent;
display: flex;
flex-direction: column;
.index-item {
padding: 2px 4px;
font-size: 12px;
color: #007AFF;
}
}
}
</style>

View File

@ -0,0 +1,257 @@
<template>
<view class="contact-page">
<u-navbar class="u-navbar" title="我的组织" placeholder @leftClick="leftClick" leftIconColor="#fff"
bgColor="#00337A" :titleStyle="{ color: '#FFF', fontSize: '32rpx' }"/>
<!-- 搜索框 -->
<view class="search-box">
<view class="search-input">
<uni-icons type="search" size="16" color="#999"></uni-icons>
<input
type="text"
v-model="searchText"
placeholder="搜索"
placeholder-class="placeholder"
/>
</view>
<text class="cancel-btn" @tap="onCancel">取消</text>
</view>
<scroll-view class="content" scroll-y="true">
<!-- 列表区域 -->
<view class="list-container">
<template v-for="item in formattedList">
<view
:key="item.id"
class="list-item"
:style="{ paddingLeft: item.level * 20 + 15 + 'px' }"
@tap="onItemClick(item)"
>
<view class="item-content">
<text class="item-icon" v-if="item.type === 'team'"></text>
<text class="item-name">{{item.name}}</text>
</view>
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</template>
</view>
</scroll-view>
<!-- 加载中提示 -->
<view v-if="loading" class="loading">
<uni-icons type="spinner-cycle" size="24" color="#999"></uni-icons>
<text>加载中...</text>
</view>
<!-- 错误提示 -->
<view v-if="error" class="error">
<text>{{error}}</text>
<button @tap="fetchData">重试</button>
</view>
</view>
</template>
<script>
import config from '@/config'
export default {
data() {
return {
searchText: '',
listData: [],
loading: false,
error: null
}
},
computed: {
formattedList() {
if (!this.searchText) return this.formatData(this.listData);
return this.formatData(this.listData.filter(item =>
item.name.toLowerCase().includes(this.searchText.toLowerCase())
));
}
},
mounted() {
this.fetchData()
},
methods: {
fetchData() {
this.loading = true
this.error = null
let param={
name:this.searchText,
proId:uni.getStorageSync('realNameUser').proId,
teamId:uni.getStorageSync('realNameUser').teamId
}
console.log("param:",param)
uni.request({
url: config.lpAppUrl+'/offLine/selectMailTree', // API
method: 'post',
data: JSON.stringify(param),
header: {
'content-type': 'application/json',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
res = res.data;
if(res.code==200){
console.log(res)
this.listData=res.data;
}
this.loading = false
},
fail: err => {
console.log(err)
this.loading = false
}
})
},
onCancel() {
this.searchText=''
},
onItemClick(item) {
//
console.log('点击了:', item)
const type = item.type
const value = item.id
uni.navigateTo({
url: `/pages/realName/workbench/myOrg/addressBook?type=${encodeURIComponent(type)}&value=${encodeURIComponent(value)}`
})
},
formatData(data) {
return data.map(item => ({...item, level: this.getLevel(item.id)}))
},
getLevel(id) {
let level = 0;
let current = this.listData.find(item => item.id === id);
while (current && current.pId !== 0) {
level++;
current = this.listData.find(item => item.id === current.pId);
}
return level;
},
//
leftClick() {
console.log('返回')
uni.navigateBack({
delta: 1 //
});
},
goAdd(){
uni.navigateTo({
url: `/pages/realName/workbench/safeguarding/add`
})
},
}
}
</script>
<style lang="scss">
.contact-page {
min-height: 100vh;
background-color: #f5f5f5;
.search-box {
padding: 10px 15px;
background-color: #fff;
display: flex;
align-items: center;
.search-input {
flex: 1;
height: 36px;
background: #f5f5f5;
border-radius: 18px;
display: flex;
align-items: center;
padding: 0 12px;
input {
flex: 1;
margin-left: 8px;
font-size: 14px;
}
.placeholder {
color: #999;
}
}
.cancel-btn {
padding-left: 15px;
font-size: 14px;
color: #007AFF;
}
}
.list-container {
background-color: #fff;
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 15px;
border-bottom: 1px solid #f5f5f5;
.item-content {
display: flex;
align-items: center;
.item-icon {
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
background: #f0f0f0;
border-radius: 4px;
margin-right: 10px;
font-size: 12px;
color: #666;
}
.item-name {
font-size: 15px;
color: #333;
}
}
}
}
.loading, .error {
padding: 20px;
text-align: center;
color: #999;
.uni-icons {
margin-right: 10px;
}
}
.error {
color: #ff4d4f;
button {
margin-top: 10px;
padding: 5px 10px;
background-color: #007AFF;
color: #fff;
border: none;
border-radius: 4px;
}
}
.content{
width: 100%;
height: 84vh;
margin-top: 20rpx;
background-color: #f8f8f8;
padding-bottom: 40rpx;
}
}
</style>