修改登录页样式、车牌号输入问题、定位加载问题、联系物业权限问题

This commit is contained in:
zhouyanli
2026-05-23 16:44:29 +08:00
parent 6b520fb70e
commit c4d91787b5
14 changed files with 278 additions and 81 deletions

View File

@@ -1,9 +1,9 @@
{
"name" : "uniapp-project-test",
"appid" : "",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"name" : "花开物业用户端app",
"appid" : "__UNI__29C3D60",
"description" : "物业用户端app",
"versionName" : "1.0.1",
"versionCode" : "101",
"transformPx" : false,
/* 5+App */
"app-plus" : {
@@ -17,7 +17,10 @@
"delay" : 0
},
/* */
"modules" : {},
"modules" : {
"Geolocation" : {},
"Maps" : {}
},
/* */
"distribute" : {
/* android */
@@ -37,13 +40,31 @@
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>"
]
},
/* ios */
"ios" : {},
"ios" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {}
"sdkConfigs" : {
"geolocation" : {
"system" : {
"__platform__" : [ "ios", "android" ]
}
},
"maps" : {
"amap" : {
"name" : "玉米汁穿过三峡人家",
"appkey_ios" : "39a4c28a01c3ec15684b21d4093aad3d",
"appkey_android" : "044055aed47cb305e86419fd82e4c5f3"
}
}
}
}
},
/* */
@@ -54,18 +75,15 @@
"setting" : {
"urlCheck" : false
},
"requiredPrivateInfos": [
"chooseLocation",
"getLocation"
],
"permission": {
"scope.camera": {
"desc": "用于扫码"
},
"scope.userLocation": {
"desc": "你的位置信息将用于定位选择"
}
},
"requiredPrivateInfos" : [ "chooseLocation", "getLocation" ],
"permission" : {
"scope.camera" : {
"desc" : "用于扫码"
},
"scope.userLocation" : {
"desc" : "你的位置信息将用于定位选择"
}
},
"usingComponents" : true
},
"mp-alipay" : {

View File

@@ -65,7 +65,7 @@
<up-row justify="space-between" customStyle="margin-bottom: 10px">
<up-col span="4">
<view class="info-image-left">
<image :src="activity.coverImage" style="width: 100%;height: 100%;border-radius: 16rpx;"></image>
<image :src="activity.coverImage" mode="aspectFit" style="width: 100%;height: 100%;border-radius: 16rpx;"></image>
</view>
</up-col>
<up-col span="8">

View File

@@ -58,6 +58,9 @@ import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { addActivityLive, signinActivityLive, uploadFile } from '../api/api.js';
// 高德地图 Web API Key用于逆地址解析需要去 https://lbs.amap.com 申请免费 Key
const AMAP_KEY = 'f362f595be12ab7d84bd502b48b30d2a';
// 活动ID
const activityId = ref('');
// 实况描述内容
@@ -82,6 +85,29 @@ const handleTextInput = (e) => {
currentLength.value = e.detail.value.length;
};
// 逆地址解析(坐标转地址)
const reverseGeocode = async (lng, lat) => {
if (!AMAP_KEY) return null;
try {
const [err, res] = await uni.request({
url: 'https://restapi.amap.com/v3/geocode/regeo',
data: {
key: AMAP_KEY,
location: `${lng},${lat}`,
extensions: 'base'
}
});
if (err) throw err;
if (res.data?.status === '1' && res.data.regeocode?.formatted_address) {
return res.data.regeocode.formatted_address;
}
return null;
} catch (e) {
console.error('逆地址解析失败:', e);
return null;
}
};
// 选择图片
const chooseImg = () => {
uni.chooseImage({
@@ -103,43 +129,92 @@ const chooseImg = () => {
imgList.value.splice(index, 1);
};
// 重新定位
// 定位并获取具体地点名称
// 检查 App 端定位权限Android/iOS
const checkAppLocationPermission = () => {
// #ifdef APP-PLUS
try {
const platform = uni.getSystemInfoSync().platform;
if (platform === 'android') {
const main = plus.android.runtimeMainActivity();
const PackageManager = plus.android.importClass('android.content.pm.PackageManager');
return main.checkSelfPermission('android.permission.ACCESS_FINE_LOCATION') === PackageManager.PERMISSION_GRANTED;
}
if (platform === 'ios') {
const CLAuthorizationStatus = plus.ios.importClass('CLAuthorizationStatus');
const CLLocationManager = plus.ios.importClass('CLLocationManager');
return CLLocationManager.authorizationStatus() !== 2; // 2 = denied
}
} catch (e) {
console.error('检查权限失败', e);
}
// #endif
return true; // 非 App 端默认通过
};
// 跳转系统设置App 端)
const openAppSettings = () => {
// #ifdef APP-PLUS
const platform = uni.getSystemInfoSync().platform;
if (platform === 'android') {
const Intent = plus.android.importClass('android.content.Intent');
const Settings = plus.android.importClass('android.provider.Settings');
const Uri = plus.android.importClass('android.net.Uri');
const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse('package:' + plus.runtime.packageName));
plus.android.runtimeMainActivity().startActivity(intent);
} else if (platform === 'ios') {
const UIApplication = plus.ios.importClass('UIApplication');
const app = UIApplication.sharedApplication();
const NSURL = plus.ios.importClass('NSURL');
const url = NSURL.URLWithString('app-settings:');
app.openURL(url);
}
// #endif
};
// 重新定位(获取当前位置 + 逆地址解析)
const reLocate = () => {
// 调用微信原生选择位置接口(自带地址解析,无调用上限)
uni.chooseLocation({
success: (res) => {
// res.address = 具体地址XX市XX区XX街道XX小区
// res.name = 地点名称XX小区
// App 端先检查权限,无权限直接引导设置
// #ifdef APP-PLUS
if (!checkAppLocationPermission()) {
uni.showModal({
title: '需要定位权限',
content: '请前往系统设置中允许本应用使用定位权限',
confirmText: '去设置',
success: (res) => {
if (res.confirm) openAppSettings();
}
});
return;
}
// #endif
uni.showLoading({ title: '正在定位...', mask: true });
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
success: async (res) => {
longitude.value = res.longitude;
latitude.value = res.latitude;
location.value = res.address; // 显示具体地址
uni.showToast({ title: `定位成功:${res.name}`, icon: 'success' });
// 逆地址解析
const address = await reverseGeocode(res.longitude, res.latitude);
location.value = address || `${res.longitude.toFixed(6)}, ${res.latitude.toFixed(6)}`;
uni.hideLoading();
},
fail: (err) => {
// 处理权限拒绝/定位失败
if (err.errMsg.includes('auth deny')) {
uni.hideLoading();
const errMsgStr = err?.errMsg || err?.message || JSON.stringify(err);
console.error('定位失败:', err);
if (err?.code === -22 || /权限|auth|deny|permission/i.test(errMsgStr)) {
uni.showModal({
title: '需要定位权限',
content: '请允许获取位置信息以显示具体地点',
confirmText: '去设置',
success: (modalRes) => {
if (modalRes.confirm) {
uni.openSetting({
success: (settingRes) => {
// 用户开启权限后重新定位
if (settingRes.authSetting['scope.userLocation']) {
reLocate();
}
}
});
}
}
success: (res) => { if (res.confirm) openAppSettings(); }
});
} else {
uni.hideLoading();
uni.showToast({ title: '定位失败,请重试', icon: 'none' });
// console.error('定位失败:', err);
uni.showToast({ title: `定位失败:${errMsgStr}`, icon: 'none', duration: 3000 });
}
}
});

View File

@@ -60,7 +60,7 @@ export default function request(url, data = {}, method = "GET") {
});
}
export const get = (url, data) => request(url, data, 'GET');
export const get = (url, data = {}) => request(url, data, 'GET');
export const post = (url, data) => request(url, data, 'POST');
export const deleteMethod = (url, data) => request(url, data, 'DELETE');
export const putMethod = (url, data) => request(url, data, 'PUT');

View File

@@ -157,6 +157,21 @@ const handleConfirm = () => {
height: 100%;
}
/* 深度覆盖 uni-easyinput 内部默认样式,解决高度偏移 */
.input-content :deep(.uni-easyinput__content) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
background-color: transparent !important;
}
.input-content :deep(.uni-easyinput__content-input) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
line-height: 88rpx;
}
/* 确定按钮 */
.confirm-btn {
width: 100%;

View File

@@ -187,6 +187,22 @@ const goBack = () => {
color: #333;
height: 100%;
}
/* 深度覆盖 uni-easyinput 内部默认样式,解决高度偏移 */
.input-content :deep(.uni-easyinput__content) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
background-color: transparent !important;
}
.input-content :deep(.uni-easyinput__content-input) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
line-height: 88rpx;
}
.verify-input {
padding-right: 20rpx;
}
@@ -231,7 +247,7 @@ const goBack = () => {
color: #fff;
}
/* 禁用按钮边框 */
button:after{
.forget-btn:after{
border-radius: 8px;
}

View File

@@ -302,6 +302,21 @@ onUnmounted(() => {
height: 100%;
}
/* 深度覆盖 uni-easyinput 内部默认样式,解决高度偏移 */
.input-content :deep(.uni-easyinput__content) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
background-color: transparent !important;
}
.input-content :deep(.uni-easyinput__content-input) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
line-height: 88rpx;
}
/* 验证码输入框 */
.verify-input {
padding-right: 20rpx;

View File

@@ -160,6 +160,7 @@ const handleLogin = () => {
}
}).catch(err => {
// console.log(err)
uni.showToast({
title: err.msg || '网络异常',
icon: 'error'
@@ -212,6 +213,21 @@ const handleLogin = () => {
height: 100%;
}
/* 深度覆盖 uni-easyinput 内部默认样式,解决高度偏移 */
.input-content :deep(.uni-easyinput__content) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
background-color: transparent !important;
}
.input-content :deep(.uni-easyinput__content-input) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
line-height: 88rpx;
}
.agreement-wrap {
display: flex;
justify-content: space-between;

View File

@@ -358,6 +358,21 @@
height: 100%;
}
/* 深度覆盖 uni-easyinput 内部默认样式,解决高度偏移 */
.input-content :deep(.uni-easyinput__content) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
background-color: transparent !important;
}
.input-content :deep(.uni-easyinput__content-input) {
height: 100% !important;
min-height: unset !important;
padding: 0 !important;
line-height: 88rpx;
}
.verify-input {
padding-right: 20rpx;
}

View File

@@ -8,14 +8,14 @@
class="search-input"
placeholder="请输入关键字进行搜索"
placeholder-class="placeholder"
v-model="searchText"
:value="searchText"
@input="handleSearchInput"
/>
<view v-if="searchText" class="clear-icon" @tap="clearSearch">
<uni-icons type="clear" size="18" color="#999"></uni-icons>
</view>
</view>
<button class="search-btn" @tap="handleSearch">搜索</button>
<!-- <button class="search-btn" @tap="handleSearch">搜索</button> -->
</view>
<!-- 小区列表 -->
@@ -103,7 +103,7 @@ const currentVillageIdFromHome = ref('') // 首页传入的当前选中小区ID
// 分页相关
const currentPage = ref(1)
const pageSize = 5
const pageSize = 10
const totalCount = ref(0)
const displayedCommunities = ref([])
const hasMoreData = ref(true)
@@ -119,6 +119,7 @@ const getCommunityList = async (pageNum = 1, keyword = '') => {
isLoading.value = true
try {
keyword = decodeURIComponent(keyword)
const params = {
pageNum,
pageSize,
@@ -188,22 +189,19 @@ const loadMoreData = () => {
}
// 处理搜索输入(防抖)
const handleSearchInput = () => {
const handleSearchInput = (e) => {
let val = e.detail.value || ''
searchText.value = val
if (searchTimeout) {
clearTimeout(searchTimeout)
}
searchTimeout = setTimeout(() => {
handleSearch()
currentPage.value = 1
isSearching.value = !!val.trim()
getCommunityList(1, val.trim())
}, 300)
}
// 处理搜索
const handleSearch = () => {
const keyword = searchText.value.trim()
isSearching.value = !!keyword
currentPage.value = 1
getCommunityList(1, keyword)
}
// 清空搜索
const clearSearch = () => {
@@ -274,13 +272,6 @@ const handleConfirm = async () => {
}
}
// 监听搜索文本变化
watch(searchText, (newVal) => {
if (!newVal.trim()) {
clearSearch()
}
})
// 初始化
onMounted(() => {
if (displayedCommunities.value.length === 0 && !isLoading.value) {

View File

@@ -8,7 +8,7 @@
<!-- 表单区域 -->
<scroll-view class="page" scroll-y="true">
<view v-if="dataList.length === 0" class="empty-state">
<uni-icons type="info" size="60" color="#ccc"></uni-icons>
<uni-icons type="info" size="30" color="#ccc"></uni-icons>
<text class="empty-text">
{{ '暂无数据'}}
</text>
@@ -28,10 +28,9 @@
</view>
</view>
<!-- 值班电话 -->
<view class="phone-item" v-for="phoneItems,phoneIndex in item.phoneList" :key="phoneIndex" @click="callPhone(phoneItems.phoneNum)">
<view class="phone-item" v-for="phoneItems,phoneIndex in item.phoneList" :key="phoneIndex" @click="callPhone(phoneItems.phoneNum)" @longpress="copyPhone(phoneItems.phoneNum)">
<text class="phone-label">值班电话</text>
<text class="phone-num">{{phoneItems.phoneNum}}</text>
<!-- <text class="phone-icon"></text> -->
<uni-icons type="phone" size="16" color="#2F77FD"></uni-icons>
</view>
</view>
@@ -52,13 +51,39 @@ import { getManagePhoneData } from '../api/apiSub.js'
// ====方法=====
function callPhone(phone) {
if (!phone || !phone.trim()) {
uni.showToast({ title: '电话号码为空', icon: 'none' });
return;
}
const cleanPhone = phone.replace(/-/g, '').trim();
if (!/^1[3-9]\d{9}$/.test(cleanPhone) && !/^0\d{2,3}-?\d{7,8}$/.test(cleanPhone)) {
uni.showToast({ title: '电话号码格式有误', icon: 'none' });
return;
}
uni.makePhoneCall({
phoneNumber: phone.replace(/-/g, ""),
phoneNumber: cleanPhone,
fail: (err) => {
console.log('用户取消拨号', err)
console.log('拨号失败或用户取消', err);
uni.showToast({ title: '拨号失败,请长按复制号码', icon: 'none' });
}
});
}
});
}
function copyPhone(phone) {
if (!phone || !phone.trim()) {
uni.showToast({ title: '电话号码为空', icon: 'none' });
return;
}
uni.setClipboardData({
data: phone.replace(/-/g, '').trim(),
success: () => {
uni.showToast({ title: '号码已复制', icon: 'none' });
},
fail: () => {
uni.showToast({ title: '复制失败', icon: 'none' });
}
});
}
function goBack() {
uni.switchTab({
url: '/pages/serviceIndex/serviceIndex',
@@ -117,7 +142,7 @@ import { getManagePhoneData } from '../api/apiSub.js'
}
.empty-text {
font-size: 32rpx;
font-size: 28rpx;
color: #999;
margin-top: 20rpx;
margin-bottom: 10rpx;

View File

@@ -12,7 +12,7 @@
<scroll-view class="page" scroll-y>
<view class="list-container">
<view v-if="currentList.length === 0" class="empty-state">
<uni-icons type="info" size="60" color="#ccc"></uni-icons>
<uni-icons type="info" size="30" color="#ccc"></uni-icons>
<text class="empty-text">暂无数据</text>
</view>
@@ -256,7 +256,7 @@
}
.empty-text {
font-size: 32rpx;
font-size: 28rpx;
color: #999;
margin-top: 20rpx;
margin-bottom: 10rpx;

View File

@@ -58,6 +58,8 @@
<view class="car-number-wrap">
<input class="car-input" v-for="(item, index) in 8" :key="index"
:value="form.carNumber[index]" @input="(e) => onCarInput(index, e)"
:focus="carFocusIndex === index"
@focus="carFocusIndex = index"
type="text" />
</view>
</view>
@@ -170,6 +172,9 @@
const addressModalRef = ref(null);
const genderModalRef = ref(null);
// 车牌号输入框聚焦索引
const carFocusIndex = ref(0);
// =========方法===========
// 获取房屋列表
const fetchHouseList = async () => {
@@ -228,7 +233,13 @@
// 车牌号单格输入
const onCarInput = (index, e) => {
const val = (e.detail && e.detail.value !== undefined) ? e.detail.value : (e.target ? e.target.value : '');
form.carNumber[index] = (val || '').toUpperCase().slice(0, 1);
const upperVal = (val || '').toUpperCase().slice(0, 1);
form.carNumber[index] = upperVal;
// 输入一位后自动聚焦到下一个
if (upperVal && index < 7) {
carFocusIndex.value = index + 1;
}
};
// 时间校验

View File

@@ -131,7 +131,7 @@
<up-row justify="space-between" customStyle="margin-bottom: 10px">
<up-col span="4">
<view class="demo-layout bg-purple-light activity-img">
<image :src="activity.coverImage" style="width: 100%;height: 100%;"></image>
<image :src="activity.coverImage" style="width: 100%;height: 100%;" mode="aspectFit"></image>
</view>
</up-col>
<up-col span="8">