通话样式组件封装完成

This commit is contained in:
小李 2026-03-11 11:24:00 +08:00
parent 6095979884
commit bd99f8e013
14 changed files with 432 additions and 45 deletions

View File

@ -1,15 +1,31 @@
<template> <template>
<view class="header" :class="['header_'+type]"> <view class="header" :class="['header_'+type]">
<view class="title"> <view class="title" v-if="type!='vivo'">
{{title}} {{title}}
</view> </view>
<view class="search"> <view class="search" v-if="type!='oppo'&&type!='huawei'&&type!='vivo'">
<view class="left"> <view class="left">
<image src="/static/image/call/iosSearchLeft.png" mode=""></image> <image src="/static/image/call/iosSearchLeft.png" mode=""></image>
{{searchTitle}} {{searchTitle}}
</view> </view>
<image v-if="type=='ios'" src="/static/image/call/iosSearchRight.png" mode=""></image> <image v-if="type=='ios'" src="/static/image/call/iosSearchRight.png" mode=""></image>
</view> </view>
<view class="selectType" v-if="type=='huawei'">
<view class="btn active">
全部来电
</view>
<view class="btn">
未接来电
</view>
</view>
<view class="selectTypeVivo" v-if="type=='vivo'">
<view class="btn active">
全部
</view>
<view class="btn">
未接
</view>
</view>
<view class="select" v-if="type=='xiaomi'"> <view class="select" v-if="type=='xiaomi'">
全部通话 全部通话
<image src="/static/image/call/xiaomiHeaderSelectImg.png" mode=""></image> <image src="/static/image/call/xiaomiHeaderSelectImg.png" mode=""></image>
@ -62,7 +78,12 @@
searchTitle.value="搜索联系人" searchTitle.value="搜索联系人"
title.value="通话" title.value="通话"
console.log('aaaaaaaaaaa') console.log('aaaaaaaaaaa')
}else if(props.type=='oppo'){
title.value="通话"
}else if(props.type=='huawei'){
title.value="电话"
} }
}) })
</script> </script>
@ -111,6 +132,66 @@
} }
} }
} }
.selectTypeVivo{
padding-top: 18px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
.btn{
width: 62px;
background-color: #F6F6F6;
text-align: center;
font-size: 13px;
color: #555555;
height: 30px;
line-height: 30px;
border-radius: 8px 0 0 8px;
margin: 0 1px;
}
.btn:nth-child(2){
border-radius:0 8px 8px 0;
}
.active{
font-size: 13px;
color: #1A1A1A;
background: #DCF6E6;
}
}
.header_huawei{
padding-bottom: 14px;
.title{
padding-left: 3px;
font-weight: bold;
font-size: 30px !important;
color: #1A1A1A !important;
}
.selectType{
margin-top: 18px;
height: 38px;
background: #F4F4F4;
border-radius: 19px 19px 19px 19px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 2px;
.btn{
width: 50%;
text-align: center;
font-size: 13px;
color: #555555;
height: 34px;
line-height: 34px;
}
.active{
font-size: 13px;
color: #1A1A1A;
background: #fff;
border-radius: 19px 19px 19px 19px;
}
}
}
.header_xiaomi{ .header_xiaomi{
.title{ .title{
padding-left: 15px; padding-left: 15px;

View File

@ -86,12 +86,43 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 编辑按钮 -->
<view class="edit-btn" @click="editItem(index)">
<text class="edit-text">编辑</text>
</view>
<!-- 删除按钮 --> <!-- 删除按钮 -->
<view class="delete-btn" @click="deleteItem(index)"> <view class="delete-btn" @click="deleteItem(index)">
<text class="delete-text">删除</text> <text class="delete-text">删除</text>
</view> </view>
</view> </view>
</view> </view>
<!-- 编辑弹窗 -->
<view class="modal-mask" v-if="showEditModal" @click="closeEditModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">编辑通话记录</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="form-label">姓名</text>
<input class="form-input" v-model="editForm.name" placeholder="请输入姓名" />
</view>
<view class="form-item">
<text class="form-label">电话</text>
<input class="form-input" v-model="editForm.phone" placeholder="请输入电话" />
</view>
<view class="form-item">
<text class="form-label">备注</text>
<input class="form-input" v-model="editForm.notes" placeholder="请输入备注" />
</view>
</view>
<view class="modal-footer">
<view class="btn btn-cancel" @click="closeEditModal">取消</view>
<view class="btn btn-confirm" @click="saveEdit">保存</view>
</view>
</view>
</view>
</template> </template>
<script setup> <script setup>
@ -108,6 +139,8 @@
} }
}); });
const emit = defineEmits(['update:list']);
const list = ref([ const list = ref([
{ {
"avatar": "/static/avatar/1.png", "avatar": "/static/avatar/1.png",
@ -391,13 +424,20 @@
} }
]); ]);
const swiperList = ref([]); // item const swiperList = ref([]);
const startX = ref(0); // X const startX = ref(0);
const startY = ref(0); // Y const startY = ref(0);
const deleteWidth = ref(70); // const deleteWidth = ref(140);
const showEditModal = ref(false);
const editForm = reactive({
name: '',
phone: '',
notes: ''
});
const editIndex = ref(-1);
onMounted(() => { onMounted(() => {
// swiperList
swiperList.value = new Array(list.value.length).fill(0); swiperList.value = new Array(list.value.length).fill(0);
}); });
@ -405,11 +445,9 @@
console.log(newValue); console.log(newValue);
}); });
//
const touchStart = (e, index) => { const touchStart = (e, index) => {
startX.value = e.changedTouches[0].clientX; startX.value = e.changedTouches[0].clientX;
startY.value = e.changedTouches[0].clientY; startY.value = e.changedTouches[0].clientY;
// item
swiperList.value.forEach((item, i) => { swiperList.value.forEach((item, i) => {
if (i !== index) { if (i !== index) {
swiperList.value[i] = 0; swiperList.value[i] = 0;
@ -417,27 +455,21 @@
}); });
}; };
//
const touchMove = (e, index) => { const touchMove = (e, index) => {
const moveX = e.changedTouches[0].clientX; const moveX = e.changedTouches[0].clientX;
const moveY = e.changedTouches[0].clientY; const moveY = e.changedTouches[0].clientY;
const disX = moveX - startX.value; const disX = moveX - startX.value;
const disY = moveY - startY.value; const disY = moveY - startY.value;
//
if (Math.abs(disX) > Math.abs(disY)) { if (Math.abs(disX) > Math.abs(disY)) {
//
e.preventDefault(); e.preventDefault();
// 0-deleteWidth
let distance = Math.max(-deleteWidth.value, Math.min(0, disX)); let distance = Math.max(-deleteWidth.value, Math.min(0, disX));
swiperList.value[index] = distance; swiperList.value[index] = distance;
} }
}; };
//
const touchEnd = (e, index) => { const touchEnd = (e, index) => {
const endX = e.changedTouches[0].clientX; const endX = e.changedTouches[0].clientX;
const disX = endX - startX.value; const disX = endX - startX.value;
//
if (disX < -deleteWidth.value / 2) { if (disX < -deleteWidth.value / 2) {
swiperList.value[index] = -deleteWidth.value; swiperList.value[index] = -deleteWidth.value;
} else { } else {
@ -445,9 +477,7 @@
} }
}; };
// item
const deleteItem = (index) => { const deleteItem = (index) => {
//
uni.showModal({ uni.showModal({
title: '确认删除', title: '确认删除',
content: '确定要删除这条通话记录吗?', content: '确定要删除这条通话记录吗?',
@ -455,14 +485,42 @@
cancelText: '取消', cancelText: '取消',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
// item
list.value.splice(index, 1); list.value.splice(index, 1);
// swiperList
swiperList.value.splice(index, 1); swiperList.value.splice(index, 1);
emit('update:list', list.value);
} }
} }
}); });
}; };
const editItem = (index) => {
editIndex.value = index;
editForm.name = list.value[index].name;
editForm.phone = list.value[index].phone;
editForm.notes = list.value[index].notes;
showEditModal.value = true;
};
const closeEditModal = () => {
showEditModal.value = false;
editIndex.value = -1;
};
const saveEdit = () => {
if (!editForm.name && !editForm.phone) {
uni.showToast({
title: '请填写姓名或电话',
icon: 'none'
});
return;
}
list.value[editIndex.value].name = editForm.name;
list.value[editIndex.value].phone = editForm.phone;
list.value[editIndex.value].notes = editForm.notes;
emit('update:list', list.value);
closeEditModal();
swiperList.value[editIndex.value] = 0;
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -492,6 +550,7 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
background-color: #fff; background-color: #fff;
z-index: 2;
.left-box { .left-box {
display: flex; display: flex;
@ -564,29 +623,52 @@
} }
} }
// .edit-btn {
position: absolute;
top: 0;
right: -140rpx;
width: 70rpx;
height: 100%;
background-color: #007AFF;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
.edit-text {
color: #fff;
font-size: 28rpx;
}
}
.delete-btn { .delete-btn {
position: absolute; position: absolute;
top: 0; top: 0;
right: -160rpx; right: -70rpx;
width: 160rpx; width: 70rpx;
height: 100%; height: 100%;
background-color: #FF3B30; background-color: #FF3B30;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
z-index: 1;
.delete-text { .delete-text {
color: #fff; color: #fff;
font-size: 32rpx; font-size: 28rpx;
} }
} }
} }
} }
.call-list-ios { .call-list-ios {
.delete-btn{ .edit-btn{
right: -140rpx !important; right: -140rpx !important;
width: 140rpx !important; width: 70rpx !important;
height: 100% !important;
background-color: #007AFF;
}
.delete-btn{
right: -70rpx !important;
width: 70rpx !important;
height: 100% !important; height: 100% !important;
background-color: #FF3B30; background-color: #FF3B30;
} }
@ -875,4 +957,84 @@
align-items: center; align-items: center;
} }
} }
</style>
.modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.modal-content {
width: 600rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
}
.modal-header {
padding: 40rpx;
text-align: center;
border-bottom: 1rpx solid #f0f0f0;
}
.modal-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.modal-body {
padding: 40rpx;
}
.form-item {
margin-bottom: 30rpx;
}
.form-label {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 16rpx;
}
.form-input {
width: 100%;
height: 80rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.modal-footer {
display: flex;
border-top: 1rpx solid #f0f0f0;
}
.btn {
flex: 1;
height: 100rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 32rpx;
}
.btn-cancel {
border-right: 1rpx solid #f0f0f0;
color: #666;
}
.btn-confirm {
color: #007AFF;
}
</style>

View File

@ -1,19 +1,11 @@
<template> <template>
<uni-nav-bar :backgroundColor="navBgColor" class="nav-bar" :border="false" :title="title" fixed="true" > <uni-nav-bar :backgroundColor="navBgColor" class="nav-bar" :border="false" :title="title" fixed="true">
<template v-slot:left> <template v-slot:left>
<slot name="left"> <slot name="left">
<view :class="[type+'LeftTitle']" v-if="type=='ios'"> <view :class="[type+'LeftTitle']" :style="{opacity:(type!='huawei'&&type!='oppo'?1: navOpacity)}">
编辑 {{LeftTitle}}
</view>
<view :class="[type+'LeftTitle']" v-else-if="type=='vivo'">
拨号
</view>
<view :class="[type+'LeftTitle']" v-else-if="type=='oppo'">
通话
</view>
<view :class="[type+'LeftTitle']" v-else-if="type=='huawei'">
电话
</view> </view>
</slot> </slot>
</template> </template>
<view class="nav-bar-title " :class="['nav-bar-title-'+type]"> <view class="nav-bar-title " :class="['nav-bar-title-'+type]">
@ -26,6 +18,14 @@
未接来电 未接来电
</view> </view>
</view> </view>
<view class="oppoBox" v-if="type=='oppo'" :style="{opacity: navOpacity?1-navOpacity:1}">
<view class="btn active">
全部
</view>
<view class="btn">
未接
</view>
</view>
<view class="title" v-else-if="type=='xiaomi'" :style="{opacity: navOpacity}"> <view class="title" v-else-if="type=='xiaomi'" :style="{opacity: navOpacity}">
通话 通话
</view> </view>
@ -33,7 +33,12 @@
</view> </view>
<template v-slot:right> <template v-slot:right>
<slot name="right"> <slot name="right">
<image v-if="type!='ios'" class="rightImg" :class="['rightImg_'+type]" src="/static/image/call/xiaomiNavRightImg.png"></image> <view class="rightImgBox" :class="['rightImgBox'+type]">
<image v-if="type=='oppo'||type=='vivo'" class="rightImg" :src="`/static/image/call/${type}NavRightImg2.png`"></image>
<image v-if="type!='ios'" class="rightImg" :class="['rightImg_'+type]"
:src="`/static/image/call/${type}NavRightImg.png`"></image>
</view>
</slot> </slot>
</template> </template>
</uni-nav-bar> </uni-nav-bar>
@ -68,7 +73,7 @@
type: String, type: String,
default: 'ios' default: 'ios'
}, },
scrollTop:{ scrollTop: {
type: Number, type: Number,
default: 0 default: 0
} }
@ -76,12 +81,14 @@
const data = reactive({ const data = reactive({
statusBarHeight: 0, statusBarHeight: 0,
LeftTitle:'',
showTipLayer: true, showTipLayer: true,
navOpacity: 0, // navOpacity: 0, //
navBgColor: props.bgColor // navBgColor: props.bgColor //
}) })
let { let {
LeftTitle,
showTipLayer, showTipLayer,
navOpacity, navOpacity,
navBgColor navBgColor
@ -104,15 +111,68 @@
}); });
onMounted(() => { onMounted(() => {
if(props.type=='ios'){
LeftTitle.value='编辑'
}else if(props.type=='vivo'){
LeftTitle.value='拨号'
}else if(props.type=='oppo'){
LeftTitle.value='通话'
}else if(props.type=='huawei'){
LeftTitle.value='电话'
}else {
LeftTitle.value=''
}
}) })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
::v-deep .uni-navbar__header-btns {
width: 25vw !important;
}
.iosLeftTitle { .iosLeftTitle {
font-weight: 400; font-weight: 400;
font-size: 16px; font-size: 16px;
color: #018AE0; color: #018AE0;
} }
.rightImgBox {
display: flex;
align-items: center;
image {
width: 24px ;
height: 24px;
}
}
.rightImg_oppo {
margin-left: 26px;
}
.rightImg_vivo {
margin-left: 26px;
margin-right: 16px;
}
.oppoLeftTitle {
padding-left: 8px;
font-weight: bold;
font-size: 32px;
color: #1A1A1A;
}
.huaweiLeftTitle {
padding-left: 8px;
font-weight: bold;
font-size: 30px;
color: #1A1A1A;
}
.vivoLeftTitle {
padding-left: 34px;
font-weight: bold;
font-size: 30px;
color: #1A1A1A;
}
.nav-bar-title-xiaomi { .nav-bar-title-xiaomi {
display: flex; display: flex;
align-items: center; align-items: center;
@ -122,11 +182,47 @@
font-size: 18px; font-size: 18px;
color: #1A1A1A; color: #1A1A1A;
} }
.nav-bar-title-oppo {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
.oppoBox {
padding: 0 2px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-around;
width: 137px;
height: 34px;
background: #E9E9E9;
border-radius: 17px 17px 17px 17px;
.btn {
font-size: 12px;
color: #6B6B6B;
width: 67px;
height: 30px;
text-align: center;
line-height: 30px;
}
.active {
color: #1A1A1A;
background: #FFFFFF;
border-radius: 17px 17px 17px 17px;
}
}
}
.nav-bar-title-ios { .nav-bar-title-ios {
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.iosBox { .iosBox {
width: 100%; width: 100%;
display: flex; display: flex;
@ -136,6 +232,7 @@
height: 30px; height: 30px;
background: #EEEEEE; background: #EEEEEE;
border-radius: 8px 8px 8px 8px; border-radius: 8px 8px 8px 8px;
.btn { .btn {
font-size: 12px; font-size: 12px;
color: #1A1A1A; color: #1A1A1A;
@ -144,6 +241,7 @@
text-align: center; text-align: center;
line-height: 26px; line-height: 26px;
} }
.active { .active {
background: #FFFFFF; background: #FFFFFF;
box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1);
@ -151,8 +249,14 @@
} }
} }
} }
.rightImg_xiaomi{
width: 20px; .rightImg_xiaomi {
height: 20px; width: 20px !important;
height: 20px !important;
}
.rightImg_huawei {
width: 38px !important;
height: 38px !important;
} }
</style> </style>

View File

@ -71,6 +71,16 @@
"联系人", "联系人",
"营业厅" "营业厅"
] ]
}else if (props.type == 'huawei') {
list.value = ["电话",
"联系人",
"收藏"
]
}else if (props.type == 'vivo') {
list.value = ["拨号",
"联系人",
"收藏"
]
} }
}) })
</script> </script>
@ -117,7 +127,37 @@
} }
} }
} }
.footer_huawei {
background: #FAFAFA !important;
padding-top: 3px;
.item {
image {
width: 24px;
height: 24px;
}
}
.item:nth-child(1) {
text {
color: #0060EA;
}
}
}
.footer_vivo {
background: #FAFAFA !important;
padding-top: 13px;
padding-bottom: 13px;
.item {
image {
width: 24px;
height: 24px;
}
}
.item:nth-child(1) {
text {
color: #1BA552;
}
}
}
.footer_xiaomi ,.footer_oppo{ .footer_xiaomi ,.footer_oppo{
padding-top: 7px; padding-top: 7px;

View File

@ -19,7 +19,7 @@
import { onLoad, onShow, onReady, onPageScroll, onReachBottom } from "@dcloudio/uni-app"; import { onLoad, onShow, onReady, onPageScroll, onReachBottom } from "@dcloudio/uni-app";
const { appContext, proxy } = getCurrentInstance(); const { appContext, proxy } = getCurrentInstance();
const data = reactive({ const data = reactive({
type: 'ios', type: 'vivo',
scrollTop:0 scrollTop:0
}) })

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB