添加逻辑并测试连接数据库
This commit is contained in:
293
pages/mall/delivery/about.uvue
Normal file
293
pages/mall/delivery/about.uvue
Normal file
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<view class="about-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="header-bar">
|
||||
<!-- 左侧:返回按钮 -->
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">←</text>
|
||||
</view>
|
||||
|
||||
<!-- 中部:页面标题 -->
|
||||
<text class="page-title">关于我们</text>
|
||||
|
||||
<!-- 右侧:留空 -->
|
||||
<view class="nav-right"></view>
|
||||
</view>
|
||||
|
||||
<!-- 主要内容 -->
|
||||
<view class="content-wrapper">
|
||||
<!-- Logo 区域 -->
|
||||
<view class="logo-section">
|
||||
<image src="/static/logo.png" class="app-logo" mode="aspectFit" />
|
||||
</view>
|
||||
|
||||
<!-- 版本信息 -->
|
||||
<view class="version-info">
|
||||
<text class="version-text">版本: v2.1.5</text>
|
||||
</view>
|
||||
|
||||
<!-- 应用介绍 -->
|
||||
<view class="app-intro">
|
||||
<text class="intro-title">快递配送助手</text>
|
||||
<text class="intro-desc">专为配送员打造的一站式智能配送平台,提升效率,优化服务体验</text>
|
||||
</view>
|
||||
|
||||
<!-- 功能亮点 -->
|
||||
<view class="feature-section">
|
||||
<text class="section-header">核心功能</text>
|
||||
<view class="features">
|
||||
<view class="feature-item">
|
||||
<text class="feature-icon">📍</text>
|
||||
<text class="feature-text">智能路线规划</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-icon">📱</text>
|
||||
<text class="feature-text">实时订单管理</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-icon">💰</text>
|
||||
<text class="feature-text">在线结算系统</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-icon">⭐</text>
|
||||
<text class="feature-text">客户评价反馈</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 公司信息 -->
|
||||
<view class="company-info">
|
||||
<text class="section-header">公司信息</text>
|
||||
<text class="info-item">公司名称: 快递科技有限公司</text>
|
||||
<text class="info-item">成立时间: 2020年</text>
|
||||
<text class="info-item">总部地点: 深圳市南山区科技园</text>
|
||||
<text class="info-item">联系电话: 400-123-4567</text>
|
||||
<text class="info-item">邮箱: support@delivery.com</text>
|
||||
</view>
|
||||
|
||||
<!-- 更新日志 -->
|
||||
<view class="update-log">
|
||||
<text class="section-header">近期更新</text>
|
||||
<view class="log-item">
|
||||
<text class="log-version">v2.1.5 (2026-01-27)</text>
|
||||
<text class="log-desc">• 修复了地图定位精度问题\n• 优化了任务分配算法\n• 提升了语音播报稳定性</text>
|
||||
</view>
|
||||
<view class="log-item">
|
||||
<text class="log-version">v2.1.4 (2026-01-15)</text>
|
||||
<text class="log-desc">• 新增智能语音助手功能\n• 改进了路线导航算法\n• 修复了部分UI显示异常</text>
|
||||
</view>
|
||||
<view class="log-item">
|
||||
<text class="log-version">v2.1.3 (2025-12-28)</text>
|
||||
<text class="log-desc">• 新增客户满意度评价\n• 优化了离线地图功能\n• 增强了数据同步机制</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 版权信息 -->
|
||||
<view class="copyright">
|
||||
<text class="copyright-text">© 2020-2026 快递科技有限公司 版权所有</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
export default {
|
||||
methods: {
|
||||
// 返回上一页
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.about-container {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 100vh;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #e9ecef;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 10rpx;
|
||||
border-radius: 8rpx;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-left:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.nav-left:active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
flex: 1; /* 让标题占据中间剩余空间 */
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
width: 60rpx; /* 与左侧箭头区域宽度一致 */
|
||||
height: 1rpx;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 40rpx 30rpx;
|
||||
gap: 40rpx;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.app-logo {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: #e3f2fd;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.version-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.version-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
background-color: #e8f4fd;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
|
||||
.app-intro {
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.intro-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 15rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.intro-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.feature-section, .company-info, .update-log {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 15rpx;
|
||||
width: 40rpx;
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
font-size: 26rpx;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.company-info .info-item {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 15rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.update-log {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 25rpx;
|
||||
}
|
||||
|
||||
.log-item {
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.log-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.log-version {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.log-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.copyright-text {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,3 @@
|
||||
✅ 明白了!你不需要完整代码,而是希望我**用简洁的 Markdown 文档形式,解释这个 `delivery` 文件夹下的项目结构和每个页面的功能定位**。
|
||||
|
||||
---
|
||||
|
||||
# 🚚 配送端模块项目结构说明(`/pages/mall/delivery/`)
|
||||
|
||||
> 本模块为配送员使用的移动端应用核心功能区,涵盖个人中心、任务管理、收入统计、车辆管理等核心功能。
|
||||
@@ -25,7 +21,6 @@ delivery/
|
||||
├── vehicle.uvue # 车辆管理主页
|
||||
├── vehicle-add.uvue # 添加车辆
|
||||
├── vehicle-edit.uvue # 编辑车辆信息
|
||||
└── index.uvue # 首页(与上面重复?应统一命名)
|
||||
```
|
||||
|
||||
> 💡 注:`index.uvue` 出现两次,建议保留一个作为首页入口,另一个可重命名为 `dashboard.uvue` 或 `home.uvue`
|
||||
@@ -171,7 +166,6 @@ index.uvue
|
||||
|
||||
| 问题 | 建议 |
|
||||
|------|------|
|
||||
| `index.uvue` 重复 | 重命名为 `dashboard.uvue` 或 `home.uvue` |
|
||||
| 页面间参数传递 | 使用 `uni.navigateTo({ url: '?param=value' })` 并在 `onLoad` 中接收 |
|
||||
| UTS 语法兼容性 | 如遇问题,可临时改用标准 TS 语法调试 |
|
||||
|
||||
|
||||
451
pages/mall/delivery/feedback.uvue
Normal file
451
pages/mall/delivery/feedback.uvue
Normal file
@@ -0,0 +1,451 @@
|
||||
<template>
|
||||
<view class="feedback-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="header-bar">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">←</text>
|
||||
</view>
|
||||
<text class="page-title">意见反馈</text>
|
||||
<view class="nav-right"></view>
|
||||
</view>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-wrapper">
|
||||
<!-- 问题类型 -->
|
||||
<view class="form-item">
|
||||
<text class="label">问题类型</text>
|
||||
<picker mode="selector" :range="feedbackTypes" @change="onTypeChange" :value="selectedTypeIndex">
|
||||
<view class="picker-input">{{ feedbackTypes[selectedTypeIndex] }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<view class="form-item">
|
||||
<text class="label">标题</text>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="请简要描述问题"
|
||||
v-model="title"
|
||||
class="input-field"
|
||||
maxlength="50"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 内容 -->
|
||||
<view class="form-item">
|
||||
<text class="label">详细内容</text>
|
||||
<textarea
|
||||
placeholder="请描述具体问题、发生时间、订单号等信息(至少10字)"
|
||||
v-model="content"
|
||||
class="textarea-field"
|
||||
maxlength="500"
|
||||
auto-height
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 上传截图(可选) -->
|
||||
<view class="form-item">
|
||||
<text class="label">上传截图(可选)</text>
|
||||
<view class="upload-area" @click="chooseImage">
|
||||
<text class="upload-icon">🖼️</text>
|
||||
<text class="upload-text">点击上传截图</text>
|
||||
<text class="upload-tip">支持 JPG/PNG,最多3张</text>
|
||||
</view>
|
||||
|
||||
<!-- 已上传图片预览 -->
|
||||
<view class="preview-list" v-if="previewImages.length > 0">
|
||||
<view class="preview-item" v-for="(img, index) in previewImages" :key="index">
|
||||
<image :src="img" class="preview-img" mode="aspectFill" />
|
||||
<text class="remove-btn" @click="removeImage(index)">×</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 关联订单号(下拉选择) -->
|
||||
<view class="form-item">
|
||||
<text class="label">关联订单号(可选)</text>
|
||||
<picker mode="selector" :range="orderOptions" @change="onOrderChange" :value="selectedOrderIndex">
|
||||
<view class="picker-input">
|
||||
{{ selectedOrderIndex === -1 ? '请选择订单' : orderOptions[selectedOrderIndex] }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-section">
|
||||
<button
|
||||
class="submit-btn"
|
||||
:disabled="!isValid || isSubmitting"
|
||||
@click="submitFeedback"
|
||||
>
|
||||
{{ isSubmitting ? '提交中...' : '提交反馈' }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部提示 -->
|
||||
<view class="footer-tip">
|
||||
<text>您的反馈将被优先处理,我们将在24小时内回复</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 表单数据
|
||||
title: '',
|
||||
content: '',
|
||||
selectedTypeIndex: 0,
|
||||
selectedOrderIndex: -1, // -1 表示未选择
|
||||
previewImages: [] as string[],
|
||||
|
||||
// 配置
|
||||
feedbackTypes: [
|
||||
'订单问题',
|
||||
'配送异常',
|
||||
'系统故障',
|
||||
'账号/认证问题',
|
||||
'车辆/设备问题',
|
||||
'收入结算问题',
|
||||
'其他'
|
||||
],
|
||||
|
||||
// 模拟历史订单(实际项目中应从接口获取)
|
||||
orders: [
|
||||
{ id: 'ORD20250122001', status: '已完成', created_at: '2025-01-22 14:30' },
|
||||
{ id: 'ORD20250122002', status: '配送中', created_at: '2025-01-22 13:15' },
|
||||
{ id: 'ORD20250122003', status: '已取消', created_at: '2025-01-22 10:45' },
|
||||
{ id: 'ORD20250122004', status: '待接单', created_at: '2025-01-22 09:20' }
|
||||
],
|
||||
|
||||
isSubmitting: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 订单选项:格式为 "ORDxxx - 状态 - 时间"
|
||||
orderOptions() {
|
||||
if (this.orders.length === 0) return ['无可用订单']
|
||||
return this.orders.map(order =>
|
||||
`${order.id} - ${order.status} - ${order.created_at.split(' ')[0]}`
|
||||
)
|
||||
},
|
||||
|
||||
isValid() {
|
||||
return this.title.trim().length >= 2 &&
|
||||
this.content.trim().length >= 10 &&
|
||||
this.selectedTypeIndex >= 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
|
||||
onTypeChange(e: UniEvent<HTMLInputElement>) {
|
||||
this.selectedTypeIndex = e.detail.value as number
|
||||
},
|
||||
|
||||
onOrderChange(e: UniEvent<HTMLInputElement>) {
|
||||
const index = e.detail.value as number
|
||||
this.selectedOrderIndex = index
|
||||
// 如果选择了有效订单,自动填充 orderId 字段(可选)
|
||||
if (index >= 0 && index < this.orders.length) {
|
||||
// 实际业务中可绑定 order.id 到某个字段,此处仅作示意
|
||||
} else {
|
||||
// 未选择时清空
|
||||
}
|
||||
},
|
||||
|
||||
chooseImage() {
|
||||
if (this.previewImages.length >= 3) {
|
||||
uni.showToast({
|
||||
title: '最多上传3张图片',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.chooseImage({
|
||||
count: 3 - this.previewImages.length,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const tempFilePaths = res.tempFilePaths
|
||||
const newImages = [...this.previewImages, ...tempFilePaths]
|
||||
if (newImages.length > 3) {
|
||||
this.previewImages = newImages.slice(0, 3)
|
||||
} else {
|
||||
this.previewImages = newImages
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
removeImage(index: number) {
|
||||
this.previewImages.splice(index, 1)
|
||||
},
|
||||
|
||||
submitFeedback() {
|
||||
if (!this.isValid) {
|
||||
let errorMsg = ''
|
||||
if (this.title.trim().length < 2) {
|
||||
errorMsg = '请填写标题(至少2字)'
|
||||
} else if (this.content.trim().length < 10) {
|
||||
errorMsg = '请填写详细内容(至少10字)'
|
||||
} else if (this.selectedTypeIndex < 0) {
|
||||
errorMsg = '请选择问题类型'
|
||||
}
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isSubmitting) return
|
||||
|
||||
this.isSubmitting = true
|
||||
|
||||
// 模拟提交
|
||||
uni.showLoading({ title: '提交中...' })
|
||||
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '反馈已提交成功!',
|
||||
icon: 'success'
|
||||
})
|
||||
// 1.5秒后返回上一页
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.feedback-container {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 100vh;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
/* 顶部导航 */
|
||||
.header-bar {
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #e9ecef;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 10rpx;
|
||||
border-radius: 8rpx;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-left:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.nav-left:active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
width: 60rpx;
|
||||
height: 1rpx;
|
||||
}
|
||||
|
||||
/* 表单区域 */
|
||||
.form-wrapper {
|
||||
padding: 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 输入框统一样式 */
|
||||
.input-field,
|
||||
.textarea-field,
|
||||
.picker-input {
|
||||
width: 100%;
|
||||
padding: 20rpx 24rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
background-color: #fafafa;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.textarea-field {
|
||||
min-height: 180rpx;
|
||||
height: auto;
|
||||
padding: 24rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.picker-input {
|
||||
background-color: #fff;
|
||||
text-align: right;
|
||||
color: #666;
|
||||
padding-right: 40rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.picker-input::after {
|
||||
content: '▼';
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 上传区域 */
|
||||
.upload-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx 20rpx;
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
border-radius: 16rpx;
|
||||
background-color: #f8f9fa;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: #74b9ff;
|
||||
background-color: #e8f4fd;
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
font-size: 60rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.upload-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 图片预览 */
|
||||
.preview-list {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
position: relative;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
font-size: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 提交按钮 */
|
||||
.submit-section {
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
|
||||
color: white;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
border-radius: 44rpx;
|
||||
border: none;
|
||||
box-shadow: 0 8rpx 20rpx rgba(116, 185, 255, 0.3);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.submit-btn:disabled {
|
||||
background: #cccccc; /* 禁用时灰色背景 */
|
||||
color: #999;
|
||||
cursor: not-allowed; /* 禁用时显示禁止光标 */
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 4rpx 12rpx rgba(116, 185, 255, 0.2);
|
||||
}
|
||||
|
||||
/* 底部提示 */
|
||||
.footer-tip {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
background-color: #fff;
|
||||
border-top: 1rpx solid #e9ecef;
|
||||
}
|
||||
</style>
|
||||
524
pages/mall/delivery/help-center.uvue
Normal file
524
pages/mall/delivery/help-center.uvue
Normal file
@@ -0,0 +1,524 @@
|
||||
<template>
|
||||
<view class="help-center-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="header-bar">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">←</text>
|
||||
</view>
|
||||
<text class="page-title">帮助中心</text>
|
||||
<view class="nav-right"></view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-bar">
|
||||
<view class="search-input-wrapper">
|
||||
<text class="search-icon">🔍</text>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索常见问题..."
|
||||
v-model="searchQuery"
|
||||
@input="onSearch"
|
||||
class="search-input"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分类导航 -->
|
||||
<view class="category-tabs">
|
||||
<scroll-view scroll-x="true" class="tabs-scroll">
|
||||
<view
|
||||
v-for="cat in categories"
|
||||
:key="cat.id"
|
||||
class="tab-item"
|
||||
:class="{ active: activeCategory === cat.id }"
|
||||
@click="switchCategory(cat.id)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<view class="content-wrapper">
|
||||
<!-- 筛选标签(仅在搜索时显示) -->
|
||||
<view v-if="searchQuery" class="filter-tags">
|
||||
<text class="tag">搜索结果:{{ searchResults.length }} 条</text>
|
||||
<text class="clear-btn" @click="clearSearch">清除</text>
|
||||
</view>
|
||||
|
||||
<!-- 常见问题列表 -->
|
||||
<view v-if="currentQuestions.length > 0">
|
||||
<view v-for="item in currentQuestions" :key="item.id" class="question-item">
|
||||
<view class="question-header" @click="toggleExpand(item)">
|
||||
<text class="question-text">{{ item.title }}</text>
|
||||
<text class="expand-icon">{{ item.expanded ? '▲' : '▼' }}</text>
|
||||
</view>
|
||||
<view v-if="item.expanded" class="answer-content">
|
||||
<text class="answer-text">{{ item.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 无结果提示 -->
|
||||
<view v-else class="no-result">
|
||||
<text class="no-result-icon">❓</text>
|
||||
<text class="no-result-title">暂无匹配结果</text>
|
||||
<text class="no-result-desc">请尝试更换关键词,或查看以下热门问题</text>
|
||||
<view class="hot-questions">
|
||||
<text class="hot-tag">热门问题:</text>
|
||||
<text class="hot-item" @click="jumpToQuestion('q1')">如何接单?</text>
|
||||
<text class="hot-item" @click="jumpToQuestion('q2')">配送超时怎么办?</text>
|
||||
<text class="hot-item" @click="jumpToQuestion('q3')">如何联系客户?</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部联系客服 -->
|
||||
<view class="contact-footer">
|
||||
<view class="contact-card">
|
||||
<text class="contact-title">需要人工帮助?</text>
|
||||
<text class="contact-desc">7×24小时在线客服,为您解决配送中遇到的任何问题</text>
|
||||
<button class="contact-btn" @click="contactCustomerService">联系客服</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchQuery: '',
|
||||
activeCategory: 'all',
|
||||
categories: [
|
||||
{ id: 'all', name: '全部' },
|
||||
{ id: 'order', name: '订单相关' },
|
||||
{ id: 'delivery', name: '配送操作' },
|
||||
{ id: 'account', name: '账号与认证' },
|
||||
{ id: 'payment', name: '收入与结算' },
|
||||
{ id: 'vehicle', name: '车辆管理' }
|
||||
],
|
||||
questions: [
|
||||
{
|
||||
id: 'q1',
|
||||
title: '如何接单?',
|
||||
content: '1. 进入【任务列表】页面\n2. 查看“待接单”任务\n3. 点击任务卡片 → 点击【接受订单】按钮\n4. 系统将自动分配该订单给您,状态变为“已接单”\n⚠️ 注意:同一时间只能接1个订单,接单后需在15分钟内取货。',
|
||||
category: ['order', 'delivery'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q2',
|
||||
title: '配送超时怎么办?',
|
||||
content: '若因交通堵塞、客户联系不上等不可抗力导致超时,请在送达后点击【异常上报】→ 选择原因并上传凭证(如截图、通话记录),系统将审核后减免处罚。建议提前10分钟联系客户确认收货时间。',
|
||||
category: ['delivery'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q3',
|
||||
title: '如何联系客户?',
|
||||
content: '在【任务详情】页点击【联系客户】→ 选择【拨打电话】或【发送短信】。系统会隐藏真实号码,保护双方隐私。首次联系建议使用语音电话,确保沟通效率。',
|
||||
category: ['delivery', 'order'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q4',
|
||||
title: '如何修改个人信息?',
|
||||
content: '进入【个人中心】→ 点击头像 → 【编辑资料】→ 修改姓名/电话/身份证号等信息 → 提交后等待审核(通常2小时内完成)。注意:身份证信息需上传清晰照片。',
|
||||
category: ['account'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q5',
|
||||
title: '配送费如何计算?',
|
||||
content: '基础配送费 = 距离费(¥1.5/km) + 时间费(¥0.5/分钟) + 服务费(¥2~5,根据时段浮动)\n例如:3km + 15分钟 = 3×1.5 + 15×0.5 + 3 = ¥15\n实际金额以订单详情页为准。',
|
||||
category: ['payment'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q6',
|
||||
title: '车辆信息如何绑定?',
|
||||
content: '【个人中心】→ 【车辆管理】→ 【添加车辆】→ 输入车牌号、车型、行驶证照片 → 提交审核。审核通过后,系统将自动关联您的配送任务。未绑定车辆无法接单。',
|
||||
category: ['vehicle'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q7',
|
||||
title: '如何查看收入明细?',
|
||||
content: '【个人中心】→ 【收入明细】→ 可按日/周/月筛选 → 查看每笔订单的配送费、奖励、扣款及到账时间。支持导出Excel报表(需企业版权限)。',
|
||||
category: ['payment'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q8',
|
||||
title: '任务被取消了怎么办?',
|
||||
content: '若客户取消订单,您将收到系统通知。已完成取货的订单,可申请补偿(路径:任务详情 → 【申请补偿】);未取货的订单无补偿。每月最多3次无责取消不计入考核。',
|
||||
category: ['order'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q9',
|
||||
title: '导航功能不准确?',
|
||||
content: '请检查:① 手机GPS权限是否开启;② 是否使用最新版APP;③ 在【设置】→ 【地图偏好】中切换高德/百度地图。仍无效请反馈至客服,并提供截图+坐标。',
|
||||
category: ['delivery'],
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
id: 'q10',
|
||||
title: '如何提升评分?',
|
||||
content: '评分由客户评价(70%)+ 系统考核(30%)组成。建议:① 准时送达(≤预计时间);② 礼貌沟通;③ 主动拍照上传(取货/送达);④ 避免频繁拒单。当前平均分:4.8/5.0',
|
||||
category: ['delivery', 'account'],
|
||||
expanded: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentQuestions() {
|
||||
if (this.searchQuery) {
|
||||
return this.searchResults
|
||||
}
|
||||
return this.questions.filter(q =>
|
||||
this.activeCategory === 'all' || q.category.includes(this.activeCategory)
|
||||
)
|
||||
},
|
||||
searchResults() {
|
||||
const query = this.searchQuery.toLowerCase()
|
||||
return this.questions.filter(q =>
|
||||
q.title.toLowerCase().includes(query) ||
|
||||
q.content.toLowerCase().includes(query)
|
||||
)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
|
||||
onSearch() {
|
||||
// 实时搜索(可加防抖)
|
||||
if (!this.searchQuery) {
|
||||
this.activeCategory = 'all'
|
||||
}
|
||||
},
|
||||
|
||||
clearSearch() {
|
||||
this.searchQuery = ''
|
||||
this.activeCategory = 'all'
|
||||
},
|
||||
|
||||
switchCategory(categoryId) {
|
||||
this.activeCategory = categoryId
|
||||
this.searchQuery = ''
|
||||
},
|
||||
|
||||
toggleExpand(item) {
|
||||
item.expanded = !item.expanded
|
||||
// 关闭其他展开项(可选)
|
||||
// this.questions.forEach(q => { if (q !== item) q.expanded = false })
|
||||
},
|
||||
|
||||
jumpToQuestion(id) {
|
||||
const item = this.questions.find(q => q.id === id)
|
||||
if (item) {
|
||||
item.expanded = true
|
||||
this.activeCategory = 'all'
|
||||
this.searchQuery = ''
|
||||
// 滚动到该问题(简化版)
|
||||
uni.pageScrollTo({ scrollTop: 300, duration: 300 })
|
||||
}
|
||||
},
|
||||
|
||||
contactCustomerService() {
|
||||
uni.showActionSheet({
|
||||
itemList: ['在线客服', '电话咨询', '提交工单'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
uni.navigateTo({ url: '/pages/mall/common/customer-service' })
|
||||
} else if (res.tapIndex === 1) {
|
||||
uni.makePhoneCall({ phoneNumber: '400-123-4567' })
|
||||
} else {
|
||||
uni.navigateTo({ url: '/pages/mall/common/feedback?from=help' })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.help-center-container {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 100vh;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
/* 顶部导航 */
|
||||
.header-bar {
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #e9ecef;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 10rpx;
|
||||
border-radius: 8rpx;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-left:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.nav-left:active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
width: 60rpx;
|
||||
height: 1rpx;
|
||||
}
|
||||
|
||||
/* 搜索框 —— 修复放大镜与输入框垂直对齐 */
|
||||
.search-bar {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center; /* ✅ 垂直居中核心 */
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 40rpx;
|
||||
padding: 12rpx 20rpx;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-right: 12rpx;
|
||||
line-height: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 48rpx; /* 与 input 高度一致 */
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
color: #333;
|
||||
height: 48rpx;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 分类导航 */
|
||||
.category-tabs {
|
||||
background-color: #fff;
|
||||
padding: 0 30rpx 20rpx;
|
||||
}
|
||||
|
||||
.tabs-scroll {
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
display: inline-block;
|
||||
padding: 12rpx 24rpx;
|
||||
margin-right: 16rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 30rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
background-color: #74b9ff;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 内容区域 */
|
||||
.content-wrapper {
|
||||
padding: 0 30rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.filter-tags {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 0;
|
||||
background-color: #e8f4fd;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.clear-btn {
|
||||
font-size: 24rpx;
|
||||
color: #74b9ff;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.question-item {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.question-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx 20rpx;
|
||||
cursor: pointer;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.question-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
width: 36rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.answer-content {
|
||||
padding: 0 20rpx 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.answer-text {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
/* 无结果提示 */
|
||||
.no-result {
|
||||
text-align: center;
|
||||
padding: 80rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.no-result-icon {
|
||||
font-size: 80rpx;
|
||||
color: #e0e0e0;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.no-result-title {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.no-result-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 25rpx;
|
||||
}
|
||||
|
||||
.hot-questions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.hot-tag {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.hot-item {
|
||||
font-size: 24rpx;
|
||||
color: #74b9ff;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
background-color: #e8f4fd;
|
||||
}
|
||||
|
||||
/* 底部联系客服 */
|
||||
.contact-footer {
|
||||
padding: 30rpx;
|
||||
background-color: #fff;
|
||||
border-top: 1rpx solid #e9ecef;
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contact-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.contact-desc {
|
||||
font-size: 26rpx;
|
||||
opacity: 0.9;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.contact-btn {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background-color: white;
|
||||
color: #74b9ff;
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
border-radius: 40rpx;
|
||||
border: none;
|
||||
box-shadow: 0 6rpx 15rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
||||
@@ -4,8 +4,8 @@
|
||||
<!-- 1. 蓝色头像条(profile-header) -->
|
||||
<view class="profile-header">
|
||||
<!-- 返回按钮:最左边垂直居中 -->
|
||||
<view class="back-box" @click="backToIndex">
|
||||
<text class="back-icon">‹</text>
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
</view>
|
||||
|
||||
<image :src="driverInfo.avatar_url || '/static/default-avatar.png'" class="driver-avatar" @click="editProfile" />
|
||||
@@ -30,8 +30,12 @@
|
||||
<view class="toggle-handle"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="workStatus === 1" class="current-location">
|
||||
<!-- 修改点:将定位信息和重新定位按钮合并到一个区域 -->
|
||||
<view v-if="workStatus === 1" class="current-location-section">
|
||||
<text class="location-text">📍 {{ currentLocation }}</text>
|
||||
<view class="relocate-icon" @click.stop="showRelocateConfirm">
|
||||
<text class="icon-text">↻</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -214,7 +218,7 @@ const driverInfo = ref({
|
||||
})
|
||||
|
||||
const workStatus = ref(1) // 1 工作中 0 休息中
|
||||
const currentLocation = ref('朝阳区建国门附近')
|
||||
const currentLocation = ref('朝阳区建国门附近') // 默认位置
|
||||
|
||||
const taskCounts = ref({ total: 0, pending: 0, ongoing: 0, completed: 0 })
|
||||
|
||||
@@ -364,6 +368,41 @@ function toggleWorkStatus() {
|
||||
})
|
||||
}
|
||||
|
||||
// --- 新增:重新定位逻辑 ---
|
||||
function showRelocateConfirm() {
|
||||
uni.showModal({
|
||||
title: '重新定位',
|
||||
content: '确定要更新当前位置吗?',
|
||||
confirmText: '立即定位',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
relocate()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function relocate() {
|
||||
uni.showLoading({
|
||||
title: '获取位置中...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
// 模拟定位耗时
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
|
||||
// 模拟定位成功,更新位置(实际项目中应调用API获取真实位置)
|
||||
currentLocation.value = '朝阳区建国门外大街附近'
|
||||
|
||||
uni.showToast({
|
||||
title: '定位成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
}, 1200)
|
||||
}
|
||||
|
||||
function contactCustomer() {
|
||||
uni.showActionSheet({
|
||||
itemList: ['拨打电话', '发送短信'],
|
||||
@@ -398,10 +437,10 @@ function goToRatings() {
|
||||
uni.navigateTo({ url: '/pages/mall/delivery/ratings' })
|
||||
}
|
||||
function goToHelp() {
|
||||
uni.navigateTo({ url: '/pages/mall/common/help' })
|
||||
uni.navigateTo({ url: '/pages/mall/delivery/help-center' })
|
||||
}
|
||||
function goToFeedback() {
|
||||
uni.navigateTo({ url: '/pages/mall/common/feedback' })
|
||||
uni.navigateTo({ url: '/pages/mall/delivery/feedback' })
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -410,7 +449,7 @@ function goToFeedback() {
|
||||
.profile-header {
|
||||
position: relative;
|
||||
}
|
||||
.back-box {
|
||||
.nav-left {
|
||||
position: absolute;
|
||||
left: 30rpx;
|
||||
top: 50%;
|
||||
@@ -423,15 +462,15 @@ function goToFeedback() {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.back-box:active {
|
||||
.nav-left:active {
|
||||
background: rgba(0, 0, 0, .3);
|
||||
}
|
||||
.back-icon {
|
||||
.nav-icon {
|
||||
font-size: 40rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ---------- 以下与原样式一致 ---------- */
|
||||
/* ---------- 以下与原样式一致,仅修改工作状态区域 ---------- */
|
||||
.delivery-profile {
|
||||
padding: 0 0 120rpx 0;
|
||||
background-color: #f5f5f5;
|
||||
@@ -541,14 +580,39 @@ function goToFeedback() {
|
||||
.toggle-switch.active .toggle-handle {
|
||||
left: 55rpx;
|
||||
}
|
||||
.current-location {
|
||||
|
||||
/* --- 修改后的定位信息区域:地址 + 图标 --- */
|
||||
.current-location-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15rpx 20rpx;
|
||||
background: #e8f4fd;
|
||||
background: #e8f4fd; /* 与原样式保持一致 */
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
.location-text {
|
||||
font-size: 24rpx; /* 与截图字号一致 */
|
||||
color: #74b9ff; /* 与截图颜色一致 */
|
||||
flex: 1; /* 让文字占据剩余空间 */
|
||||
margin-right: 16rpx; /* 与图标留空隙 */
|
||||
}
|
||||
.relocate-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: rgba(116, 185, 255, 0.15); /* 浅蓝底 */
|
||||
color: #74b9ff; /* 主色文字 */
|
||||
font-size: 24rpx;
|
||||
color: #74b9ff;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.relocate-icon:hover {
|
||||
background: rgba(116, 185, 255, 0.3); /* 悬停效果 */
|
||||
}
|
||||
.relocate-icon:active {
|
||||
background: rgba(116, 185, 255, 0.4); /* 点击效果 */
|
||||
}
|
||||
|
||||
.task-tabs {
|
||||
@@ -556,10 +620,10 @@ function goToFeedback() {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.task-tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
.tab-icon {
|
||||
|
||||
418
pages/mall/delivery/test.uvue
Normal file
418
pages/mall/delivery/test.uvue
Normal file
@@ -0,0 +1,418 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">Supabase 连接测试</text>
|
||||
</view>
|
||||
|
||||
<view class="config-info">
|
||||
<text class="label">当前配置:</text>
|
||||
<text class="value">URL: {{ config.url }}</text>
|
||||
<text class="value">Key: {{ config.keyMasked }}</text>
|
||||
</view>
|
||||
|
||||
<view class="test-section">
|
||||
<button class="btn-primary" @click="runAllTests" :disabled="isLoading">
|
||||
{{ isLoading ? '测试中...' : '运行全部测试' }}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="results" v-if="testResults.length > 0">
|
||||
<text class="section-title">测试结果</text>
|
||||
<view
|
||||
class="result-item"
|
||||
v-for="(result, index) in testResults"
|
||||
:key="index"
|
||||
:class="{ success: result.success, error: !result.success }"
|
||||
>
|
||||
<text class="result-icon">{{ result.success ? '✅' : '❌' }}</text>
|
||||
<text class="result-text">{{ result.name }}</text>
|
||||
<text class="result-message">{{ result.message }}</text>
|
||||
<text v-if="result.errorDetails" class="error-details">{{ result.errorDetails }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="quick-tests">
|
||||
<text class="section-title">单项测试</text>
|
||||
<button class="btn-secondary" @click="testConnection">测试连接</button>
|
||||
<button class="btn-secondary" @click="testQuery">测试查询</button>
|
||||
<button class="btn-secondary" @click="testAuth">测试认证</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
// 导入你的封装库和配置
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
import { SUPA_URL, SUPA_KEY } from '@/ak/config.uts'
|
||||
|
||||
// 定义测试结果类型
|
||||
type TestResult = {
|
||||
name: string
|
||||
success: boolean
|
||||
message: string
|
||||
errorDetails?: string
|
||||
}
|
||||
|
||||
// 定义用户类型(用于类型安全查询)
|
||||
type User = {
|
||||
id?: number
|
||||
email?: string
|
||||
nickname?: string
|
||||
phone?: string
|
||||
created_at?: string
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
url: SUPA_URL,
|
||||
key: SUPA_KEY,
|
||||
keyMasked: SUPA_KEY.substring(0, 20) + '...' // 隐藏部分密钥
|
||||
},
|
||||
isLoading: false,
|
||||
testResults: [] as TestResult[]
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
console.log('🎯 Supabase 测试页面加载完成')
|
||||
console.log('📋 配置信息:', {
|
||||
url: SUPA_URL,
|
||||
hasKey: !!SUPA_KEY
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 获取错误消息的安全函数
|
||||
getErrorMessage(err: any): string {
|
||||
if (err == null) return '未知错误'
|
||||
if (typeof err === 'string') return err
|
||||
if (typeof err === 'object') {
|
||||
if (err.message) return err.message
|
||||
if (err.error) return err.error
|
||||
if (err.msg) return err.msg
|
||||
return JSON.stringify(err)
|
||||
}
|
||||
return String(err)
|
||||
},
|
||||
|
||||
// 安全执行测试
|
||||
async safeExecute<T>(promise: Promise<T>, operationName: string): Promise<{ success: boolean; data?: T; error?: string }> {
|
||||
try {
|
||||
const result = await promise
|
||||
return { success: true, data: result }
|
||||
} catch (err) {
|
||||
const errorMessage = this.getErrorMessage(err)
|
||||
console.error(`❌ ${operationName} 失败:`, err)
|
||||
return { success: false, error: errorMessage }
|
||||
}
|
||||
},
|
||||
|
||||
// 测试连接
|
||||
async testConnection(): Promise<TestResult> {
|
||||
console.log('🔍 开始测试连接...')
|
||||
|
||||
const result = await this.safeExecute(
|
||||
uni.request({
|
||||
url: `${SUPA_URL}/rest/v1/`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'apikey': SUPA_KEY,
|
||||
'Authorization': `Bearer ${SUPA_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: 10000
|
||||
}),
|
||||
'基础连接测试'
|
||||
)
|
||||
|
||||
if (result.success) {
|
||||
const response = result.data as any
|
||||
if (response.statusCode === 200 || response.statusCode === 404) {
|
||||
return {
|
||||
name: '基础连接',
|
||||
success: true,
|
||||
message: `API 可达 (HTTP ${response.statusCode})`,
|
||||
errorDetails: response.statusCode === 404 ? 'API 响应正常,但请求的资源不存在' : undefined
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: '基础连接',
|
||||
success: false,
|
||||
message: `HTTP 错误`,
|
||||
errorDetails: `状态码: ${response.statusCode}, 数据: ${JSON.stringify(response.data)}`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: '基础连接',
|
||||
success: false,
|
||||
message: '连接失败',
|
||||
errorDetails: result.error
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 测试查询
|
||||
async testQuery(): Promise<TestResult> {
|
||||
console.log('🔍 开始测试查询...')
|
||||
|
||||
// 尝试查询 users 表
|
||||
const queryResult = await this.safeExecute(
|
||||
supa.from('users').select('id, email, nickname').limit(1).execute(),
|
||||
'查询测试'
|
||||
)
|
||||
|
||||
if (queryResult.success) {
|
||||
const { data, error } = queryResult.data as any
|
||||
if (error) {
|
||||
const errorMsg = this.getErrorMessage(error)
|
||||
// 检查是否是表不存在的错误
|
||||
if (errorMsg.includes('relation') && errorMsg.includes('does not exist')) {
|
||||
return {
|
||||
name: '查询测试',
|
||||
success: false,
|
||||
message: '表不存在',
|
||||
errorDetails: 'users 表不存在,建议先在 Studio 中创建表'
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: '查询测试',
|
||||
success: false,
|
||||
message: '查询出错',
|
||||
errorDetails: errorMsg
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: '查询测试',
|
||||
success: true,
|
||||
message: `查询成功,返回 ${data?.length || 0} 条记录`,
|
||||
errorDetails: data && data.length > 0 ? `第一条: ${JSON.stringify(data[0])}` : '表为空'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: '查询测试',
|
||||
success: false,
|
||||
message: '查询失败',
|
||||
errorDetails: queryResult.error
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 测试认证
|
||||
async testAuth(): Promise<TestResult> {
|
||||
console.log('🔍 开始测试认证...')
|
||||
|
||||
const authResult = await this.safeExecute(
|
||||
supa.auth.getSession(),
|
||||
'认证测试'
|
||||
)
|
||||
|
||||
if (authResult.success) {
|
||||
const { data, error } = authResult.data as any
|
||||
if (error) {
|
||||
return {
|
||||
name: '认证测试',
|
||||
success: false,
|
||||
message: '获取会话失败',
|
||||
errorDetails: this.getErrorMessage(error)
|
||||
}
|
||||
}
|
||||
if (data?.session) {
|
||||
return {
|
||||
name: '认证测试',
|
||||
success: true,
|
||||
message: '用户已登录',
|
||||
errorDetails: `用户: ${data.session.user.email || data.session.user.phone || 'ID: ' + data.session.user.id}`
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: '认证测试',
|
||||
success: true,
|
||||
message: '未登录(正常状态)',
|
||||
errorDetails: '当前没有活动会话,需要先登录'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: '认证测试',
|
||||
success: false,
|
||||
message: '认证失败',
|
||||
errorDetails: authResult.error
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 运行所有测试
|
||||
async runAllTests() {
|
||||
this.isLoading = true
|
||||
this.testResults = []
|
||||
|
||||
try {
|
||||
// 依次运行测试
|
||||
const tests = [
|
||||
{ name: 'connection', func: this.testConnection },
|
||||
{ name: 'query', func: this.testQuery },
|
||||
{ name: 'auth', func: this.testAuth }
|
||||
]
|
||||
|
||||
for (const test of tests) {
|
||||
console.log(`🧪 运行测试: ${test.name}`)
|
||||
const result = await test.func.call(this)
|
||||
this.testResults.push(result)
|
||||
|
||||
// 短暂延迟,让用户看到测试进度
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
}
|
||||
|
||||
// 总结结果
|
||||
const passed = this.testResults.filter(r => r.success).length
|
||||
const total = this.testResults.length
|
||||
console.log(`📈 测试总结: ${passed}/${total} 通过`)
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 运行测试时发生错误:', error)
|
||||
this.testResults.push({
|
||||
name: '整体测试',
|
||||
success: false,
|
||||
message: '测试框架错误',
|
||||
errorDetails: this.getErrorMessage(error)
|
||||
})
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 30rpx;
|
||||
background-color: #f8f9fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.config-info {
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.test-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
background-color: #6c757d;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
font-size: 26rpx;
|
||||
border: none;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.btn-primary:disabled, .btn-secondary:disabled {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.results {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.result-item {
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.result-item.success {
|
||||
border-left: 4px solid #28a745;
|
||||
background-color: #d4edda;
|
||||
}
|
||||
|
||||
.result-item.error {
|
||||
border-left: 4px solid #dc3545;
|
||||
background-color: #f8d7da;
|
||||
}
|
||||
|
||||
.result-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.result-text {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.result-message {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.error-details {
|
||||
display: block;
|
||||
font-size: 20rpx;
|
||||
color: #856404;
|
||||
background-color: #fff3cd;
|
||||
padding: 8rpx;
|
||||
border-radius: 4rpx;
|
||||
margin-top: 8rpx;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user