添加拨打虚拟号接口

This commit is contained in:
wangxiaowei
2026-04-23 18:50:17 +08:00
parent 93850b98f3
commit 02dca6c329
7 changed files with 60 additions and 354 deletions

View File

@ -9,6 +9,7 @@ VITE_SHOW_SOURCEMAP = true
# 请求地址 # 请求地址
VITE_SERVER_BASEURL = 'https://test1.stnav.com' VITE_SERVER_BASEURL = 'https://test1.stnav.com'
# 图片上传路径 # 图片上传路径
VITE_UPLOAD_BASEURL = 'https://test1.stnav.com/upload' VITE_UPLOAD_BASEURL = 'https://test1.stnav.com/upload'

View File

@ -198,3 +198,10 @@ export function getConfigItem() {
export function updateWorkState(state: number) { export function updateWorkState(state: number) {
return http.Post<any>('/teamapi/user/updateState', {state}) return http.Post<any>('/teamapi/user/updateState', {state})
} }
/**
* 拨打虚拟手机号码
*/
export function callVirtualNumber(order_sn: string) {
return http.Post<any>('/api/order/mobileBind', {order_sn})
}

View File

@ -1,182 +0,0 @@
<route lang="jsonc" type="page">
{
"layout": "default",
"style": {
"navigationStyle": "custom"
}
}
</route>
<template>
<view class="home-bg">
<view class="home-bg w-[100%] fixed top-0 left-0 z-100">
<view>
<navbar custom-class='!bg-[transparent]'></navbar>
</view>
</view>
<view class="pb-200rpx" :style="{ paddingTop: navbarHeight + 'px' }">
<!-- 账号昵称显示 -->
<view class="ml-60rpx flex items-center">
<view>
<wd-img width="120rpx" height="120rpx" :src="`${OSS}icon/icon_avatar.png`" mode="aspectFill" round />
</view>
<view class="flex-1 ml-22rpx flex justify-between items-center">
<view @click="Profile.handleToProfile">
<view class="text-[#303133] text-36rpx leading-50rpx ml-8rpx">昵称名称</view>
<view class="flex justify-center items-center mt-10rpx text-26rpx text-[#675649] font-400 leading-36rpx flex items-center">
13525626532
</view>
</view>
</view>
</view>
<view class="bg-white rounded-t-16rpx mt-46rpx px-30rpx">
<view class="font-bold text-34rpx leading-48rpx text-#303133 pt-36rpx">茶艺师的名字</view>
<view class="">
<wd-rate v-model="rate" readonly active-color="#FF5951" allow-half active-icon="star-filled" icon="star" space="4rpx"/>
</view>
<view class="flex items-center mt-20rpx">
<view class=" mr-20rpx">
<wd-tag color="#FF5951" bg-color="#FEF1F0" custom-class="!rounded-6rpx !px-16rpx !py-4rpx !h-40rpx">90后茶艺师</wd-tag>
</view>
<view class="w-160rpx h-40rpx relative mr-44rpx top-6rpx">
<view class="absolute left-0 top-0 h-36rpx flex items-start">
<wd-img :src="`${OSS}icon/icon_gold_medal.png`" width="36rpx" height="36rpx"></wd-img>
</view>
<view class="bg-[#F0F6EF] text-[#006C2D] font-400 text-22rpx leading-32rpx rounded-4rpx text-center w-150rpx ml-18rpx h-40rpx">金牌茶艺师</view>
</view>
</view>
</view>
<view class="h-2rpx bg-#F6F7F9 mx-30rpx mt-28rpx"></view>
<view class="flex justify-between items-center mx-88rpx text-center mt-30rpx">
<view>
<view class="font-400 text-28rpx leading-40rpx text-#606266">性别</view>
<view class="font-bold text-30rpx leading-42rpx text-#303133 mt-12rpx"></view>
</view>
<view class="w-4rpx h-66rpx bg-#F6F7F9"></view>
<view>
<view class="font-400 text-28rpx leading-40rpx text-#606266">年龄</view>
<view class="font-bold text-30rpx leading-42rpx text-#303133 mt-12rpx">21</view>
</view>
<view class="w-4rpx h-66rpx bg-#F6F7F9"></view>
<view>
<view class="font-400 text-28rpx leading-40rpx text-#606266">身高</view>
<view class="font-bold text-30rpx leading-42rpx text-#303133 mt-12rpx">165cm</view>
</view>
<view class="w-4rpx h-66rpx bg-#F6F7F9"></view>
<view>
<view class="font-400 text-28rpx leading-40rpx text-#606266">体重</view>
<view class="font-bold text-30rpx leading-42rpx text-#303133 mt-12rpx">53kg</view>
</view>
</view>
<view class="flex items-center justify-between mx-30rpx mt-40rpx">
<view>
<wd-img :src="`${OSS}images/reserve_room/reserve_room_image2.png`" width="220rpx" height="240rpx" radius="16rpx"></wd-img>
</view>
<view>
<wd-img :src="`${OSS}images/reserve_room/reserve_room_image2.png`" width="220rpx" height="240rpx" radius="16rpx"></wd-img>
</view>
<view>
<wd-img :src="`${OSS}images/reserve_room/reserve_room_image2.png`" width="220rpx" height="240rpx" radius="16rpx"></wd-img>
</view>
</view>
<!-- 兴趣爱好 -->
<view class="mx-30rpx mt-44rpx">
<view class="font-bold text-32rpx leading-44rpx text-#303133">
兴趣爱好
</view>
<view class="bg-#FBFBFB rounded-8rpx px-28rpx py-20rpx mt-22rpx">
<view class="flex items-center">
<view class="mr-12rpx">
<wd-img :src="`${OSS}icon/icon_tea2.png`" width="32rpx" height="32rpx"></wd-img>
</view>
<view class="font-400 text-26rpx leading-36rpx text-#606266">兴趣爱好</view>
</view>
<view class="mt-20rpx font-400 text-28rpx leading-40rpx text-#303133">
爱好茶艺喜欢旅游把爱好当工作
</view>
</view>
</view>
<view class="h-20rpx bg-#F6F7F9 mt-42rpx mb-40rpx"></view>
<!-- 费用说明 -->
<view class="mx-30rpx mt-44rpx">
<view class="font-bold text-32rpx leading-44rpx text-#303133">
费用说明
</view>
<view class="flex items-center mt-24rpx">
<view class="mr-12rpx flex items-center">
<wd-img :src="`${OSS}icon/icon_billing.png`" width="32rpx" height="32rpx"></wd-img>
</view>
<view class="font-400 text-26rpx leading-36rpx text-#606266">计费标准</view>
</view>
<view class=" mt-22rpx">
<view class="flex items-center justify-between">
<view class="w-8rpx h-8rpx rounded-8rpx bg-#6A6363 mr-14rpx"></view>
<view class="flex-1 flex items-center justify-between font-500 text-26rpx leading-48rpx text-#303133">
<view>服务费</view>
<view>160/小时</view>
</view>
</view>
<view class="flex items-center justify-between mt-20rpx">
<view class="w-8rpx h-8rpx rounded-8rpx bg-#6A6363 mr-14rpx"></view>
<view class="flex-1 flex items-center justify-between font-500 text-26rpx leading-48rpx text-#303133">
<view>车马费</view>
<view>3.00/公里</view>
</view>
</view>
</view>
</view>
</view>
<tabbar tab="my"></tabbar>
</view>
</template>
<script lang="ts" setup>
import Tabbar from '@/bundle/parten/components/Tabbar.vue'
const OSS = inject('OSS')
const navbarHeight = inject('navbarHeight')
// 评分
const rate = ref(4.5)
const Profile = {
handleToProfile: () => {
uni.navigateTo({
url: '/pages/profile/profile'
})
},
handleToMyBank: () => {
uni.navigateTo({
url: '/bundle/parten/pages/my-bank/my-bank'
})
},
handleToFundRecord: () => {
uni.navigateTo({
url: '/bundle/parten/pages/fund-record/fund-record'
})
},
}
</script>
<style lang="scss">
page, home-bg{
background: #fff url(#{$OSS}images/parten/parten_image3.png) 0 0 no-repeat;
background-size: 100%;
}
</style>

View File

@ -1,158 +0,0 @@
<route lang="jsonc" type="page">
{
"layout": "default",
"style": {
"navigationBarBackgroundColor": "#FFF",
"navigationBarTitleText": "下级用户"
}
}
</route>
<template>
<view>
<!-- 展示人员信息 -->
<wd-overlay :show="showProfilePopup" @click="showProfilePopup = false">
<view class="h-full relative pb-62rpx">
<view class="absolute-center bg-white rounded-30rpx w-660rpx px-88rpx py-48rpx">
<view>
<view class="text-center">
<wd-img width="100rpx" height="100rpx" :src="`${OSS}icon/icon_avatar.png`" mode="aspectFill" round />
</view>
<view class="font-bold text-28rpx leading-40rpx text-#303133 mt-16rpx text-center">用户昵称</view>
<view class="mt-10rpx text-center">13525626532</view>
<view class="flex items-center justify-between mt-62rpx">
<view class="text-center">
<view class="font-bold text-36rpx leading-50rpx text-#303133">1200</view>
<view class="font-400 text-26rpx leading-36rpx text-#606266 mt-20rpx">本月下级佣金</view>
</view>
<view class="text-center">
<view class="font-bold text-36rpx leading-50rpx text-#303133">1200</view>
<view class="font-400 text-26rpx leading-36rpx text-#606266 mt-20rpx">本月下级佣金</view>
</view>
</view>
<view class="mt-46rpx">
<text class="font-400 text-26rpx leading-36rpx text-#303133">加入时间</text>
<text class="text-26rpx leading-36rpx text-#909399">2025-03-08 11:20</text>
</view>
</view>
</view>
</view>
</wd-overlay>
<view class="mt-24rpx pb-60rpx">
<view class="mt-20rpx">
<mescroll-body @init="mescrollInit" @down="downCallback" @up="Sub.upCallback">
<view class="mx-30rpx border-b border-b-solid mb-26rpx pb-10rpx flex" v-for="(item, index) in 10" :key="index">
<view class="mr-20rpx" @click="Sub.handleShowProfilePopup">
<wd-img width="100rpx" height="100rpx" :src="`${OSS}icon/icon_avatar.png`" mode="aspectFill" round />
</view>
<view class="flex-1 flex justify-between items-center">
<view @click="Sub.handleToSubPorfile(item)">
<view class="font-bold text-28rpx leading-40rpx text-#303133">用户昵称</view>
<view class="font-400 text-26rpx leading-36rpx text-#303133 mt-12rpx">13525626532</view>
<view class="text-24rpx leading-34rpx text-#909399 mt-10rpx">2025-03-08 11:20</view>
</view>
<view @click="Sub.handleCallMobile">
<wd-img width="64rpx" height="64rpx" :src="`${OSS}icon/icon_phone.png`" mode="aspectFill" round />
</view>
</view>
</view>
</mescroll-body>
</view>
</view>
<tabbar tab="sub"></tabbar>
</view>
</template>
<script lang="ts" setup>
import Tabbar from '@/bundle/parten/components/Tabbar.vue'
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js"
const OSS = inject('OSS')
// mescroll
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
// 展示人员信息
const showProfilePopup = ref<boolean>(false)
// tab 切换
const tab = ref<Array<{ id: number, name: string }>>([
{ id: 1, name: '全部' },
{ id: 2, name: '收入' },
{ id: 3, name: '支出' },
])
const currentTab = ref<number>(0)
const Sub = {
upCallback: (mescroll) => {
// 需要留一下数据为空的时候显示的空数据图标内容
// list({
// page: mescroll.num,
// size: mescroll.size
// }).then((res: { list: Array<any>, totalPages: Number }) => {
// const curPageData = res.list || [] // 当前页数据
// if(mescroll.num == 1) goods.value = []; // 第一页需手动制空列表
// goods.value = goods.value.concat(curPageData); //追加新数据
// console.log("🚀 ~ goods:", goods)
// mescroll.endByPage(curPageData.length, res.totalPages); //必传参数(当前页的数据个数, 总页数)
// }).catch(() => {
// mescroll.endErr(); // 请求失败, 结束加载
// })
// apiGoods(mescroll.num, mescroll.size).then(res=>{
// const curPageData = res.list || [] // 当前页数据
// if(mescroll.num == 1) goods.value = []; // 第一页需手动制空列表
// goods.value = goods.value.concat(curPageData); //追加新数据
// //联网成功的回调,隐藏下拉刷新和上拉加载的状态;
// //mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
// //方法一(推荐): 后台接口有返回列表的总页数 totalPage
// //mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
// //方法二(推荐): 后台接口有返回列表的总数据量 totalSize
// //mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
// //方法三(推荐): 您有其他方式知道是否有下一页 hasNext
// //mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
// //方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
// mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
// }).catch(()=>{
mescroll.endErr(); // 请求失败, 结束加载
// })
},
// 打电话
handleCallMobile: (mobile: number) => {
uni.makePhoneCall({
phoneNumber: '13525626532'
})
},
// 展示人员信息
handleShowProfilePopup: () => {
showProfilePopup.value = true
},
// 去下级用户详情
handleToSubPorfile: (item: any) => {
uni.navigateTo({
url: '/bundle/parten/pages/sub/profile'
})
}
}
</script>
<style lang="scss" scoped>
page {
background: #FFF;
}
</style>

View File

@ -47,7 +47,8 @@
<wd-checkbox v-model="agree" checked-color="#4C9F44" size="large"> </wd-checkbox> <wd-checkbox v-model="agree" checked-color="#4C9F44" size="large"> </wd-checkbox>
</view> </view>
<view class="font-400 text-26rpx leading-40rpx text-[#8F959E] ml-14rpx flex-1" @click="agree = !agree"> <view class="font-400 text-26rpx leading-40rpx text-[#8F959E] ml-14rpx flex-1" @click="agree = !agree">
我已阅读并同意 <text class="text-[#4C9F44]" @click.stop="Login.handleToService">服务协议</text> <text class="text-[#4C9F44]" @click.stop="Login.handleToPrivacy">隐私政策</text>未注册手机号登录后将自动你为您创建账号 我已阅读并同意
<text class="text-[#4C9F44]" @click.stop="Login.handleToService">服务协议</text><text class="text-[#4C9F44]" @click.stop="Login.handleToPrivacy">隐私政策</text><text class="text-[#4C9F44]" @click.stop="Login.handleToAgreement">茶址茶艺师入驻协议</text>未注册手机号登录后将自动你为您创建账号
</view> </view>
</view> </view>
@ -114,7 +115,7 @@
} }
if (!agree.value) { if (!agree.value) {
toast.info('请同意服务协议隐私政策') toast.info('请同意服务协议隐私政策、茶址茶艺师入驻协议')
return return
} }
@ -144,6 +145,31 @@
handleToPrivacy: () => { handleToPrivacy: () => {
router.navigateTo('/pages/webview/webview?type=privacy') router.navigateTo('/pages/webview/webview?type=privacy')
}, },
// 跳转到茶址茶艺师入驻协议页面
handleToAgreement: () => {
const fileUrl = import.meta.env.VITE_SERVER_BASEURL + '/茶址茶艺师入驻协议.docx'
uni.downloadFile({
url: fileUrl,
success: (downloadRes) => {
if (downloadRes.statusCode === 200) {
uni.openDocument({
filePath: downloadRes.tempFilePath,
showMenu: true,
fail: (err) => {
console.error('打开文档失败:', err)
toast.info('打开文档失败,请稍后重试')
}
})
} else {
toast.info('下载协议失败')
}
},
fail: (err) => {
toast.info('下载协议失败,请稍后重试')
}
})
}
} }
</script> </script>

View File

@ -24,7 +24,7 @@
</text> </text>
</view> --> </view> -->
<!-- 设置图标 --> <!-- 设置图标 -->
<view class="nav-icon-item relative mr-24rpx" @click="router.navigateTo('/bundle/store/setting')"> <view class="nav-icon-item relative mr-24rpx" @click="router.navigateTo('/bundle/store/setting')" v-if="setting.status == 1">
<wd-img :src="`${OSS}icon/icon_setting.png`" width="36rpx" height="36rpx"></wd-img> <wd-img :src="`${OSS}icon/icon_setting.png`" width="36rpx" height="36rpx"></wd-img>
<text <text
class="icon-label text-20rpx text-[#606266] top-20rpx"> class="icon-label text-20rpx text-[#606266] top-20rpx">
@ -109,7 +109,7 @@
</view> </view>
<!-- 上班安排区域 --> <!-- 上班安排区域 -->
<view :style="{ <view v-if="setting.status == 1" :style="{
backgroundImage: `url('${OSS}images/chayishi/richeng.png')`, backgroundImage: `url('${OSS}images/chayishi/richeng.png')`,
backgroundSize: 'contain', backgroundSize: 'contain',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
@ -128,7 +128,7 @@
</view> </view>
</view> </view>
<!-- 服务方式 --> <!-- 服务方式 -->
<view class="schedule-item mb-20rpx flex items-center" v-if="setting.status == 1"> <view class="schedule-item mb-20rpx flex items-center">
<text class="label-text w-140rpx text-24rpx text-[#606266] leading-40rpx">服务方式:</text> <text class="label-text w-140rpx text-24rpx text-[#606266] leading-40rpx">服务方式:</text>
<view class="flex flex-1 items-center"> <view class="flex flex-1 items-center">
<view class="mr-16rpx flex items-center"> <view class="mr-16rpx flex items-center">
@ -169,7 +169,7 @@
</view> </view>
<!-- 更多服务区域 --> <!-- 更多服务区域 -->
<view class="more-services-section mx-30rpx mt-30rpx rounded-24rpx bg-white p-30rpx"> <view v-if="setting.status == 1" class="more-services-section mx-30rpx mt-30rpx rounded-24rpx bg-white p-30rpx">
<text class="mb-24rpx block text-32rpx text-[#303133] font-bold leading-44rpx">更多服务</text> <text class="mb-24rpx block text-32rpx text-[#303133] font-bold leading-44rpx">更多服务</text>
<view class="services-grid grid grid-cols-4 gap-10rpx"> <view class="services-grid grid grid-cols-4 gap-10rpx">
<!-- 个人介绍 --> <!-- 个人介绍 -->

View File

@ -268,9 +268,15 @@
<text class="info-value">{{ order.hours }}小时</text> <text class="info-value">{{ order.hours }}小时</text>
</view> </view>
<view class="info-item"> <view class="info-item" @click="Detail.handleCall(order.order_sn)"
<text class="info-label">用户联系方式:</text> v-if="orderStatus === TeaSpecialistOrderStatus.Pending || orderStatus === TeaSpecialistOrderStatus.Accepted || orderStatus === TeaSpecialistOrderStatus.Departed"
<text class="info-value" @click="Detail.handleCall(order.user_mobile)">{{ order.user_mobile }}</text> >
<view class="info-label">用户联系方式:</view>
<view class="flex items-center">
<wd-img :src="`${OSS}icon/icon_phone2.png`" width="32rpx" height="32rpx"></wd-img>
</view>
<!-- <wd-icon name="call" size="32px"></wd-icon> -->
<!-- <text class="info-value" @click="Detail.handleCall(order.order_sn)">{{ order.user_mobile }}</text> -->
</view> </view>
<view class="info-item" v-if="order.group_name"> <view class="info-item" v-if="order.group_name">
@ -466,6 +472,7 @@
import { router, copy } from '@/utils/tools' import { router, copy } from '@/utils/tools'
import { TeaSpecialistOrderStatus, TeaSpecialistManageStatusTextValue } from '@/utils/teaSpecialistOrder' import { TeaSpecialistOrderStatus, TeaSpecialistManageStatusTextValue } from '@/utils/teaSpecialistOrder'
import { getTeaSpecialistOrderDetails, getTeaSpecialistCostDetails } from '@/api/tes-specialist' import { getTeaSpecialistOrderDetails, getTeaSpecialistCostDetails } from '@/api/tes-specialist'
import { callVirtualNumber } from '@/api/user'
import { import {
handleReleaseOrderHooks, handleReleaseOrderHooks,
handleDepartOrderHooks, handleDepartOrderHooks,
@ -475,6 +482,7 @@
handleDeleteOrderHooks, handleDeleteOrderHooks,
handleRefuseOrderHooks handleRefuseOrderHooks
} from '@/hooks/useOrder' } from '@/hooks/useOrder'
import { resolve } from 'path'
const OSS = inject('OSS') const OSS = inject('OSS')
const toast = useToast() const toast = useToast()
@ -826,12 +834,16 @@
}, },
// 拨打手机号 // 拨打手机号
handleCall: (phone: string) => { handleCall: async (order: any) => {
const res = await callVirtualNumber(order)
console.log("🚀 ~ res:", res)
if (res) {
uni.makePhoneCall({ uni.makePhoneCall({
phoneNumber: phone, phoneNumber: res.mobile,
}) })
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">