123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- <!--
- 联系人主页,获取通讯录信息
-
- zzh 24.9.28 选择对方电话号码
- 方新力 24.8.28 修改字体大小,满6字换行,号码满7字换
- -->
- <template>
- <view class="content">
- <view v-if="searchActive" class="navbar" style="padding-bottom: 20px;">
- <image @click="showBar()" class="icon" src="../../static/pics/search.png"></image>
- <image @click="navigateToPage('add')" class="icon" src="../../static/pics/add.png"></image>
- <image @click="navigateToPage('setting')" class="icon" src="../../static/pics/setting.png"></image>
-
- </view>
- <view class="navbar" v-else>
- <view class="uni-column">
- <view class="search-input">
- <input type="text" focus confirm-type="search" v-model="searchText" placeholder="输入号码或名字" @input="filterContacts" />
- </view>
- <view class="search-img" @click="showBar()">
- 取消
- </view>
- </view>
- </view>
- <view class="text-area">
- <view v-if="filteredContacts.length" v-for="(item, id) in filteredContacts" :key="id">
- <view class="name-btn">
-
- <view v-if="switchStatus" style="display: flex;flex-direction: row; ">
- <view class="loud" @click="play(item.displayName || item.phoneNumbers[0].value)">
- <image style="width: 80%;height: 40%; margin-left: 35rpx;" src="../../static/pics/laba.png"></image>
- </view>
- <view class="con-mes" @click="goToDetails(item)">
- <text v-if="!item.displayName">{{ formatPhoneNumber(item.phoneNumbers[0].value) }}</text>
- <text v-else>{{ truncate(item.displayName) }}</text>
- </view>
- </view>
-
- <view v-else>
- <view class="con-mes-null" @click="goToDetails(item)">
- <text v-if="!item.displayName">{{ formatPhoneNumber(item.phoneNumbers[0].value) }}</text>
- <text v-else>{{ truncate(item.displayName) }}</text>
- </view>
- </view>
-
- <NumbersChoose class="phonenumber-choose-component"
- :visible="isChooseNumberVisible[item.id] || false"
- :title="item.displayName"
- @update:visible="(visible) => this.$set(isChooseNumberVisible, item.id, visible)">
- <template #default>
- <div class="scrollable-box">
- <view v-for="(number, index) in item.phoneNumbers" :key="index" @click="CallPhone(item,number.value)">
- <text class="choose-phonenumber">
- {{formatPhoneNumber1(number.value) }}
- </text>
- </view>
- </div>
- </template>
- </NumbersChoose>
- <!-- :style="{backgroundColor:isActive ? 'grey' :'white'}"
- @touchedstart="handleTouchedStart"
- @touchend="handleTouchedEnd"
- @touchcancel="handleTouchedEnd" -->
- <view class="btn" @click="showChooseNumber(item,item.phoneNumbers[0].value)">
- <image class="Call" src="../../static/pics/call-out.png"></image>
- </view>
- </view>
- </view>
- <view v-else class="notFind">
- 该号码或联系人不存在
- </view>
- </view>
- </view>
- </template>
- <script>
- // 辅助函数,用于获取字符串的所有拼音首字母
- function getInitials(str) {
- // 将字符串转换为拼音数组,每个汉字转换为对应的拼音首字母
- const initialsArray = pinyin(str, {
- style: pinyin.STYLE_FIRST_LETTER
- });
-
- // 映射每个拼音首字母数组,只取每个数组的第一个字符(即首字母)
- const firstLettersOnly = initialsArray.map(initial => initial[0]);
-
- // 使用 join 方法将所有首字母拼接成一个字符串
- return firstLettersOnly.join('');
- }
- const FvvUniTTS=uni.requireNativePlugin('Fvv-UniTTS');
- import pinyin from "pinyin"; // 假设你使用了一个 pinyin 库,例如 pinyin
- import CustomModal from '@/components/customModal.vue';
- import NumbersChoose from '@/components/oppositePhonenumberChoose.vue'
- // import oppositePhonenumbers from '@components/oppositePhonenumberChoose.vue';
- export default {
- //注册组件
- components:{
- CustomModal,
- NumbersChoose,
- // oppositePhonenumbers,
- } ,
- data() {
- return {
- searchText: '', // 用户输入的搜索文本
- list: [], // 原始联系人列表
- filteredContacts: [], // 过滤后的联系人列表
- num: '',
- isLoudVisible: true, // 初始状态为显示
- searchActive: true,
- showModal:false,//选择对方号码部件显示判断
- phoneNumbersCount:'',
- switchStatus:false,
- isChooseNumberVisible:{},
- isActive: false,//点击对方号码,背景加深判断
- };
- },
- onShow() {
- // 页面显示时直接调用
- this.ToGetMessage();
- /* this.ToGetHis(); */
- this.setLanguage();
- this.init();
- this.getM();
- },
- beforeCreate() {
- const domModule = uni.requireNativePlugin('dom')
- domModule.addRule('fontFace', {
- 'fontFamily': "myIconfont",
- 'src': "url('../assets/typeface/almmdfdk.ttf')"
- });
- },
- mounted() {
- this.filteredContacts.forEach(item => {
- this.$set(this.isChooseNumberVisible, item.id, false);
- });
- },
- methods: {
- showChooseNumber(item,phoneNumber){
- console.log("showChooseNumber called");
- console.log(new Error().stack); // 打印当前调用堆栈
- if(item.phoneNumbers.length>1){
- this.$set(this.isChooseNumberVisible,item.id,true)
- console.log("isChooseNumberVisible",this.isChooseNumberVisible)
- }
- else{
- console.log("这里对方只有一个电话号码")
- this.CallPhone(item,phoneNumber)
- }
- },
- toggleActive() {
- this.isActive = !this.isActive;
- },
- handleTouchedStart(){
- this.isActive=true;
- },
- handleTouchedEnd(){
- this.isActive=false;
- },
- toNum(e){
- console.log("num",e);
- this.num=e;
- },
- // 格式化电话号码
- formatPhoneNumber(value) {
- // 移除所有非数字字符
- value = value.replace(/\D/g, '');
-
- if (value.length === 11) {
- // 如果长度为11, 在第4和第9位插入空格
- return value.replace(/(\d{3})(\d{4})(\d{4})/, '$1 $2 $3');
- } else {
- // 如果长度不为11,每4个字符插入一个空格
- return value.replace(/(\d{4})(?=\d)/g, '$1 ');
- }
- },
- formatPhoneNumber1(value) {
- // 移除所有非数字字符
- value = value.replace(/\D/g, '');
-
- if (value.length === 11) {
- // 如果长度为11,在第三位后插入换行符,并在第七位添加空格
- return value.replace(/(\d{3})(\d{4})(\d{4})/, '$1\n$2 $3');
- } else if (value.length > 11) {
- // 如果长度大于11,在第三位后插入换行符,并在第七位添加空格,11位之后显示省略号
- return value.replace(/(\d{3})(\d{4})(\d{4})/, '$1\n$2 $3') + '...';
- } else {
- // 如果长度不为11且小于11位,每4个字符插入一个空格,并在第7位后添加换行符
- // 这个分支可能不需要,因为根据前面的条件,号码长度应该至少为11位
- return value.replace(/(\d{4})(\d{3})/, '$1\n$2').replace(/(\d{4})(?=\d)/g, '$1 ');
- }
- },
- truncate(value) {
- if (value.length > 9) {
- return value.slice(0, 5) + '\n' + value.substring(5, 9) + '...';
- }
- else{
- return value.slice(0, 5) + '\n' + value.substring(5, 9)
- }
- return value;
- },
-
-
- init(){
-
- FvvUniTTS.init((callback) => {
- console.log(callback);
- },"com.iflytek.speechcloud");
-
- FvvUniTTS.onStart((res) => {
- console.log("onStart:" + res)
- });
-
- FvvUniTTS.onDone((res) => {
- console.log("onDone:" + res)
- });
-
- FvvUniTTS.onError((res) => {
- console.log("onError:" + res)
- });
- FvvUniTTS.getInstallTTS(res => {
- console.log(res+"11")
- })
- },
- play(e){
- console.log("xinxi",e)
- FvvUniTTS.speak({
- text:e,
- id:2,
- });
-
- FvvUniTTS.getInstallTTS(res => {
- console.log(res+"11")
- })
- },
- setLanguage(){
- console.log("set lang : " + FvvUniTTS.setLanguage("CHINESE"));
- },
- setEngines(){
- let setEngine = "com.iflytek.speechcloud"
-
- //获取已安装的引擎
- FvvUniTTS.getInstallTTS(res => {
- if(res == null || res.length <= 0){
- return
- }
- console.log(res)
- if(JSON.stringify(res).indexOf(setEngine) < 0){
- console.log("未安装该语音引擎")
- return
- }
- console.log("set engine : " + FvvUniTTS.setEngine(setEngine));
- FvvUniTTS.speak({
- text:"设置成功",
- id:2,
- });
- })
- },
- saveFile(){
- FvvUniTTS.saveAudioFile({
- text:"hello",
- id:3,
- path:"/sdcard/test/1.wav"
- })
- },
- setVoice(){
- FvvUniTTS.setPitch(100)
- FvvUniTTS.setSpeechRate(100)
- },
- navigateToPage(page) {
- switch (page) {
- case 'add':
- // 导航到添加页面
- uni.navigateTo({
- url: '/pages/add/add'
- });
- break;
- case 'setting':
- // 导航到设置页面
- uni.navigateTo({
- url: '/pages/setting/setting'
- });
- break;
- default:
- break;
- }
- },
-
- showBar() {
- this.searchActive = !this.searchActive;
- this.ToGetMessage();
- },
- // 获取联系人信息
- ToGetMessage() {
- var that = this;
- // 获取通讯录对象
- plus.contacts.getAddressBook(plus.contacts.ADDRESSBOOK_PHONE, function(addressbook) {
- addressbook.find(["displayName", "phoneNumbers"], function(contacts) {
- that.list = contacts;
- console.log(that.list)
-
- // 将联系人按自定义规则排序
- that.list.sort(function(a, b) {
- // 检查是否为汉字、英文、数字或符号
- const isChinese = (str) => /^[\u4e00-\u9fa5]+$/.test(str);
- const isEnglish = (str) => /^[A-Za-z]+$/.test(str);
- const isNumber = (str) => /^[0-9]+$/.test(str);
-
- // 获取首字母,如果 displayName 是空,则使用 phoneNumbers 的第一个号码
- let firstCharA = a.displayName ? a.displayName.trim()[0] : a.phoneNumbers[0].value;
- let firstCharB = b.displayName ? b.displayName.trim()[0] : b.phoneNumbers[0].value;
-
- // 将汉字转换为拼音以便比较
- if (isChinese(firstCharA)) {
- firstCharA = pinyin(firstCharA, { style: pinyin.STYLE_FIRST_LETTER })[0][0];
- }
- if (isChinese(firstCharB)) {
- firstCharB = pinyin(firstCharB, { style: pinyin.STYLE_FIRST_LETTER })[0][0];
- }
-
- // 确定排序的优先级
- if (isEnglish(firstCharA) && isEnglish(firstCharB)) {
- // 如果都是英文,按字母顺序排序
- return firstCharA.localeCompare(firstCharB);
- } else if (isChinese(firstCharA) && isChinese(firstCharB)) {
- // 如果都是汉字(已经转换为拼音首字母),按拼音排序
- return firstCharA.localeCompare(firstCharB);
- } else if ((isEnglish(firstCharA) || isChinese(firstCharA)) && (isNumber(firstCharB) || !isEnglish(firstCharB))) {
- // 如果 A 是英文或汉字,而 B 是数字或其他符号,则 A 在前
- return -1;
- } else if ((isNumber(firstCharA) || !isEnglish(firstCharA)) && (isEnglish(firstCharB) || isChinese(firstCharB))) {
- // 如果 A 是数字或其他符号,而 B 是英文或汉字,则 B 在前
- return 1;
- } else {
- // 若是其他情况(如两个字符都为数字或符号),按字符顺序排序
- return firstCharA.localeCompare(firstCharB);
- }
- });
-
- // 更新过滤后的联系人列表
- console.log("list",that.list);
- that.filteredContacts = that.list;
- console.error("更新过滤后的联系人列表",that.filteredContacts)
- }, function() {
- uni.showToast({
- title: '获取联系人失败',
- duration: 2000 // 在屏幕上显示的时间长度
- });
- }, { multiple: true }); // 应该检索多个联系人
- }, function(e) {
- uni.showToast({
- title: '获取通讯录对象失败:' + e.message,
- duration: 2000
- });
- });
- },
- // 拨打电话
- CallPhone(item,e) {
- // 重置所有isChooseNumberVisible状态
- Object.keys(this.isChooseNumberVisible).forEach(key=>{
- this.$set(this.isChooseNumberVisible,key,false);
- });
- console.log("ischooseNumber",this.isChooseNumberVisible)
- // 调用HTML5 Plus框架提供的接口
- plus.device.dial(e, false);
- Object.keys(this.isChooseNumberVisible).forEach(key=>{
- this.$set(this.isChooseNumberVisible,key,false);
- });
- },
- filterContacts() {
- // 获取用户输入的文本,转换为小写
- const searchText = this.searchText.toLowerCase();
- console.log("输入内容",searchText)
- if (!searchText) {
- // 如果用户没有输入,显示所有联系人
- console.log("kong")
- this.filteredContacts = this.list;
-
- } else {
- // 过滤出匹配用户输入的联系人
- this.filteredContacts = this.list.filter(contact => {
- // 模糊查找逻辑:检查 displayName 或 phoneNumbers 是否包含用户输入的文本
- const isFuzzyMatch = (contact.displayName || '').toLowerCase().includes(searchText) ||
- contact.phoneNumbers.some(phone => phone.value.toLowerCase().includes(searchText));
-
- // 拼音首字母查找逻辑:检查拼音首字母序列是否包含用户输入的序列
- const displayNameFirstLetters = getInitials(contact.displayName || '');
- const isInitialsMatch = displayNameFirstLetters.includes(searchText);
-
- // 返回匹配结果,只有当模糊查找或拼音首字母查找任一条件满足时,才包含该联系人
- return isFuzzyMatch || isInitialsMatch;
- });
- }
- },
-
- search() {
- // 可以在这里添加更复杂的搜索逻辑
- this.filterContacts();
- },
- //进行页面跳转到联系人详情
- goToDetails(item){
- console.error('item',item)
- const phoneNumbers=item.phoneNumbers
- const phoneNumbersString=JSON.stringify(phoneNumbers)
- const phoenNumberCount=item.phoneNumbers.length;
- console.error("phonenumber",phoneNumbers)
- console.error("phoenNumberCount",phoenNumberCount)
- uni.navigateTo({
- url: `/pages/ContactDetails/ContactDetails?name=${encodeURIComponent(item.displayName)}&phoneNumbers=${encodeURIComponent(phoneNumbersString)}&count=${phoenNumberCount}`
- });
- },
- getM(){//获取本地语音开关信息
- // 从本地存储中读取开关状态
- const storedSwitchStatus = uni.getStorageSync('voiceBroadcastSwitch');
- console.log("读取的本地存储状态1:", storedSwitchStatus);
-
- if (typeof storedSwitchStatus === 'boolean') {
- this.switchStatus = storedSwitchStatus;
- }
- }
- },
- mounted() {
- this.getM();
- }
- }
- </script>
- <style>
- .floating-button {
- width: 50px; /* 根据需要调整尺寸 */
- height: 300px; /* 根据需要调整尺寸,确保字母列表可以容纳 */
- border-radius: 25px;
- background-color: rgba(0, 0, 0, 0.5);
- position: fixed;
- right: 20px;
- bottom: 20px;
- overflow: hidden; /* 确保内容在按钮范围内 */
- z-index: 1000; /* 一个较高的z-index值,确保它在最上层 */
- }
- .alphabet-scroll {
- width: 100%;
- height: 100%;
- background-color: #fff; /* 根据需要调整背景色 */
- }
- .alphabet-item {
- padding: 5px 10px;
- text-align: center;
- cursor: pointer;
- }
- .alphabet-item.active {
- background-color: #007AFF; /* 高亮颜色 */
- color: #fff;
- }
-
- .notFind{
- font-size: 50rpx;
- }
-
- .null {}
- /* 其他样式保持不变 */
- .uni-column {
- width: 690rpx;
- height: 140rpx;
- border: 1px solid black;
- margin-top: 18rpx;
- border-radius: 20rpx;
- font-size: 50rpx;
- display: flex; /* 使用flex布局 */
- justify-content: space-between; /* 左右分布 */
- /* 其他样式保持不变 */
- }
- .search-input {
- width: 75%;
- /* 可以根据需要调整以下样式 */
- display: flex;
- align-items: center;
- }
- .search-img {
- width: 25%;
- /* 可以根据需要调整以下样式 */
- display: flex;
- border-left: 1px solid black;
- justify-content: center;
- align-items: center;
- }
- .search-input input {
- /* 根据需要调整输入框大小 */
- width: 90%; /* 例如90% */
- height: 90%; /* 例如80% */
- font-size: 50rpx;
- padding: 10px; /* 根据需要调整内边距 */
- }
- .search-img image {
- width: 50%; /* 例如30% */
- height: 50%; /* 保持与输入框一致的高度 */
- font-size: 50rpx;
- }
- .content {
- min-height: 100%;
- display: flex;
- flex-direction: column;
- justify-content: center;
- background-color: #f0efef;
- }
- .con-mes,.con-mes-null {
- font-family: 'FangSong', '仿宋_GB2312', serif;
- font-size: 35px;
- font-weight: 700;
- display: flex;
- align-items: center;
- justify-content: center;
- text-align: center;
- white-space: pre-line; /* 保证换行符有效 */
- word-wrap: break-word; /* 确保长单词换行 */
- width: 410rpx;
- height: 200rpx;
- border: none;
- background-color: white;
- }
- .con-mes-null{
- border-radius: 20rpx 0rpx 0rpx 20rpx;
- width: 510rpx;
- height: 200rpx;
- }
- .name-btn {
- display: flex;
- align-items: center;
- justify-content: space-between;
- width: 690rpx;
- height: 200rpx;
- border: 0.5px solid black;
- margin-top: 8rpx;
- margin-bottom: 10rpx;
- border-radius: 20rpx;
- font-size: 50rpx;
- }
- .text-area {
- padding-top: 145px;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .loud {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100rpx;
- height: 200rpx;
- border-radius: 20rpx 0rpx 0rpx 20rpx;
- background-color: white;
- }
- .btn {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 180rpx;
- height: 200rpx;
- background-color: #ecfff3;
- border-radius: 0rpx 20rpx 20rpx 0rpx;
- }
- .Call {
- width: 100rpx;
- height: 100rpx;
- object-fit: contain;
- }
- .navbar {
- display: flex;
- justify-content: space-around;
- align-items: flex-end;
- width: 100%;
- background-color: #f0efef;
- min-height: 120px;
- padding-bottom: 20px;
- position: fixed; /* 设置为固定定位 */
- top: 0; /* 与页面顶部的距离为0 */
- z-index: 999;
- }
- .icon {
- justify-content: space-around;
- width: 100rpx;
- height: 100rpx;
- }
- .uni-tabbar__iconfont {
- font-size: 50px; /* 自定义字体大小 */
- width: 80px;
- height: 80px;
- }
- .numbers{
- }
- .choose-phonenumber1{
- display: flex;
- align-items: center;
- text-align: center;
- justify-content: center;
- font-size: 80rpx;
- border-left: 5px solid #9ee493;
- border-radius: 6px;
- background-color: white;
- padding: 10px;
- margin-top: 10px;
- margin-bottom: 10px;
-
- }
-
- .scrollable-box {
- height: 700rpx; /* 或者你希望的高度 */
- overflow-y: auto; /* 当内容超出时显示垂直滚动条 */
- scrollbar-width: thin; /* 可选,设置滚动条的宽度 */
- }
- .choose-phonenumber{
- display: flex;
- text-align: center;
- width: 90%;
- align-items: center;
- justify-content: center;
- font-size: 100rpx;
- border-radius: 10px;
- background-color: #c6ffcf;
- padding: 10px;
- margin-top: 10px;
- margin-bottom: 10px;
- }
- .choose-phonenumber.active {
- background-color: #b0b0b0; /* 点击后颜色 */
- }
- .line{
- /*分隔线,宽度、height参数为分隔线的粗细、颜色、上下间隔*/
- width: 100%;
- height: 2rpx;
- background-color: #dbdbdb;
- margin: 9rpx 0;
- }
- /* 悬浮框css */
- movable-view {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 150rpx;
- width: 150rpx;
- background-color: #007AFF;
- color: #fff;
- }
- movable-area {
- height: 300rpx;
- width: 100%;
- background-color: #D8D8D8;
- overflow: hidden;
- }
- .max {
- width:500rpx;
- height: 500rpx;
- }
- </style>
|