!4 提交 readme

Merge pull request !4 from master_xzc
This commit is contained in:
2025-05-09 04:03:12 +00:00
committed by Gitee
158 changed files with 8619 additions and 5056 deletions
+1 -1
View File
@@ -1 +1 @@
node_modules
node_modules
+43 -43
View File
@@ -1,44 +1,44 @@
<script>
import {
wxLogin,
getUserInfo
} from './util/index'
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: async function() {
console.log('App Show')
await this.autoLogin()
},
onHide: function() {
console.log('App Hide')
},
methods: {
async autoLogin() {
try {
const loginResult = await wxLogin()
console.log('自动登录成功:', loginResult)
// await getUserInfo()
} catch (error) {
console.error('自动登录失败:', error)
// 登录失败的处理可以在 wxLogin 中统一处理
// 这里可以添加特殊的错误处理逻辑
}
}
}
}
</script>
<style lang="scss">
@import "uview-ui/index.scss"
/*每个页面公共css */
<script>
import {
wxLogin,
getUserInfo
} from './util/index'
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: async function() {
console.log('App Show')
await this.autoLogin()
},
onHide: function() {
console.log('App Hide')
},
methods: {
async autoLogin() {
try {
const loginResult = await wxLogin()
console.log('自动登录成功:', loginResult)
// await getUserInfo()
} catch (error) {
console.error('自动登录失败:', error)
// 登录失败的处理可以在 wxLogin 中统一处理
// 这里可以添加特殊的错误处理逻辑
}
}
}
}
</script>
<style lang="scss">
@import "uview-ui/index.scss"
/*每个页面公共css */
</style>
+300
View File
@@ -0,0 +1,300 @@
# Uni-Fans API 接口文档
本文档详细说明了 Uni-Fans 应用中使用的所有接口,包括参数说明和使用示例。
## 目录
1. [订单查询接口](#1-订单查询接口)
2. [设备信息查询接口](#2-设备信息查询接口)
3. [订单套餐更新接口](#3-订单套餐更新接口)
4. [用户余额更新接口](#4-用户余额更新接口)
5. [微信支付订单创建接口](#5-微信支付订单创建接口)
6. [设备租借指令接口](#6-设备租借指令接口)
## 1. 订单查询接口
### 描述
根据订单ID查询订单详细信息。
### 接口信息
- **方法名**: `queryById`
- **请求方式**: GET
- **URL**: `/app/order/query/{orderId}`
### 请求参数
| 参数名 | 类型 | 必须 | 描述 |
| ----- | ---- | ---- | ---- |
| orderId | String | 是 | 订单ID |
### 响应参数
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"orderId": "订单ID",
"orderNo": "订单编号",
"deviceNo": "设备编号",
"createTime": "创建时间",
"phone": "联系电话",
"depositAmount": "押金金额",
"packageTime": "套餐时间(分钟)",
"packagePrice": "套餐价格"
}
}
```
### 使用示例
```javascript
const orderInfo = await queryById('12345');
if (orderInfo.code === 200) {
// 处理订单信息
console.log(orderInfo.data);
}
```
## 2. 设备信息查询接口
### 描述
根据设备编号查询设备详细信息。
### 接口信息
- **方法名**: `getDeviceInfo`
- **请求方式**: GET
- **URL**: `/app/device/info/{deviceNo}`
### 请求参数
| 参数名 | 类型 | 必须 | 描述 |
| ----- | ---- | ---- | ---- |
| deviceNo | String | 是 | 设备编号 |
### 响应参数
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"device": {
"deviceNo": "设备编号",
"deviceName": "设备名称",
"deviceStatus": "设备状态",
"depositAmount": "押金金额",
"feeType": "收费类型(hour/times)",
"feeConfig": "费用配置JSON字符串"
}
}
}
```
### 使用示例
```javascript
const deviceInfo = await getDeviceInfo('D001');
if (deviceInfo.code === 200) {
// 处理设备信息
console.log(deviceInfo.data.device);
}
```
## 3. 订单套餐更新接口
### 描述
更新订单的套餐信息。
### 接口信息
- **方法名**: `updateOrderPackage`
- **请求方式**: POST
- **URL**: `/app/order/update-package`
### 请求参数
| 参数名 | 类型 | 必须 | 描述 |
| ----- | ---- | ---- | ---- |
| orderId | String | 是 | 订单ID |
| packageTime | Number | 是 | 套餐时间(分钟) |
| packagePrice | Number | 是 | 套餐价格 |
### 响应参数
```json
{
"code": 200,
"msg": "操作成功",
"data": null
}
```
### 使用示例
```javascript
const result = await updateOrderPackage({
orderId: '12345',
packageTime: 360, // 6小时(分钟)
packagePrice: 30 // 30元
});
if (result.code === 200) {
console.log('套餐更新成功');
}
```
## 4. 用户余额更新接口
### 描述
支付成功后更新用户余额信息。
### 接口信息
- **方法名**: `updateUserBalance`
- **请求方式**: POST
- **URL**: `/app/user/update-balance`
### 请求参数
| 参数名 | 类型 | 必须 | 描述 |
| ----- | ---- | ---- | ---- |
| orderId | String | 是 | 订单ID |
### 响应参数
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"userId": "用户ID",
"balance": "更新后余额"
}
}
```
### 使用示例
```javascript
const result = await updateUserBalance('12345');
if (result.code === 200) {
console.log('用户余额更新成功');
}
```
## 5. 微信支付订单创建接口
### 描述
创建微信支付订单。
### 接口信息
- **请求方式**: GET
- **URL**: `/app/wx-payment/create/{orderNo}`
### 请求参数
| 参数名 | 类型 | 必须 | 描述 |
| ----- | ---- | ---- | ---- |
| orderNo | String | 是 | 订单编号 |
### 请求头
| 参数名 | 必须 | 描述 |
| ----- | ---- | ---- |
| Authorization | 是 | Bearer 认证令牌 |
| Clientid | 是 | 客户端ID |
### 响应参数
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"appId": "微信应用ID",
"timeStamp": "时间戳",
"nonceStr": "随机字符串",
"package": "预支付交易会话标识",
"signType": "签名类型",
"paySign": "签名"
}
}
```
### 使用示例
```javascript
const res = await uni.request({
url: `${URL}/app/wx-payment/create/${orderNo}`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
});
if (res.statusCode === 200 && res.data.code === 200) {
const payParams = res.data.data;
await uni.requestPayment({
...payParams,
success: () => {
console.log('支付成功');
},
fail: (err) => {
console.error('支付失败:', err);
}
});
}
```
## 6. 设备租借指令接口
### 描述
发送设备租借指令。
### 接口信息
- **请求方式**: POST
- **URL**: `/app/device/sendRentCommand`
### 请求参数
| 参数名 | 类型 | 必须 | 描述 |
| ----- | ---- | ---- | ---- |
| orderId | String | 是 | 订单ID |
### 请求头
| 参数名 | 必须 | 描述 |
| ----- | ---- | ---- |
| Content-Type | 是 | application/x-www-form-urlencoded |
| Authorization | 是 | Bearer 认证令牌 |
| Clientid | 是 | 客户端ID |
### 响应参数
```json
{
"code": 200,
"msg": "操作成功",
"data": null
}
```
### 使用示例
```javascript
const res = await uni.request({
url: `${URL}/app/device/sendRentCommand`,
method: 'POST',
data: {
orderId: '12345'
},
header: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
});
if (res.statusCode === 200 && res.data.code === 200) {
console.log('租借指令发送成功');
}
```
+87 -60
View File
@@ -1,61 +1,88 @@
import {
URL,
appid
} from './url'
const request = (option) => {
return new Promise((resolve, reject) => {
// Debug request info
console.log(`发起请求: ${option.method} ${URL + option.url}`, option.data)
uni.request({
url: URL + option.url,
method: option.method,
data: option.data,
header: {
"Content-Type": "application/x-www-form-urlencoded",
...option.headers,
'appid': appid,
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
},
success(res) {
// 记录响应
console.log(`请求响应: ${option.url}`, res)
// 检查响应状态码
if (res.statusCode !== 200) {
console.error(`HTTP状态码错误: ${res.statusCode}`, res.data)
// 为了适应某些服务器的异常响应,我们仍然返回数据
if (res.data) {
resolve(res.data)
return
}
reject({msg: `请求失败,状态码:${res.statusCode}`})
return
}
// 检查业务状态码
if (res.data && res.data.code !== 200) {
console.warn(`业务状态码错误: ${res.data.code}`, res.data)
// 仍然返回数据,由业务逻辑处理
resolve(res.data)
return
}
resolve(res.data)
},
fail(err) {
// 网络请求本身失败
console.error(`请求失败: ${option.url}`, err)
reject(err)
}
})
})
}
import {
URL,
appid
} from './url'
const request = (option) => {
return new Promise((resolve, reject) => {
// Debug request info
console.log(`发起请求: ${option.method} ${URL + option.url}`, option.data)
// 默认不显示加载中提示
if (!option.hideLoading) {
uni.showLoading({
title: option.loadingText || '加载中...',
mask: true
})
}
uni.request({
url: URL + option.url,
method: option.method,
data: option.data,
header: {
"Content-Type": "application/x-www-form-urlencoded",
...option.headers,
'appid': appid,
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
},
success(res) {
// 记录响应
console.log(`请求响应: ${option.url}`, res)
// 检查响应状态码
if (res.statusCode !== 200) {
console.error(`HTTP状态码错误: ${res.statusCode}`, res.data)
// 为了适应某些服务器的异常响应,我们仍然返回数据
if (res.data) {
resolve(res.data)
return
}
reject({msg: `请求失败,状态码:${res.statusCode}`})
return
}
// 检查业务状态码
if (res.data && res.data.code !== 200) {
console.warn(`业务状态码错误: ${res.data.code}`, res.data)
// 判断是否需要忽略数据为空的错误
if (option.ignoreEmptyError &&
(res.data.code === 500 && res.data.msg &&
(res.data.msg.includes('未找到') || res.data.msg.includes('不存在')))) {
// 对于指定需要忽略的错误,返回一个标准的"成功但数据为空"的响应
resolve({
code: 200,
msg: "操作成功",
data: []
})
return
}
// 仍然返回数据,由业务逻辑处理
resolve(res.data)
return
}
resolve(res.data)
},
fail(err) {
// 网络请求本身失败
console.error(`请求失败: ${option.url}`, err)
reject(err)
},
complete() {
// 隐藏加载提示
if (!option.hideLoading) {
uni.hideLoading()
}
}
})
})
}
export default request
+4 -4
View File
@@ -1,4 +1,4 @@
// export const URL = "https://notify.gxfs123.com"
export const URL = "http://127.0.0.1:8080"
export const appid = "wx3ae63fb09936b379"
// export const URL = "https://unifans.gxfs123.com"
export const URL = "http://127.0.0.1:8080"
export const appid = "wxe752f45e7f7aa271"
+72
View File
@@ -18,6 +18,16 @@ export const getMyIndexInfo = (data) => {
})
}
// 添加押金提现API
export const withdrawDeposit = (orderNo) => {
console.log('调用提现API,订单号:', orderNo)
return request({
url: `/app/withdraw/add/${orderNo}`,
method: 'get',
hideLoading: true
})
}
//获取所有全部订单
export const getOrderList = (data) => {
return request({
@@ -36,6 +46,18 @@ export const queryHasOrder = (deviceNo) => {
})
}
// 查询指定设备号下,特定状态的订单列表
export const checkOrdersByStatus = (deviceNo, statuses) => {
// statuses 是一个包含状态字符串的数组,例如 ['in_used', 'waiting_for_payment']
const statusQuery = statuses.join(','); // 后端需要支持逗号分隔的状态查询
return request({
url: `/app/order/list?deviceNo=${deviceNo}&orderStatus=${statusQuery}`,
method: 'get',
hideLoading: true, // 隐藏加载提示,避免干扰用户
ignoreEmptyError: true // 添加标记,表示即使返回空数据也不视为错误
})
}
//设备查询
export const getDeviceInfo = (deviceNo) => {
return request({
@@ -56,9 +78,11 @@ export const createOrder = (data) => {
//查询订单
export const queryById = (id) => {
console.log(`查询订单详情, orderId: ${id}`)
return request({
url: `/app/order/${id}`,
method: 'get',
hideLoading: true
})
}
@@ -91,6 +115,16 @@ export const rentPowerBank = (deviceNo, phone) => {
})
}
//确认支付并弹出充电宝
export const confirmPaymentAndRent = (orderId) => {
console.log(`确认支付并弹出充电宝, orderId: ${orderId}`)
return request({
url: `/app/device/confirmPaymentAndRent?orderId=${orderId}`,
method: 'post'
})
}
//投诉反馈
export const addUserFeedback = (data) => {
@@ -100,3 +134,41 @@ export const addUserFeedback = (data) => {
data,
})
}
//强制打开空格子
export const forcefOpenEmptyGrid = (deviceNo) => {
console.log(`强制打开空格子, deviceNo: ${deviceNo}`)
return request({
url: `/app/device/forcef/${deviceNo}`,
method: 'post'
})
}
// 通过订单号获取订单信息
export const getOrderByOrderNo = (orderNo) => {
console.log('通过订单号获取订单信息:', orderNo)
return request({
url: `/app/order/byOrderNo/${orderNo}`,
method: 'get',
hideLoading: true
})
}
// 更新订单套餐信息
export const updateOrderPackage = (data) => {
console.log('更新订单套餐信息:', data)
return request({
url: '/app/device/updateOrderPackage',
method: 'post',
data
})
}
// 更新用户余额
export const updateUserBalance = (orderId) => {
return request({
url: `/app/user/updateBalance/${orderId}`,
method: 'post',
hideLoading: true
})
}
+38 -38
View File
@@ -1,39 +1,39 @@
// 帮助中心文案配置
export const HELP_CONTENT = {
// FAQ列表
FAQ_LIST: [
{
question: '如何租借风扇?',
answer: '点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。'
},
{
question: '收费标准是怎样的?',
answer: '使用费用为2元/小时,不足1小时按1小时计算。押金99元,归还后自动退还。'
},
{
question: '如何归还风扇?',
answer: '将风扇带到任意归还点,点击首页"扫码归还"按钮,扫描归还点二维码即可完成归还。'
},
{
question: '押金多久能退还?',
answer: '归还设备后押金将自动发起退款,预计0-7个工作日到账。'
},
{
question: '设备无法正常使用怎么办?',
answer: '您可以通过"我的-投诉与建议"提交故障反馈,或直接拨打客服电话处理。'
}
],
// 联系方式
CONTACT: {
TITLE: '联系客服',
PHONE: {
LABEL: '客服电话',
VALUE: '400-888-8888'
},
SERVICE_TIME: {
LABEL: '服务时间',
VALUE: '周一至周日 09:00-22:00'
}
}
// 帮助中心文案配置
export const HELP_CONTENT = {
// FAQ列表
FAQ_LIST: [
{
question: '如何租借风扇?',
answer: '点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。'
},
{
question: '收费标准是怎样的?',
answer: '使用费用为2元/小时,不足1小时按1小时计算。押金99元,归还后自动退还。'
},
{
question: '如何归还风扇?',
answer: '将风扇带到任意归还点,点击首页"扫码归还"按钮,扫描归还点二维码即可完成归还。'
},
{
question: '押金多久能退还?',
answer: '归还设备后押金将自动发起退款,预计0-7个工作日到账。'
},
{
question: '设备无法正常使用怎么办?',
answer: '您可以通过"我的-投诉与建议"提交故障反馈,或直接拨打客服电话处理。'
}
],
// 联系方式
CONTACT: {
TITLE: '联系客服',
PHONE: {
LABEL: '客服电话',
VALUE: '400-888-8888'
},
SERVICE_TIME: {
LABEL: '服务时间',
VALUE: '周一至周日 09:00-22:00'
}
}
}
+54 -54
View File
@@ -1,55 +1,55 @@
/**
* 订单状态映射
*/
export const OrderStatusMap = {
waiting_for_payment: {
text: '待支付',
class: 'status-waiting'
},
payment_in_progress: {
text: '支付中',
class: 'status-progress'
},
payment_successful: {
text: '支付成功',
class: 'status-success'
},
in_used: {
text: '使用中',
class: 'status-using'
},
payment_failed: {
text: '支付失败',
class: 'status-failed'
},
order_cancelled: {
text: '已取消',
class: 'status-cancelled'
},
used_done: {
text: '已完成',
class: 'status-finished'
}
}
/**
* 订单状态分类
*/
export const OrderStatusTabs = [
{
text: '全部',
status: []
},
{
text: '待支付',
status: ['waiting_for_payment', 'payment_in_progress']
},
{
text: '使用中',
status: ['payment_successful', 'in_used']
},
{
text: '已完成',
status: ['used_done', 'payment_failed', 'order_cancelled']
}
/**
* 订单状态映射
*/
export const OrderStatusMap = {
waiting_for_payment: {
text: '待支付',
class: 'status-waiting'
},
payment_in_progress: {
text: '支付中',
class: 'status-progress'
},
payment_successful: {
text: '支付成功',
class: 'status-success'
},
in_used: {
text: '使用中',
class: 'status-using'
},
payment_failed: {
text: '支付失败',
class: 'status-failed'
},
order_cancelled: {
text: '已取消',
class: 'status-cancelled'
},
used_done: {
text: '已完成',
class: 'status-finished'
}
}
/**
* 订单状态分类
*/
export const OrderStatusTabs = [
{
text: '全部',
status: []
},
{
text: '待支付',
status: ['waiting_for_payment', 'payment_in_progress']
},
{
text: '使用中',
status: ['payment_successful', 'in_used']
},
{
text: '已完成',
status: ['used_done', 'payment_failed', 'order_cancelled']
}
]
+20 -20
View File
@@ -1,20 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>
+34 -26
View File
@@ -1,27 +1,35 @@
import App from './App'
import uView from "uview-ui";
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
Vue.use(uView)
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
import App from './App'
import { orderMonitor } from './utils/orderMonitor.js'
import uView from "uview-ui";
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
// 注册全局订单监控服务
Vue.prototype.$orderMonitor = orderMonitor
App.mpType = 'app'
Vue.use(uView)
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
// 注册全局订单监控服务到VUE3
app.config.globalProperties.$orderMonitor = orderMonitor
return {
app
}
}
// #endif
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name" : "fs",
"appid" : "__UNI__66470C9",
"appid" : "__UNI__4630191",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
@@ -50,7 +50,7 @@
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx3ae63fb09936b379",
"appid" : "wxe752f45e7f7aa271",
"setting" : {
"urlCheck" : false
},
+1757 -1757
View File
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -1,12 +1,12 @@
{
"dependencies": {
"axios": "^1.7.9",
"axios-miniprogram-adapter": "0.3.4",
"uniapp-axios-adapter": "^0.3.2",
"uview-ui": "1.8.8"
},
"devDependencies": {
"sass": "^1.57.1",
"sass-loader": "^13.2.0"
}
{
"dependencies": {
"axios": "^1.7.9",
"axios-miniprogram-adapter": "0.3.4",
"uniapp-axios-adapter": "^0.3.2",
"uview-ui": "1.8.8"
},
"devDependencies": {
"sass": "^1.57.1",
"sass-loader": "^13.2.0"
}
}
+112 -104
View File
@@ -1,105 +1,113 @@
{
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
"pages": [{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "共享风扇"
}
},
{
"path": "pages/my/index",
"style": {
"navigationBarTitleText": "个人中心"
}
},
{
"path": "pages/deposit/index",
"style": {
"navigationBarTitleText": "押金管理"
}
},
{
"path": "pages/order/index",
"style": {
"navigationBarTitleText": "租借记录"
}
},
{
"path": "pages/order/payment",
"style": {
"navigationBarTitleText": "订单支付",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/feedback/index",
"style": {
"navigationBarTitleText": "投诉与建议"
}
},
{
"path": "pages/help/index",
"style": {
"navigationBarTitleText": "帮助中心"
}
},
{
"path": "pages/device/detail",
"style": {
"navigationBarTitleText": "设备详情",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/serve/bagCheck/index",
"style": {
"navigationBarTitleText": "共享风扇"
}
},
{
"path": "pages/return/index",
"style": {
"navigationBarTitleText": "归还设备",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/order/success",
"style": {
"navigationBarTitleText": "支付成功",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "共享风扇",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#999999",
"selectedColor": "#1976D2",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-active.png"
},
{
"pagePath": "pages/my/index",
"text": "我的",
"iconPath": "static/user.png",
"selectedIconPath": "static/user-active.png"
}
]
}
{
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
"pages": [{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "共享风扇"
}
},
{
"path": "pages/my/index",
"style": {
"navigationBarTitleText": "个人中心"
}
},
{
"path": "pages/deposit/index",
"style": {
"navigationBarTitleText": "押金管理"
}
},
{
"path": "pages/order/index",
"style": {
"navigationBarTitleText": "租借记录"
}
},
{
"path": "pages/order/payment",
"style": {
"navigationBarTitleText": "订单支付",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/feedback/index",
"style": {
"navigationBarTitleText": "投诉与建议"
}
},
{
"path": "pages/help/index",
"style": {
"navigationBarTitleText": "帮助中心"
}
},
{
"path": "pages/device/detail",
"style": {
"navigationBarTitleText": "设备详情",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/serve/bagCheck/index",
"style": {
"navigationBarTitleText": "共享风扇"
}
},
{
"path": "pages/return/index",
"style": {
"navigationBarTitleText": "归还设备",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/order/success",
"style": {
"navigationBarTitleText": "支付成功",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/order/return-success",
"style": {
"navigationBarTitleText": "归还成功",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "共享风扇",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#999999",
"selectedColor": "#1976D2",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-active.png"
},
{
"pagePath": "pages/my/index",
"text": "我的",
"iconPath": "static/user.png",
"selectedIconPath": "static/user-active.png"
}
]
}
}
+335 -205
View File
@@ -1,206 +1,336 @@
<template>
<view class="deposit-container">
<!-- 押金金额卡片 -->
<view class="deposit-card">
<view class="title">押金余额</view>
<view class="amount">¥{{ depositAmount }}</view>
<button class="withdraw-btn" @click="handleWithdraw">提现</button>
</view>
<!-- 提现说明 -->
<view class="notice-card">
<view class="notice-title">
<view class="dot"></view>
<text>提现说明</text>
</view>
<view class="notice-content">
<view class="notice-item">1. 提现金额将原路退回支付账户</view>
<view class="notice-item">2. 提现申请提交后预计0-7个工作日到账</view>
<view class="notice-item">3. 如超时未收到请联系客服处理</view>
</view>
</view>
<!-- 押金记录 -->
<view class="record-card">
<view class="record-title">押金记录</view>
<view class="record-list">
<view class="record-item" v-for="(item, index) in records" :key="index">
<view class="record-info">
<text class="record-type">{{ item.type }}</text>
<text class="record-time">{{ item.time }}</text>
</view>
<text class="record-amount" :class="item.type === '退还' ? 'refund' : ''">
{{ item.type === '退还' ? '+' : '-' }}¥{{ item.amount }}
</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
depositAmount: '99.00',
records: [
{ type: '支付', time: '2024-03-20 15:30', amount: '99.00' },
{ type: '退还', time: '2024-03-19 12:00', amount: '99.00' },
]
}
},
methods: {
handleWithdraw() {
uni.showModal({
title: '确认提现',
content: '押金将原路退回,预计0-7个工作日到账',
success: (res) => {
if (res.confirm) {
uni.showToast({
title: '提现申请已提交',
icon: 'success'
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.deposit-container {
min-height: 100vh;
background: #f8f8f8;
padding: 30rpx;
.deposit-card {
background: linear-gradient(135deg, #1976D2, #64B5F6);
border-radius: 20rpx;
padding: 40rpx;
color: #fff;
text-align: center;
box-shadow: 0 4rpx 20rpx rgba(25,118,210,0.2);
.title {
font-size: 28rpx;
opacity: 0.9;
margin-bottom: 20rpx;
}
.amount {
font-size: 72rpx;
font-weight: bold;
margin-bottom: 40rpx;
}
.withdraw-btn {
background: #fff;
color: #1976D2;
width: 80%;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
font-size: 32rpx;
font-weight: 500;
margin: 0 auto;
&:active {
transform: scale(0.98);
}
}
}
.notice-card {
margin-top: 30rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.notice-title {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.dot {
width: 12rpx;
height: 12rpx;
background: #1976D2;
border-radius: 50%;
margin-right: 10rpx;
}
text {
font-size: 30rpx;
font-weight: 500;
color: #333;
}
}
.notice-content {
.notice-item {
font-size: 26rpx;
color: #666;
line-height: 1.8;
padding-left: 22rpx;
}
}
}
.record-card {
margin-top: 30rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.record-title {
font-size: 30rpx;
font-weight: 500;
color: #333;
margin-bottom: 20rpx;
border-left: 8rpx solid #1976D2;
padding-left: 20rpx;
}
.record-list {
.record-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.record-info {
.record-type {
font-size: 28rpx;
color: #333;
margin-bottom: 6rpx;
display: block;
}
.record-time {
font-size: 24rpx;
color: #999;
}
}
.record-amount {
font-size: 32rpx;
color: #333;
font-weight: 500;
&.refund {
color: #4CAF50;
}
}
}
}
}
}
<template>
<view class="deposit-container">
<!-- 押金金额卡片 -->
<view class="deposit-card">
<view class="title">押金余额</view>
<view class="amount">¥{{ depositAmount }}</view>
<button class="withdraw-btn" @click="handleWithdraw" :disabled="depositAmount <= 0">提现</button>
</view>
<!-- 提现说明 -->
<view class="notice-card">
<view class="notice-title">
<view class="dot"></view>
<text>提现说明</text>
</view>
<view class="notice-content">
<view class="notice-item">1. 提现金额将原路退回支付账户</view>
<view class="notice-item">2. 提现申请提交后预计0-7个工作日到账</view>
<view class="notice-item">3. 如超时未收到请联系客服处理</view>
</view>
</view>
<!-- 押金记录 -->
<view class="record-card" v-if="records.length > 0">
<view class="record-title">押金记录</view>
<view class="record-list">
<view class="record-item" v-for="(item, index) in records" :key="index">
<view class="record-info">
<text class="record-type">{{ item.type }}</text>
<text class="record-time">{{ item.time }}</text>
</view>
<text class="record-amount" :class="item.type === '退还' ? 'refund' : ''">
{{ item.type === '退还' ? '+' : '-' }}¥{{ item.amount }}
</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { getUserInfo } from '../../util/index.js'
import { withdrawDeposit,queryById } from '../../config/user.js'
export default {
data() {
return {
depositAmount: '0.00',
orderNo: '',
records: [],
orderId:''
}
},
onLoad() {
// this.loadUserInfo()
},
onShow() {
this.loadUserInfo()
},
methods: {
async loadUserInfo() {
try {
const res = await getUserInfo()
console.log('loadUserInfo',res);
if (res.code === 200) {
this.depositAmount = res.data.balanceAmount || '0.00'
this.orderNo = res.data.latestOrderNo || ''
this.orderId = res.data.latestOrderId||''
// 如果存在余额,获取押金记录
if (parseFloat(this.depositAmount) > 0 && this.orderNo) {
this.records = [
{
type: '支付',
time: this.formatDate(new Date()),
amount: this.depositAmount
}
]
} else {
this.records = []
}
}
} catch (error) {
console.error('获取用户信息失败:', error)
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
})
}
},
async handleWithdraw() {
if (parseFloat(this.depositAmount) <= 0) {
uni.showToast({
title: '无可提现余额',
icon: 'none'
})
return
}
if(this.orderId.length!=0||this.orderNo.length!=0){
const res = await queryById(Number(this.orderId))
console.log(res);
}
// if(this.orderNo.length!=0){
// uni.showToast({
// title:'当前存在进行中的订单',
// icon:'none'
// })
// return
// }
uni.showModal({
title: '确认提现',
content: '押金将原路退回,预计0-7个工作日到账',
success: async (res) => {
if (res.confirm) {
uni.showLoading({
title: '提现中...'
})
try {
console.log('发起提现请求,订单号:', this.orderNo)
const result = await withdrawDeposit(this.orderNo)
console.log('提现响应:', result)
if (result.code === 200) {
uni.hideLoading()
uni.showToast({
title: '提现申请已提交',
icon: 'success'
})
// 更新余额为0
this.depositAmount = '0.00'
this.records.push({
type: '退还',
time: this.formatDate(new Date()),
amount: this.depositAmount
})
// 重新加载用户信息
setTimeout(() => {
this.loadUserInfo()
}, 1500)
} else {
throw new Error(result.msg || '提现失败')
}
} catch (error) {
console.error('提现失败:', error)
uni.hideLoading()
// 更详细的错误处理
let errorMessage = '提现失败,请稍后再试';
// 如果有具体错误信息,使用它
if (error.message) {
// 常见错误消息处理
if (error.message.includes('尚未归还')) {
errorMessage = '当前订单尚未归还,请归还后再提现';
} else if (error.message.includes('已退还')) {
errorMessage = '押金已退还,无需重复提现';
} else if (error.message.includes('处理中')) {
errorMessage = '押金退还处理中,请耐心等待';
} else if (error.message.includes('余额为0')) {
errorMessage = '账户余额为0,无法提现';
} else {
// 使用后端返回的具体错误消息
errorMessage = error.message;
}
}
// 显示错误提示
uni.showModal({
title: '提现失败',
content: errorMessage,
showCancel: false
})
}
}
}
})
},
formatDate(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hours = date.getHours().toString().padStart(2, '0')
const minutes = date.getMinutes().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
}
}
</script>
<style lang="scss" scoped>
.deposit-container {
min-height: 100vh;
background: #f8f8f8;
padding: 30rpx;
.deposit-card {
background: linear-gradient(135deg, #1976D2, #64B5F6);
border-radius: 20rpx;
padding: 40rpx;
color: #fff;
text-align: center;
box-shadow: 0 4rpx 20rpx rgba(25,118,210,0.2);
.title {
font-size: 28rpx;
opacity: 0.9;
margin-bottom: 20rpx;
}
.amount {
font-size: 72rpx;
font-weight: bold;
margin-bottom: 40rpx;
}
.withdraw-btn {
background: #fff;
color: #1976D2;
width: 80%;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
font-size: 32rpx;
font-weight: 500;
margin: 0 auto;
&:active {
transform: scale(0.98);
}
&[disabled] {
background: rgba(255,255,255,0.6);
color: rgba(25,118,210,0.5);
}
}
}
.notice-card {
margin-top: 30rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.notice-title {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.dot {
width: 12rpx;
height: 12rpx;
background: #1976D2;
border-radius: 50%;
margin-right: 10rpx;
}
text {
font-size: 30rpx;
font-weight: 500;
color: #333;
}
}
.notice-content {
.notice-item {
font-size: 26rpx;
color: #666;
line-height: 1.8;
padding-left: 22rpx;
}
}
}
.record-card {
margin-top: 30rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.record-title {
font-size: 30rpx;
font-weight: 500;
color: #333;
margin-bottom: 20rpx;
border-left: 8rpx solid #1976D2;
padding-left: 20rpx;
}
.record-list {
.record-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.record-info {
.record-type {
font-size: 28rpx;
color: #333;
margin-bottom: 6rpx;
display: block;
}
.record-time {
font-size: 24rpx;
color: #999;
}
}
.record-amount {
font-size: 32rpx;
color: #333;
font-weight: 500;
&.refund {
color: #4CAF50;
}
}
}
}
}
}
</style>
+259 -35
View File
@@ -73,7 +73,7 @@
<view class="bottom-bar">
<view class="price-info" v-if="!hasActiveOrder">
<text class="deposit-text">押金</text>
<text class="deposit-amount">99</text>
<text class="deposit-amount">{{ depositAmount }}</text>
</view>
<button class="action-btn" :class="hasActiveOrder ? 'return' : 'rent'" @click="handleRent">
{{ hasActiveOrder ? '归还设备' : '立即租借' }}
@@ -85,7 +85,8 @@
<script>
import {
getDeviceInfo,
rentPowerBank
rentPowerBank,
updateOrderPackage
} from '@/config/user.js'
export default {
data() {
@@ -100,22 +101,8 @@
class: 'available'
},
selectedPackage: 1,
packages: [{
time: '1小时',
price: '2.00',
unitPrice: '2.00'
},
{
time: '4小时',
price: '6.00',
unitPrice: '1.50'
},
{
time: '12小时',
price: '15.00',
unitPrice: '1.25'
}
],
packages: [],
depositAmount: "99.00", // 默认押金金额
isLoggedIn: true,
phoneNumber: ''
}
@@ -123,15 +110,65 @@
onLoad(options) {
// console.log(options);
this.deviceId = options.deviceNo
console.log(options.deviceNo);
this.getDeviceInfo()
// 如果URL中包含了feeConfig参数,直接使用它
if (options.feeConfig) {
try {
console.log('从URL获取到feeConfig:', options.feeConfig)
const feeConfigStr = decodeURIComponent(options.feeConfig)
// 存储到设备信息中,这样后续处理逻辑可以保持不变
this.deviceInfo = { ...this.deviceInfo, feeConfig: feeConfigStr }
// 马上解析feeConfig并生成套餐选项
this.parseFeeConfig()
} catch (e) {
console.error('解析URL中的feeConfig失败:', e)
// 如果解析失败,继续正常流程获取设备信息
this.checkOrderStatus()
this.getDeviceInfo()
}
} else {
// 正常流程
this.checkOrderStatus() // 新增状态检查
console.log(options.deviceNo);
this.getDeviceInfo()
}
},
methods: {
// 检查登录状态和订单
async getDeviceInfo() {
const res = await getDeviceInfo(this.deviceId);
if (res.code == 200) {
this.deviceInfo = res.data
this.deviceInfo = res.data.device || {};
// 更新设备位置信息
if (this.deviceInfo.deviceLocation) {
this.deviceLocation = this.deviceInfo.deviceLocation;
} else if (res.data.position && res.data.position.name) {
this.deviceLocation = res.data.position.name;
}
// 获取押金金额
if (this.deviceInfo.depositAmount) {
this.depositAmount = this.deviceInfo.depositAmount;
}
// 更新设备状态
if (this.deviceInfo.status) {
if (this.deviceInfo.status === 'online') {
this.deviceStatus = {
text: '可使用',
class: 'available'
};
} else if (this.deviceInfo.status === 'offline') {
this.deviceStatus = {
text: '离线',
class: 'offline'
};
}
}
// 使用抽取的方法解析feeConfig并生成套餐选项
this.parseFeeConfig();
}
},
@@ -162,10 +199,22 @@
const result = await this.$api.checkActiveOrder()
if (result.hasOrder) {
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
uni.redirectTo({
const order = result.order; // 假设后端返回 order 对象
// 检查订单状态
if (order.status === 'waiting_for_payment') {
// 跳转支付页面,带上订单ID
uni.redirectTo({
url: `/pages/order/payment?orderId=${order.orderId}&deviceId=${this.deviceId}`
})
}else if(order.status === 'in_used'){
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
uni.redirectTo({
url: `/pages/device/return?deviceId=${this.deviceId}`
})
}
}
} catch (error) {
uni.showToast({
@@ -200,16 +249,8 @@
return
}
const selectedPkg = this.packages[this.selectedPackage]
uni.showModal({
title: '确认租借',
content: `确认支付押金¥99.00及${selectedPkg.time}套餐费用¥${selectedPkg.price}`,
success: (res) => {
if (res.confirm) {
this.submitRentOrder()
}
}
})
// 直接提交订单,不显示确认对话框
this.submitRentOrder()
},
// 提交租借订单
@@ -230,12 +271,46 @@
// 获取后端返回的订单信息
const order = rentResult.data
// --- 新增:立即更新订单套餐信息 ---
try {
let packageTimeMinutes = 0;
if (selectedPkg.time.includes('小时')) {
packageTimeMinutes = parseInt(selectedPkg.time) * 60;
} else if (selectedPkg.time.includes('分钟')) {
packageTimeMinutes = parseInt(selectedPkg.time);
} else {
packageTimeMinutes = parseInt(selectedPkg.time) * 60; // 默认按小时处理
}
const updateRes = await updateOrderPackage({
orderId: order.orderId,
packageTime: packageTimeMinutes,
packagePrice: parseFloat(selectedPkg.price)
});
if (updateRes.code !== 200) {
console.warn("更新订单套餐信息失败:", updateRes.msg);
// 这里可以选择是否提示用户或阻止流程,当前不阻止
} else {
console.log("订单套餐信息已提前更新");
}
} catch (updateError) {
console.error("更新订单套餐信息时出错:", updateError);
// 即使更新失败,也继续尝试跳转支付,让用户完成支付
}
// --- 更新结束 ---
// --- 新增:计算总金额 ---
const deposit = parseFloat(this.depositAmount);
const packagePrice = parseFloat(selectedPkg.price);
const totalAmount = (deposit + packagePrice).toFixed(2);
// --- 计算结束 ---
uni.hideLoading()
// 跳转到订单支付页面,传递订单ID套餐信息
// 跳转到订单支付页面,传递订单ID套餐信息和总金额
uni.redirectTo({
url: `/pages/order/payment?orderId=${order.orderId}&packageTime=${selectedPkg.time}&packagePrice=${selectedPkg.price}`
url: `/pages/order/payment?orderId=${order.orderId}&packageTimeHours=${selectedPkg.time.replace('小时', '')}&packagePrice=${selectedPkg.price}&totalAmount=${totalAmount}&depositAmount=${this.depositAmount}${this.deviceInfo && this.deviceInfo.feeConfig ? '&feeConfig=' + encodeURIComponent(this.deviceInfo.feeConfig) : ''}`
})
} catch (error) {
uni.hideLoading()
@@ -244,6 +319,155 @@
icon: 'none'
})
}
},
// 单独抽取解析feeConfig的逻辑
parseFeeConfig() {
if (this.deviceInfo.feeConfig) {
try {
const feeConfig = JSON.parse(this.deviceInfo.feeConfig);
// 检查是否为新格式 [{"hour":1,"timesPrice":4},{"hour":3,"timesPrice":10},{"hour":5,"timesPrice":15}]
if (feeConfig.length > 0 && 'hour' in feeConfig[0] && 'timesPrice' in feeConfig[0]) {
// 新格式处理 - 直接使用所有套餐
this.packages = feeConfig.map(pkg => {
const hour = pkg.hour;
const price = pkg.timesPrice;
const unitPrice = (price / hour).toFixed(2);
return {
time: `${hour}小时`,
price: price.toFixed(2),
unitPrice: unitPrice,
hour: hour // 添加小时信息,用于后续处理
};
});
// 按小时排序
this.packages.sort((a, b) => a.hour - b.hour);
} else {
// 旧格式处理
// 通常使用common规格的配置
const commonConfig = feeConfig.find(item => item.specCode === 'common') || feeConfig[0];
if (commonConfig) {
// 根据收费类型生成套餐
if (this.deviceInfo.feeType === 'hour') {
// 按小时收费
const hourPrice = commonConfig.hourPrice > 0 ? commonConfig.hourPrice : commonConfig.timesPrice / 6;
this.packages = [
{
time: '1小时',
price: hourPrice.toFixed(2),
unitPrice: hourPrice.toFixed(2),
hour: 1
},
{
time: '6小时',
price: (hourPrice * 6).toFixed(2),
unitPrice: hourPrice.toFixed(2),
hour: 6
},
{
time: '12小时',
price: (hourPrice * 12).toFixed(2),
unitPrice: hourPrice.toFixed(2),
hour: 12
}
];
} else if (this.deviceInfo.feeType === 'times') {
// 按次收费
const timesPrice = commonConfig.timesPrice;
this.packages = [
{
time: '1次',
price: timesPrice.toFixed(2),
unitPrice: timesPrice.toFixed(2),
hour: 1
}
];
} else {
// 默认套餐
this.packages = [
{
time: '1小时',
price: '2.00',
unitPrice: '2.00',
hour: 1
},
{
time: '6小时',
price: '10.00',
unitPrice: '1.67',
hour: 6
},
{
time: '12小时',
price: '15.00',
unitPrice: '1.25',
hour: 12
}
];
}
}
}
// 默认选中中间套餐
this.selectedPackage = Math.min(1, this.packages.length - 1);
} catch (e) {
console.error('解析设备费用配置失败:', e);
// 使用默认套餐
this.packages = [
{
time: '1小时',
price: '2.00',
unitPrice: '2.00',
hour: 1
},
{
time: '6小时',
price: '10.00',
unitPrice: '1.67',
hour: 6
},
{
time: '12小时',
price: '15.00',
unitPrice: '1.25',
hour: 12
}
];
// 默认选中中间套餐
this.selectedPackage = 1;
}
} else {
// 如果没有feeConfig,使用默认套餐
this.packages = [
{
time: '1小时',
price: '2.00',
unitPrice: '2.00',
hour: 1
},
{
time: '6小时',
price: '10.00',
unitPrice: '1.67',
hour: 6
},
{
time: '12小时',
price: '15.00',
unitPrice: '1.25',
hour: 12
}
];
// 默认选中中间套餐
this.selectedPackage = 1;
}
}
}
}
+37 -4
View File
@@ -115,10 +115,43 @@ export default {
return
}
// TODO: 提交反馈
uni.showToast({
title: '提交成功',
icon: 'success'
// 构建反馈数据
const feedbackData = {
type: this.types[this.selectedType],
content: this.description,
phone: this.contact,
images: this.images
}
// 调用提交接口
uni.request({
url: '/app/feedback/add',
method: 'POST',
data: feedbackData,
success: (res) => {
if (res.statusCode === 200) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
// 清空表单
this.selectedType = -1
this.description = ''
this.contact = ''
this.images = []
} else {
uni.showToast({
title: '提交失败',
icon: 'none'
})
}
},
fail: () => {
uni.showToast({
title: '提交失败',
icon: 'none'
})
}
})
}
}
+162 -162
View File
@@ -1,163 +1,163 @@
<template>
<view class="help-container">
<!-- 常见问题 -->
<view class="faq-list">
<view
class="faq-item"
v-for="(item, index) in faqList"
:key="index"
@click="toggleFaq(index)"
>
<view class="faq-header">
<text class="question">{{ item.question }}</text>
<view class="arrow" :class="{ open: item.isOpen }"></view>
</view>
<view class="answer" v-show="item.isOpen">
{{ item.answer }}
</view>
</view>
</view>
<!-- 联系客服 -->
<view class="contact-card">
<view class="contact-title">{{ HELP_CONTENT.CONTACT.TITLE }}</view>
<view class="contact-content">
<view class="contact-item">
<text class="label">{{ HELP_CONTENT.CONTACT.PHONE.LABEL }}</text>
<text class="value" @click="makePhoneCall">{{ HELP_CONTENT.CONTACT.PHONE.VALUE }}</text>
</view>
<view class="contact-item">
<text class="label">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.LABEL }}</text>
<text class="value">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.VALUE }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { HELP_CONTENT } from '@/constants/help'
export default {
data() {
return {
HELP_CONTENT,
faqList: HELP_CONTENT.FAQ_LIST.map(item => ({
...item,
isOpen: false
}))
}
},
methods: {
toggleFaq(index) {
this.faqList[index].isOpen = !this.faqList[index].isOpen
},
makePhoneCall() {
uni.makePhoneCall({
phoneNumber: HELP_CONTENT.CONTACT.PHONE.VALUE
})
}
}
}
</script>
<style lang="scss" scoped>
.help-container {
min-height: 100vh;
background: #f8f8f8;
padding: 30rpx;
.faq-list {
background: #fff;
border-radius: 20rpx;
padding: 20rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.faq-item {
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.faq-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 20rpx;
.question {
font-size: 30rpx;
color: #333;
flex: 1;
padding-right: 20rpx;
}
.arrow {
width: 16rpx;
height: 16rpx;
border-right: 4rpx solid #999;
border-bottom: 4rpx solid #999;
transform: rotate(45deg);
transition: all 0.3s;
&.open {
transform: rotate(-135deg);
}
}
}
.answer {
font-size: 28rpx;
color: #666;
line-height: 1.6;
padding: 0 20rpx 30rpx;
background: #f9f9f9;
border-radius: 10rpx;
margin: 0 20rpx 20rpx;
}
}
}
.contact-card {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.contact-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-bottom: 20rpx;
border-left: 8rpx solid #1976D2;
padding-left: 20rpx;
}
.contact-content {
.contact-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
.label {
font-size: 28rpx;
color: #666;
}
.value {
font-size: 28rpx;
color: #333;
font-weight: 500;
&:active {
opacity: 0.7;
}
}
}
}
}
}
<template>
<view class="help-container">
<!-- 常见问题 -->
<view class="faq-list">
<view
class="faq-item"
v-for="(item, index) in faqList"
:key="index"
@click="toggleFaq(index)"
>
<view class="faq-header">
<text class="question">{{ item.question }}</text>
<view class="arrow" :class="{ open: item.isOpen }"></view>
</view>
<view class="answer" v-show="item.isOpen">
{{ item.answer }}
</view>
</view>
</view>
<!-- 联系客服 -->
<view class="contact-card">
<view class="contact-title">{{ HELP_CONTENT.CONTACT.TITLE }}</view>
<view class="contact-content">
<view class="contact-item">
<text class="label">{{ HELP_CONTENT.CONTACT.PHONE.LABEL }}</text>
<text class="value" @click="makePhoneCall">{{ HELP_CONTENT.CONTACT.PHONE.VALUE }}</text>
</view>
<view class="contact-item">
<text class="label">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.LABEL }}</text>
<text class="value">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.VALUE }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { HELP_CONTENT } from '@/constants/help'
export default {
data() {
return {
HELP_CONTENT,
faqList: HELP_CONTENT.FAQ_LIST.map(item => ({
...item,
isOpen: false
}))
}
},
methods: {
toggleFaq(index) {
this.faqList[index].isOpen = !this.faqList[index].isOpen
},
makePhoneCall() {
uni.makePhoneCall({
phoneNumber: HELP_CONTENT.CONTACT.PHONE.VALUE
})
}
}
}
</script>
<style lang="scss" scoped>
.help-container {
min-height: 100vh;
background: #f8f8f8;
padding: 30rpx;
.faq-list {
background: #fff;
border-radius: 20rpx;
padding: 20rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.faq-item {
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.faq-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 20rpx;
.question {
font-size: 30rpx;
color: #333;
flex: 1;
padding-right: 20rpx;
}
.arrow {
width: 16rpx;
height: 16rpx;
border-right: 4rpx solid #999;
border-bottom: 4rpx solid #999;
transform: rotate(45deg);
transition: all 0.3s;
&.open {
transform: rotate(-135deg);
}
}
}
.answer {
font-size: 28rpx;
color: #666;
line-height: 1.6;
padding: 0 20rpx 30rpx;
background: #f9f9f9;
border-radius: 10rpx;
margin: 0 20rpx 20rpx;
}
}
}
.contact-card {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.contact-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-bottom: 20rpx;
border-left: 8rpx solid #1976D2;
padding-left: 20rpx;
}
.contact-content {
.contact-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
.label {
font-size: 28rpx;
color: #666;
}
.value {
font-size: 28rpx;
color: #333;
font-weight: 500;
&:active {
opacity: 0.7;
}
}
}
}
}
}
</style>
+395 -323
View File
@@ -1,323 +1,395 @@
<template>
<view class="container">
<!-- 宣传图片区域 -->
<view class="banner">
<view class="temp-banner">
<text class="banner-text">共享风扇</text>
<text class="banner-subtitle">让清凉随身携带</text>
<view class="banner-bg"></view>
</view>
</view>
<!-- 扫码按钮区域 -->
<view class="scan-area">
<view class="scan-btn" @click="handleScan">
<view class="btn-content">
<image class="btn-icon" src="../../static/scan-icon.png" mode="aspectFit" />
<text class="btn-text">扫一扫</text>
</view>
<text class="btn-desc">扫描设备二维码使用或归还</text>
</view>
</view>
<!-- 使用提示区域 -->
<view class="tips-section">
<view class="tips-header">
<view class="tips-title">使用小贴士</view>
</view>
<view class="tips-list">
<view class="tip-item">
<view class="tip-dot"></view>
<text>租借时间每次最长可租借12小时</text>
</view>
<view class="tip-item">
<view class="tip-dot"></view>
<text>押金说明租借需支付99元押金归还后自动退还</text>
</view>
<view class="tip-item">
<view class="tip-dot"></view>
<text>收费标准2/小时不足1小时按1小时计算</text>
</view>
<view class="tip-item">
<view class="tip-dot"></view>
<text>爱护提示请勿将设备带离指定区域保持设备清洁</text>
</view>
</view>
</view>
</view>
</template>
<script>
import {getQueryString }from '@/util/index.js'
export default {
methods: {
async handleScan() {
try {
const scanResult = await new Promise((resolve, reject) => {
uni.scanCode({
success: resolve,
fail: reject
})
})
let deviceNo = getQueryString(scanResult.path, 'deviceNo')
console.log('扫码路径:', scanResult.path)
console.log('解析到的设备号:', deviceNo)
// 检查是否有使用中的订单
const inUseRes = await uni.request({
url: `${uni.getStorageSync('baseUrl') || 'http://127.0.0.1:8080'}/app/order/inUse`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
console.log('使用中订单检查结果:', JSON.stringify(inUseRes))
if (inUseRes.statusCode === 200 && inUseRes.data.code === 200 && inUseRes.data.data) {
// 存在使用中的订单,跳转到归还页面
const inUseOrder = inUseRes.data.data
console.log('检测到使用中订单,准备跳转:', inUseOrder)
// 直接使用reLaunch而不是navigateTo以确保页面跳转
uni.reLaunch({
url: `/pages/return/index?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
})
console.log('已发起页面跳转')
return
}
// 检查是否有待支付订单
const orderRes = await uni.request({
url: `${uni.getStorageSync('baseUrl') || 'http://127.0.0.1:8080'}/app/order/unpaid`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
console.log('待支付订单检查结果:', JSON.stringify(orderRes))
if (orderRes.statusCode === 200 && orderRes.data.code === 200 && orderRes.data.data) {
// 存在待支付订单,跳转到支付页面
const unpaidOrder = orderRes.data.data
console.log('检测到待支付订单,准备跳转:', unpaidOrder)
uni.navigateTo({
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
})
} else {
// 无待支付订单,正常跳转到设备检查页面
console.log('无待支付订单,跳转到设备检查页面, deviceNo:', deviceNo)
uni.navigateTo({
url: `/pages/serve/bagCheck/index?deviceNo=${deviceNo}`
})
}
} catch (error) {
console.error('扫码处理失败:', error)
uni.showToast({
title: '扫码失败',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
height: 87.5vh;
background: #f8f8f8;
padding-bottom: 40rpx;
.banner {
padding: 30rpx;
.temp-banner {
height: 300rpx;
background: linear-gradient(135deg, #1976D2, #42A5F5);
border-radius: 30rpx;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
box-shadow: 0 8rpx 32rpx rgba(25, 118, 210, 0.2);
.banner-text {
font-size: 56rpx;
font-weight: bold;
margin-bottom: 20rpx;
position: relative;
z-index: 1;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}
.banner-subtitle {
font-size: 32rpx;
opacity: 0.95;
position: relative;
z-index: 1;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}
.banner-bg {
position: absolute;
right: -60rpx;
bottom: -60rpx;
width: 300rpx;
height: 300rpx;
background: rgba(255,255,255,0.1);
border-radius: 50%;
transform: rotate(-15deg);
}
&::after {
content: '';
position: absolute;
left: -80rpx;
top: -80rpx;
width: 240rpx;
height: 240rpx;
background: rgba(255,255,255,0.08);
border-radius: 50%;
}
}
}
.scan-area {
padding: 20rpx 30rpx 40rpx;
display: flex;
justify-content: center;
.scan-btn {
width: 460rpx;
height: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #00C853, #69F0AE);
border-radius: 30rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 200, 83, 0.2);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:active {
transform: scale(0.98);
box-shadow: 0 4rpx 16rpx rgba(0, 200, 83, 0.15);
}
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(rgba(255,255,255,0.1), transparent);
}
.btn-content {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
position: relative;
z-index: 1;
.btn-icon {
width: 48rpx;
height: 48rpx;
margin-right: 16rpx;
}
.btn-text {
font-size: 42rpx;
font-weight: 600;
color: #fff;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}
}
.btn-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.95);
position: relative;
z-index: 1;
}
}
}
.tips-section {
margin: 0 30rpx;
background: #fff;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.05);
overflow: hidden;
.tips-header {
padding: 30rpx;
background: linear-gradient(to right, #F5F9FF, #fff);
border-bottom: 2rpx solid #f0f0f0;
.tips-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
position: relative;
padding-left: 24rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 32rpx;
background: #1976D2;
border-radius: 4rpx;
}
}
}
.tips-list {
padding: 20rpx 30rpx;
.tip-item {
display: flex;
align-items: center;
margin-bottom: 24rpx;
padding: 0 10rpx;
&:last-child {
margin-bottom: 0;
}
.tip-dot {
width: 12rpx;
height: 12rpx;
background: #1976D2;
border-radius: 50%;
margin-right: 16rpx;
flex-shrink: 0;
box-shadow: 0 2rpx 6rpx rgba(25,118,210,0.2);
}
text {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
}
}
}
}
</style>
<template>
<view class="container">
<!-- 宣传图片区域 -->
<view class="banner">
<view class="temp-banner">
<text class="banner-text">共享风扇</text>
<text class="banner-subtitle">让清凉随身携带</text>
<view class="banner-bg"></view>
</view>
</view>
<!-- 扫码按钮区域 -->
<view class="scan-area">
<view class="scan-btn" @click="handleScan">
<view class="btn-content">
<image class="btn-icon" src="../../static/scan-icon.png" mode="aspectFit" />
<text class="btn-text">扫一扫</text>
</view>
<text class="btn-desc">扫描设备二维码使用或归还</text>
</view>
</view>
<!-- 使用提示区域 -->
<view class="tips-section">
<view class="tips-header">
<view class="tips-title">使用小贴士</view>
</view>
<view class="tips-list">
<view class="tip-item">
<view class="tip-dot"></view>
<text>租借时间每次最长可租借12小时</text>
</view>
<view class="tip-item">
<view class="tip-dot"></view>
<text>押金说明租借需支付99元押金归还后自动退还</text>
</view>
<view class="tip-item">
<view class="tip-dot"></view>
<text>收费标准2/小时不足1小时按1小时计算</text>
</view>
<view class="tip-item">
<view class="tip-dot"></view>
<text>爱护提示请勿将设备带离指定区域保持设备清洁</text>
</view>
</view>
</view>
</view>
</template>
<script>
import {getQueryString, wxLogin }from '@/util/index.js'
import {
URL
}from"@/config/url.js"
import { getDeviceInfo } from '@/config/user.js'
export default {
methods: {
async handleScan() {
try {
const scanResult = await new Promise((resolve, reject) => {
uni.scanCode({
success: resolve,
fail: reject
})
})
let deviceNo = getQueryString(scanResult.path, 'deviceNo')
console.log('扫码路径:', scanResult.path)
console.log('解析到的设备号:', deviceNo)
if (!deviceNo) {
uni.showToast({
title: '无效的设备二维码',
icon: 'none'
})
return
}
// 直接在当前页面查询是否有使用中的订单,避免跳转到中间页面
if (!uni.getStorageSync('token')) {
await wxLogin()
}
// 检查是否有使用中的订单
const inUseRes = await uni.request({
url: `${URL || 'http://127.0.0.1:8080'}/app/order/inUse`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
console.log('使用中订单检查结果:', JSON.stringify(inUseRes))
if (inUseRes.statusCode == 200 && inUseRes.data.code == 200 && inUseRes.data.data) {
// 存在使用中的订单,跳转到归还页面
const inUseOrder = inUseRes.data.data
console.log('检测到使用中订单,准备跳转:', inUseOrder)
// 直接使用reLaunch而不是navigateTo以确保页面跳转
uni.reLaunch({
url: `/pages/return/index?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
})
console.log('已发起页面跳转')
return
}
// 检查是否有待支付订单
const orderRes = await uni.request({
url: `${URL || 'http://127.0.0.1:8080'}/app/order/unpaid`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
console.log('待支付订单检查结果:', JSON.stringify(orderRes))
if (orderRes.statusCode == 200 && orderRes.data.code == 200 && orderRes.data.data) {
// 存在待支付订单,跳转到支付页面
const unpaidOrder = orderRes.data.data
console.log('检测到待支付订单,准备跳转:', unpaidOrder)
uni.navigateTo({
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
})
} else {
// 修改:直接获取设备信息,而不是跳转到详情页面
console.log('无待支付订单,获取设备信息, deviceNo:', deviceNo)
try {
// 获取设备信息
const deviceInfoRes = await getDeviceInfo(deviceNo)
if (deviceInfoRes.code == 200 && deviceInfoRes.data && deviceInfoRes.data.device) {
const deviceInfo = deviceInfoRes.data.device
// 如果有feeConfig,直接解析并处理
if (deviceInfo.feeConfig) {
console.log('获取到设备feeConfig信息:', deviceInfo.feeConfig)
// 这里可以直接解析feeConfig并进行前端处理
try {
const feeConfig = JSON.parse(deviceInfo.feeConfig)
// 根据解析后的feeConfig进行页面跳转并传递信息
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}&feeConfig=${encodeURIComponent(deviceInfo.feeConfig)}`
})
} catch (e) {
console.error('解析feeConfig失败:', e)
// 解析失败时仍然跳转到详情页面,由详情页面处理
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
} else {
// 没有feeConfig时,跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
} else {
console.error('获取设备信息失败:', deviceInfoRes.msg || '未知错误')
uni.showToast({
title: '获取设备信息失败',
icon: 'none'
})
// 失败时仍然跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
} catch (error) {
console.error('获取设备信息异常:', error)
uni.showToast({
title: '获取设备信息失败',
icon: 'none'
})
// 异常时仍然跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
}
} catch (error) {
console.error('扫码处理失败:', error)
uni.showToast({
title: '扫码失败',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
height: 87.5vh;
background: #f8f8f8;
padding-bottom: 40rpx;
.banner {
padding: 30rpx;
.temp-banner {
height: 300rpx;
background: linear-gradient(135deg, #1976D2, #42A5F5);
border-radius: 30rpx;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
box-shadow: 0 8rpx 32rpx rgba(25, 118, 210, 0.2);
.banner-text {
font-size: 56rpx;
font-weight: bold;
margin-bottom: 20rpx;
position: relative;
z-index: 1;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}
.banner-subtitle {
font-size: 32rpx;
opacity: 0.95;
position: relative;
z-index: 1;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}
.banner-bg {
position: absolute;
right: -60rpx;
bottom: -60rpx;
width: 300rpx;
height: 300rpx;
background: rgba(255,255,255,0.1);
border-radius: 50%;
transform: rotate(-15deg);
}
&::after {
content: '';
position: absolute;
left: -80rpx;
top: -80rpx;
width: 240rpx;
height: 240rpx;
background: rgba(255,255,255,0.08);
border-radius: 50%;
}
}
}
.scan-area {
padding: 20rpx 30rpx 40rpx;
display: flex;
justify-content: center;
.scan-btn {
width: 460rpx;
height: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #00C853, #69F0AE);
border-radius: 30rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 200, 83, 0.2);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:active {
transform: scale(0.98);
box-shadow: 0 4rpx 16rpx rgba(0, 200, 83, 0.15);
}
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(rgba(255,255,255,0.1), transparent);
}
.btn-content {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
position: relative;
z-index: 1;
.btn-icon {
width: 48rpx;
height: 48rpx;
margin-right: 16rpx;
}
.btn-text {
font-size: 42rpx;
font-weight: 600;
color: #fff;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}
}
.btn-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.95);
position: relative;
z-index: 1;
}
}
}
.tips-section {
margin: 0 30rpx;
background: #fff;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.05);
overflow: hidden;
.tips-header {
padding: 30rpx;
background: linear-gradient(to right, #F5F9FF, #fff);
border-bottom: 2rpx solid #f0f0f0;
.tips-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
position: relative;
padding-left: 24rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 32rpx;
background: #1976D2;
border-radius: 4rpx;
}
}
}
.tips-list {
padding: 20rpx 30rpx;
.tip-item {
display: flex;
align-items: center;
margin-bottom: 24rpx;
padding: 0 10rpx;
&:last-child {
margin-bottom: 0;
}
.tip-dot {
width: 12rpx;
height: 12rpx;
background: #1976D2;
border-radius: 50%;
margin-right: 16rpx;
flex-shrink: 0;
box-shadow: 0 2rpx 6rpx rgba(25,118,210,0.2);
}
text {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
}
}
}
}
</style>
+501 -501
View File
File diff suppressed because it is too large Load Diff
+29 -10
View File
@@ -73,14 +73,22 @@ export default {
if (res.code === 200 && res.data) {
// 将获取到的订单添加到列表中
const orderData = res.data;
console.log('特定订单数据:', JSON.stringify(orderData));
console.log('特定订单的开始时间:', orderData.startTime);
console.log('特定订单的创建时间:', orderData.createTime);
// 使用实际的startTime字段,如果没有则尝试使用createTime
const orderStartTime = orderData.startTime || orderData.createTime || '';
console.log('特定订单最终显示的开始时间:', orderStartTime);
// 格式化订单数据
const formattedOrder = {
orderNo: orderData.orderId,
status: orderData.orderStatus,
deviceId: orderData.deviceNo,
startTime: orderData.createTime,
startTime: orderStartTime,
endTime: orderData.endTime || '',
amount: orderData.amount || '0.00'
amount: orderData.payAmount || orderData.actualDeviceAmount || '0.00'
};
// 将订单添加到列表开头
@@ -107,15 +115,26 @@ export default {
try {
const res = await getOrderList(statusList);
if (res.code === 200 && res.data && res.data.records) {
console.log('API返回的订单列表数据:', JSON.stringify(res.data.records));
// 处理订单列表数据
this.orderList = res.data.records.map(item => ({
orderNo: item.orderId,
status: item.orderStatus,
deviceId: item.deviceNo,
startTime: item.createTime,
endTime: item.endTime || '',
amount: item.amount || '0.00'
}));
this.orderList = res.data.records.map(item => {
console.log(`订单 ${item.orderId} 的开始时间:`, item.startTime);
console.log(`订单 ${item.orderId} 的创建时间:`, item.createTime);
// 使用实际的startTime字段,如果没有则尝试使用createTime
const orderStartTime = item.startTime || item.createTime || '';
console.log(`订单 ${item.orderId} 最终显示的开始时间:`, orderStartTime);
return {
orderNo: item.orderId,
status: item.orderStatus,
deviceId: item.deviceNo,
startTime: orderStartTime,
endTime: item.endTime || '',
amount: item.payAmount || item.actualDeviceAmount || '0.00'
};
});
}
} catch (error) {
console.error('获取订单列表失败:', error);
+582 -588
View File
File diff suppressed because it is too large Load Diff
+443
View File
@@ -0,0 +1,443 @@
<template>
<view class="success-container">
<!-- 支付成功状态 -->
<view class="status-card">
<view class="status-icon success"></view>
<view class="status-text">归还成功</view>
<view class="status-desc">您的充电宝已归还费用已从押金中扣除</view>
</view>
<!-- 订单信息 -->
<view class="order-card">
<view class="card-title">订单信息</view>
<view class="info-item">
<text class="label">订单号</text>
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
</view>
<view class="info-item">
<text class="label">设备号</text>
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
</view>
<view class="info-item">
<text class="label">使用时长</text>
<text class="value">{{ orderInfo.usedTime || '-' }}</text>
</view>
<view class="info-item">
<text class="label">套餐时长</text>
<text class="value">{{ orderInfo.packageTime || '1小时' }}</text>
</view>
<view class="info-item">
<text class="label">超出时长</text>
<text class="value">{{ orderInfo.extraTime || '0分钟' }}</text>
</view>
<view class="info-item">
<text class="label">归还时间</text>
<text class="value">{{ orderInfo.endTime || '-' }}</text>
</view>
</view>
<!-- 费用信息 -->
<view class="refund-card">
<view class="card-title">费用信息</view>
<view class="info-item">
<text class="label">套餐费用</text>
<text class="value">{{ orderInfo.packagePrice || '0.00' }}</text>
</view>
<view class="info-item">
<text class="label">超时费用</text>
<text class="value">{{ orderInfo.extraFee || '0.00' }}</text>
</view>
<view class="info-item">
<text class="label">总费用</text>
<text class="value">{{ orderInfo.currentFee || '0.00' }}</text>
</view>
<view class="info-item">
<text class="label">押金</text>
<text class="value">{{ orderInfo.deposit || '99.00' }}</text>
</view>
<view class="info-item">
<text class="label">退还金额</text>
<text class="value highlight">{{ orderInfo.refundAmount || '99.00' }}</text>
</view>
<view class="info-item">
<text class="label">退还状态</text>
<text class="value" :class="orderInfo.withdrawStatus || 'waiting'">{{ getWithdrawStatusText() }}</text>
</view>
</view>
<!-- 退款说明卡片 -->
<view class="notice-card">
<view class="card-title">退款说明</view>
<view class="notice-content">
<text>1. 押金剩余金额需要您手动申请提现</text>
<text>2. 提现申请提交后将在1-3个工作日内退还到原支付账户</text>
<text>3. 如有疑问请联系客服</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="button-group">
<button class="primary-btn" @click="handleWithdraw" v-if="!orderInfo.isWithdrawn && orderInfo.refundAmount > 0">申请退款</button>
<button class="primary-btn" @click="goToHome">返回首页</button>
</view>
</view>
</template>
<script>
import { queryById } from '@/config/user.js'
import {
URL
}from"@/config/url.js"
export default {
data() {
return {
orderId: '',
orderInfo: {
orderNo: '',
deviceNo: '',
usedTime: '',
currentFee: '0.00',
deposit: '99.00',
refundAmount: '99.00',
endTime: '',
withdrawStatus: 'waiting',
isWithdrawn: false
}
}
},
onLoad(options) {
if (options && options.orderId) {
this.orderId = options.orderId;
this.loadOrderInfo();
} else {
uni.showToast({
title: '订单ID不能为空',
icon: 'none'
});
setTimeout(() => {
this.goToHome();
}, 1500);
}
},
methods: {
// 获取退款状态文本
getWithdrawStatusText() {
const statusMap = {
'waiting': '待申请',
'processing': '处理中',
'success': '已退款',
'failed': '退款失败'
};
return statusMap[this.orderInfo.withdrawStatus] || '待申请';
},
// 加载订单信息
async loadOrderInfo() {
try {
uni.showLoading({ title: '加载中' });
const result = await queryById(this.orderId);
if (result.code === 200 && result.data) {
const orderData = result.data;
// 从remark字段中解析使用信息
let packageMinutes = 60;
let extraMinutes = 0;
let usedMinutes = 0;
let packagePrice = '0.00';
let extraFee = '0.00';
if (orderData.remark) {
try {
// 解析remark字段
const remarkInfo = orderData.remark;
// 尝试提取使用时长
const usedTimeMatch = remarkInfo.match(/使用时长:(\d+)分钟/);
if (usedTimeMatch && usedTimeMatch[1]) {
usedMinutes = parseInt(usedTimeMatch[1]);
}
// 尝试提取套餐时长
const packageTimeMatch = remarkInfo.match(/套餐时长:(\d+)分钟/);
if (packageTimeMatch && packageTimeMatch[1]) {
packageMinutes = parseInt(packageTimeMatch[1]);
}
// 尝试提取超出时长
const extraTimeMatch = remarkInfo.match(/超出时长:(\d+)分钟/);
if (extraTimeMatch && extraTimeMatch[1]) {
extraMinutes = parseInt(extraTimeMatch[1]);
}
// 尝试提取套餐费用
const packagePriceMatch = remarkInfo.match(/套餐费用:([\d.]+)元/);
if (packagePriceMatch && packagePriceMatch[1]) {
packagePrice = packagePriceMatch[1];
}
// 尝试提取超时费用
const extraFeeMatch = remarkInfo.match(/超时费用:([\d.]+)元/);
if (extraFeeMatch && extraFeeMatch[1]) {
extraFee = extraFeeMatch[1];
}
console.log('从remark解析到的信息:', {
usedMinutes,
packageMinutes,
extraMinutes,
packagePrice,
extraFee
});
} catch (e) {
console.error('解析remark字段失败:', e);
}
}
this.orderInfo = {
orderNo: orderData.orderNo || '',
deviceNo: orderData.deviceNo || '',
usedTime: usedMinutes + '分钟',
packageTime: packageMinutes + '分钟',
extraTime: extraMinutes + '分钟',
packagePrice: packagePrice,
extraFee: extraFee,
currentFee: orderData.actualDeviceAmount || '0.00',
deposit: orderData.depositAmount || '99.00',
refundAmount: orderData.residueAmount || '99.00',
endTime: orderData.endTime || '',
withdrawStatus: orderData.withdrawStatus || 'waiting',
isWithdrawn: orderData.withdrawStatus === 'success'
};
} else {
throw new Error(result.msg || '获取订单信息失败');
}
} catch (error) {
console.error('加载订单信息错误:', error);
uni.showToast({
title: error.message || '获取订单信息失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
},
// 申请退款
async handleWithdraw() {
try {
uni.showLoading({ title: '处理中' });
const res = await uni.request({
url: `${URL || 'http://127.0.0.1:8080'}/app/withdraw/add/${this.orderInfo.orderNo}`,
method: 'GET',
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
if (res.statusCode === 200 && res.data.code === 200) {
uni.showToast({
title: '退款申请成功',
icon: 'success'
});
// 更新状态
this.orderInfo.withdrawStatus = 'processing';
this.orderInfo.isWithdrawn = true;
// 刷新订单信息
setTimeout(() => {
this.loadOrderInfo();
}, 1500);
} else {
throw new Error(res.data.msg || '退款申请失败');
}
} catch (error) {
console.error('退款申请错误:', error);
uni.showToast({
title: error.message || '退款申请失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
},
// 返回首页
goToHome() {
uni.reLaunch({
url: '/pages/index/index'
});
}
}
}
</script>
<style lang="scss" scoped>
.success-container {
padding: 20px;
background-color: #f8f8f8;
min-height: 100vh;
}
.status-card {
background-color: #fff;
border-radius: 12px;
padding: 30px;
text-align: center;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
.status-icon {
width: 60px;
height: 60px;
margin: 0 auto 16px;
&.success {
background-color: #07c160;
border-radius: 50%;
position: relative;
&::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
width: 30px;
height: 20px;
border: 3px solid #fff;
border-top: none;
border-right: none;
transform-origin: center;
transform: translate(-50%, -70%) rotate(-45deg);
}
}
}
.status-text {
font-size: 24px;
font-weight: bold;
color: #07c160;
margin-bottom: 8px;
}
.status-desc {
font-size: 14px;
color: #666;
}
}
.order-card, .refund-card {
background-color: #fff;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
.card-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 10px;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
.label {
color: #666;
font-size: 14px;
}
.value {
color: #333;
font-size: 14px;
&.highlight {
color: #ff6b00;
font-weight: bold;
font-size: 16px;
}
&.success {
color: #07c160;
}
}
}
}
.button-group {
margin-top: 40rpx;
display: flex;
justify-content: center;
gap: 20rpx;
.primary-btn, .secondary-btn {
width: 50%;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
text-align: center;
font-size: 32rpx;
}
.primary-btn {
background: #07c160;
color: #fff;
&:active {
opacity: 0.8;
}
}
.secondary-btn {
background: #f0f0f0;
color: #333;
&:active {
opacity: 0.8;
}
}
}
.notice-card {
background-color: #fff;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
.card-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 10px;
}
.notice-content {
text-align: left;
color: #666;
font-size: 14px;
}
}
.waiting {
color: #ffaa00;
font-weight: bold;
}
</style>
+337 -228
View File
@@ -1,229 +1,338 @@
<template>
<view class="success-container">
<!-- 支付成功状态 -->
<view class="status-card">
<view class="status-icon success"></view>
<view class="status-text">支付成功</view>
<view class="status-desc">您的订单已支付成功</view>
</view>
<!-- 订单信息 -->
<view class="order-card">
<view class="card-title">订单信息</view>
<view class="info-item">
<text class="label">订单号</text>
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
</view>
<view class="info-item">
<text class="label">设备号</text>
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
</view>
<view class="info-item">
<text class="label">支付金额</text>
<text class="value">{{ orderInfo.amount || '0.00' }}</text>
</view>
<view class="info-item">
<text class="label">支付时间</text>
<text class="value">{{ orderInfo.payTime || '-' }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="button-group">
<button class="primary-btn" @click="goToHome">返回首页</button>
<button class="secondary-btn" @click="goToOrderList">查看订单</button>
</view>
</view>
</template>
<script>
import { queryById } from '@/config/user.js'
export default {
data() {
return {
orderId: '',
orderInfo: {}
}
},
onLoad(options) {
if (options && options.orderId) {
this.orderId = options.orderId
this.loadOrderInfo()
} else {
uni.showToast({
title: '订单信息不存在',
icon: 'none'
})
setTimeout(() => {
this.goToHome()
}, 1500)
}
},
methods: {
async loadOrderInfo() {
try {
uni.showLoading({
title: '加载中'
})
const res = await queryById(this.orderId)
if (res.code === 200 && res.data) {
const orderData = res.data
this.orderInfo = {
orderNo: orderData.orderNo || orderData.orderId,
deviceNo: orderData.deviceNo,
amount: orderData.amount,
payTime: this.formatTime(new Date())
}
} else {
throw new Error('获取订单信息失败')
}
uni.hideLoading()
} catch (error) {
uni.hideLoading()
uni.showToast({
title: error.message || '获取订单信息失败',
icon: 'none'
})
}
},
formatTime(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hour = date.getHours().toString().padStart(2, '0')
const minute = date.getMinutes().toString().padStart(2, '0')
const second = date.getSeconds().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
},
goToHome() {
uni.switchTab({
url: '/pages/index/index'
})
},
goToOrderList() {
uni.redirectTo({
url: '/pages/order/index'
})
}
}
}
</script>
<style lang="scss" scoped>
.success-container {
padding: 20px;
background-color: #f5f5f5;
min-height: 100vh;
}
.status-card {
background-color: #fff;
border-radius: 12px;
padding: 30px;
text-align: center;
margin-bottom: 20px;
.status-icon {
width: 60px;
height: 60px;
margin: 0 auto 16px;
background-color: #07c160;
border-radius: 50%;
position: relative;
&::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 30px;
height: 20px;
border: 3px solid #fff;
border-top: none;
border-right: none;
transform-origin: center;
transform: translate(-50%, -70%) rotate(-45deg);
}
}
.status-text {
font-size: 24px;
font-weight: bold;
color: #07c160;
margin-bottom: 8px;
}
.status-desc {
font-size: 14px;
color: #666;
}
}
.order-card {
background-color: #fff;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
.card-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.label {
color: #666;
font-size: 14px;
}
.value {
color: #333;
font-size: 14px;
}
}
}
.button-group {
margin-top: 30px;
display: flex;
flex-direction: column;
gap: 16px;
.primary-btn {
background-color: #07c160;
color: #fff;
border: none;
border-radius: 24px;
padding: 12px;
font-size: 16px;
&:active {
opacity: 0.8;
}
}
.secondary-btn {
background-color: #fff;
color: #07c160;
border: 1px solid #07c160;
border-radius: 24px;
padding: 12px;
font-size: 16px;
&:active {
background-color: #f5f5f5;
}
}
}
<template>
<view class="success-container">
<!-- 支付成功状态 -->
<view class="status-card">
<view class="status-icon success"></view>
<view class="status-text">支付成功</view>
<view class="status-desc">您的订单已支付成功</view>
</view>
<!-- 订单信息 -->
<view class="order-card">
<view class="card-title">订单信息</view>
<view class="info-item">
<text class="label">订单号</text>
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
</view>
<view class="info-item">
<text class="label">设备号</text>
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
</view>
<view class="info-item">
<text class="label">支付金额</text>
<text class="value">{{ orderInfo.amount || '0.00' }}</text>
</view>
<view class="info-item">
<text class="label">支付时间</text>
<text class="value">{{ orderInfo.payTime || '-' }}</text>
</view>
</view>
<!-- 设备状态 -->
<view class="device-status">
<view class="status-message">{{ deviceMessage }}</view>
<view class="loading-animation" v-if="isLoading">
<view class="loading-circle"></view>
</view>
</view>
<!-- 操作按钮 -->
<view class="button-group">
<button class="primary-btn" @click="goToHome">返回首页</button>
<button class="secondary-btn" @click="goToOrderList">查看订单</button>
</view>
</view>
</template>
<script>
import { queryById, confirmPaymentAndRent } from '@/config/user.js'
export default {
data() {
return {
orderId: '',
orderInfo: {},
isLoading: true,
deviceMessage: '正在准备您的设备,请稍候...',
hasTriggeredDevice: false
}
},
onLoad(options) {
if (options && options.orderId) {
this.orderId = options.orderId
this.loadOrderInfo()
// 添加页面显示监听,防止页面切换后重复触发弹出
uni.$once('orderSuccess:' + this.orderId, () => {
console.log('已经触发过弹出逻辑,不再重复触发')
this.hasTriggeredDevice = true
})
} else {
uni.showToast({
title: '订单信息不存在',
icon: 'none'
})
setTimeout(() => {
this.goToHome()
}, 1500)
}
},
methods: {
async loadOrderInfo() {
try {
uni.showLoading({
title: '加载中'
})
const res = await queryById(this.orderId)
if (res.code === 200 && res.data) {
const orderData = res.data
this.orderInfo = {
orderNo: orderData.orderNo || orderData.orderId,
deviceNo: orderData.deviceNo,
amount: orderData.payAmount || orderData.amount,
payTime: orderData.payTime || this.formatTime(new Date())
}
// 检查订单状态
if (orderData.orderStatus === 'IN_USED') {
// 如果已经是使用中状态,可能说明开锁已经完成
this.deviceMessage = '设备已弹出,请取走您的充电宝'
this.isLoading = false
// 如果是第一次加载页面且设备已弹出,记录状态,避免重复弹出
if (!this.hasTriggeredDevice) {
uni.$emit('orderSuccess:' + this.orderId)
this.hasTriggeredDevice = true
}
} else {
// 正常触发弹出逻辑
this.triggerDeviceEject()
}
} else {
throw new Error('获取订单信息失败')
}
uni.hideLoading()
} catch (error) {
uni.hideLoading()
uni.showToast({
title: error.message || '获取订单信息失败',
icon: 'none'
})
}
},
// 触发弹出充电宝
async triggerDeviceEject() {
if (this.hasTriggeredDevice) {
console.log('已经触发过弹出充电宝,不重复触发')
return
}
this.hasTriggeredDevice = true
uni.$emit('orderSuccess:' + this.orderId)
this.isLoading = true
this.deviceMessage = '正在准备您的设备,请稍候...'
try {
console.log(`准备触发弹出充电宝,orderId: ${this.orderId}`)
// 调用确认支付并弹出的方法
const result = await confirmPaymentAndRent(this.orderId)
console.log('确认支付并弹出充电宝结果:', JSON.stringify(result))
if (result && result.code === 200) {
this.deviceMessage = '设备已弹出,请取走您的充电宝'
uni.showToast({
title: '充电宝已弹出',
icon: 'success'
})
} else {
throw new Error((result && result.msg) || '弹出充电宝失败')
}
} catch (error) {
console.error('弹出充电宝错误:', error)
this.deviceMessage = '弹出设备失败,请联系客服'
uni.showToast({
title: error.message || '弹出充电宝失败,请联系客服',
icon: 'none'
})
} finally {
this.isLoading = false
}
},
formatTime(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hour = date.getHours().toString().padStart(2, '0')
const minute = date.getMinutes().toString().padStart(2, '0')
const second = date.getSeconds().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
},
goToHome() {
uni.switchTab({
url: '/pages/index/index'
})
},
goToOrderList() {
uni.redirectTo({
url: '/pages/order/index'
})
}
}
}
</script>
<style lang="scss" scoped>
.success-container {
padding: 20px;
background-color: #f5f5f5;
min-height: 100vh;
}
.status-card {
background-color: #fff;
border-radius: 12px;
padding: 30px;
text-align: center;
margin-bottom: 20px;
.status-icon {
width: 60px;
height: 60px;
margin: 0 auto 16px;
background-color: #07c160;
border-radius: 50%;
position: relative;
&::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 30px;
height: 20px;
border: 3px solid #fff;
border-top: none;
border-right: none;
transform-origin: center;
transform: translate(-50%, -70%) rotate(-45deg);
}
}
.status-text {
font-size: 24px;
font-weight: bold;
color: #07c160;
margin-bottom: 8px;
}
.status-desc {
font-size: 14px;
color: #666;
}
}
.order-card {
background-color: #fff;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
.card-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.label {
color: #666;
font-size: 14px;
}
.value {
color: #333;
font-size: 14px;
}
}
}
.device-status {
background-color: #fff;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
text-align: center;
.status-message {
font-size: 16px;
color: #333;
margin-bottom: 12px;
}
.loading-animation {
display: flex;
justify-content: center;
align-items: center;
height: 40px;
.loading-circle {
width: 30px;
height: 30px;
border-radius: 50%;
border: 3px solid #f0f0f0;
border-top-color: #07c160;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
}
}
.button-group {
margin-top: 30px;
display: flex;
flex-direction: column;
gap: 16px;
.primary-btn {
background-color: #07c160;
color: #fff;
border: none;
border-radius: 24px;
padding: 12px;
font-size: 16px;
&:active {
opacity: 0.8;
}
}
.secondary-btn {
background-color: #fff;
color: #07c160;
border: 1px solid #07c160;
border-radius: 24px;
padding: 12px;
font-size: 16px;
&:active {
background-color: #f5f5f5;
}
}
}
</style>
+354 -146
View File
@@ -3,7 +3,7 @@
<!-- 订单信息卡片 -->
<view class="order-card">
<view class="order-header">
<text class="title">使用中</text>
<text class="title">{{ getOrderStatusText() }}</text>
<text class="order-no">订单号{{ orderInfo.orderId }}</text>
</view>
@@ -26,6 +26,14 @@
<text class="value">{{ orderInfo.currentFee }}</text>
</view>
</view>
<!-- 调试信息(仅在开发环境显示) -->
<view class="debug-info" v-if="false">
<view class="debug-title">调试信息</view>
<view class="debug-item">原始开始时间: {{ this.orderInfo._rawStartTime }}</view>
<view class="debug-item">处理后开始时间: {{ this.orderInfo.startTime }}</view>
<view class="debug-item">订单状态: {{ this.orderInfo.orderStatus }}</view>
</view>
</view>
<!-- 归还说明 -->
@@ -38,26 +46,32 @@
</view>
<view class="notice-item">
<view class="dot"></view>
<text>请在指定区域内归还设备</text>
<text>将充电宝插入原位置或空闲插口</text>
</view>
<view class="notice-item">
<view class="dot"></view>
<text>归还后押金将自动退还</text>
<text>系统将自动检测归还并处理退款</text>
</view>
<view class="notice-item">
<view class="dot"></view>
<text>归还成功后将自动跳转到成功页面</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<button class="unlock-btn" @click="handleUnlock" :disabled="unlocking">
{{ unlocking ? '开锁中...' : '开锁归还' }}
</button>
<button class="secondary-btn" @click="checkReturnStatus">刷新状态</button>
<button class="primary-btn" @click="goToHome">返回首页</button>
</view>
</view>
</template>
<script>
import { queryById, overOrderById } from '@/config/user.js'
import { queryById } from '@/config/user.js'
import {
URL
}from"@/config/url.js"
export default {
data() {
@@ -66,19 +80,28 @@ export default {
orderInfo: {
orderId: '',
startTime: '',
_rawStartTime: '', // 用于调试
usedTime: '0分钟',
currentFee: '0.00'
currentFee: '0.00',
orderStatus: 'in_used' // 默认状态为使用中
},
unlocking: false,
timer: null
timer: null,
statusCheckTimer: null,
maxStatusChecks: 30, // 最多检查30次
currentStatusChecks: 0,
statusCheckInterval: 5000, // 5秒检查一次
isPageActive: false // 跟踪页面是否活跃
}
},
onLoad(options) {
console.log('Return page loaded with options:', JSON.stringify(options))
// 标记页面为活跃状态
this.isPageActive = true
// 获取传递的参数
this.orderInfo.orderId = options.orderId || ''
this.deviceId = options.deviceId || ''
this.deviceId = options.deviceNo || options.deviceId || ''
console.log(`初始化参数: orderId=${this.orderInfo.orderId}, deviceId=${this.deviceId}`)
@@ -90,6 +113,26 @@ export default {
this.getOrderDetails()
// 启动定时器更新使用时长
this.startTimer()
// 启动状态检查定时器
this.startStatusCheckTimer()
// 记录当前活跃订单ID
uni.setStorageSync('activeOrderId', this.orderInfo.orderId)
// 如果订单ID有效,将订单添加到全局监控服务
try {
if (this.$orderMonitor) {
// 先确保移除之前的监控(防止重复添加)
this.$orderMonitor.removeOrder({orderId: this.orderInfo.orderId})
// 添加到监控队列,明确指定为归还页面
this.$orderMonitor.addOrder({orderId: this.orderInfo.orderId}, 'return')
console.log('订单已添加到监控队列:', this.orderInfo.orderId)
} else {
console.warn('$orderMonitor 未定义,无法添加订单到监控队列')
}
} catch (error) {
console.error('添加订单到监控队列失败:', error)
}
} else {
// 缺少必要参数
uni.showToast({
@@ -99,21 +142,117 @@ export default {
// 返回首页
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
this.goToHome()
}, 1500)
}
// 注册全局订单完成事件监听器
uni.$on('orderCompleted', this.handleOrderCompleted)
},
// 添加onHide生命周期,处理页面隐藏时的清理工作
onHide() {
console.log('归还页面隐藏,清理计时器资源和监控服务')
// 标记页面为非活跃状态
this.isPageActive = false
// 清理所有计时器
this.clearTimer()
this.clearStatusCheckTimer()
// 从全局订单监控服务中移除当前订单
this.removeFromOrderMonitor()
},
onUnload() {
console.log('归还页面卸载,清理所有资源')
// 标记页面为非活跃状态
this.isPageActive = false
// 页面卸载时清除定时器
this.clearTimer()
this.clearStatusCheckTimer()
// 从全局订单监控服务中移除当前订单
this.removeFromOrderMonitor()
// 注销全局事件监听
uni.$off('orderCompleted', this.handleOrderCompleted)
},
methods: {
// 从订单监控服务中移除当前订单
removeFromOrderMonitor() {
if (this.orderInfo.orderId && this.$orderMonitor) {
try {
this.$orderMonitor.removeOrder({orderId: this.orderInfo.orderId})
console.log('订单已从监控队列移除:', this.orderInfo.orderId)
} catch (error) {
console.error('从监控队列移除订单失败:', error)
}
}
},
// 处理订单完成事件(可由任何地方触发)
handleOrderCompleted(orderData) {
console.log('收到订单完成事件:', orderData)
// 检查是否为当前订单
if (orderData.orderId === this.orderInfo.orderId || orderData.orderNo === this.orderInfo.orderNo) {
// 显示归还成功弹窗
this.showReturnSuccessModal(orderData)
}
},
// 显示归还成功弹窗
showReturnSuccessModal(orderData) {
// 清理定时器
this.clearTimer()
this.clearStatusCheckTimer()
// 显示归还成功弹窗
uni.showModal({
title: '归还成功',
content: '充电宝已归还成功,剩余押金将退还到您的账户',
confirmText: '查看详情',
success: (res) => {
if (res.confirm) {
// 跳转到归还成功页面查看详情
uni.redirectTo({
url: `/pages/order/return-success?orderId=${orderData.orderId || this.orderInfo.orderId}`
})
} else {
// 跳转到首页
uni.reLaunch({
url: '/pages/index/index'
})
}
}
})
},
// 根据订单状态获取对应的文字显示
getOrderStatusText() {
const statusMap = {
'waiting_for_payment': '待支付',
'payment_in_progress': '支付中',
'payment_successful': '支付成功',
'in_used': '使用中',
'payment_failed': '支付失败',
'order_cancelled': '订单取消',
'used_done': '订单完成',
'used_down': '订单完成'
}
return statusMap[this.orderInfo.orderStatus] || '使用中'
},
// 获取订单详情
async getOrderDetails() {
// 如果页面不再活跃,不执行API请求
if (!this.isPageActive) {
console.log('页面已不活跃,跳过订单详情请求')
return
}
try {
uni.showLoading({ title: '加载中' })
// uni.showLoading({ title: '加载中' })
if (!this.orderInfo.orderId) {
throw new Error('订单ID不能为空')
@@ -125,32 +264,30 @@ export default {
if (result.code === 200 && result.data) {
const orderData = result.data
console.log('订单数据:', JSON.stringify(orderData))
console.log('订单原始数据:', orderData)
console.log('开始时间字段:', orderData.startTime, typeof orderData.startTime)
// 更新订单信息
// 更新订单状态
if (orderData.orderStatus) {
this.orderInfo.orderStatus = orderData.orderStatus
}
// 检查订单状态,如果已完成,显示归还成功弹窗
if (orderData.orderStatus &&
(orderData.orderStatus === 'used_done' || orderData.orderStatus === 'used_down')) {
// 触发全局订单完成事件
uni.$emit('orderCompleted', orderData)
// 显示归还成功弹窗
this.showReturnSuccessModal(orderData)
return
}
// 更新订单信息 (包括开始时间)
this.updateOrderInfo(orderData)
// 格式化开始时间
const rawTime = orderData.startTime
console.log('开始时间:', rawTime)
if (rawTime) {
try {
// 尝试格式化时间
const date = new Date(rawTime.replace(' ', 'T'))
if (!isNaN(date.getTime())) {
this.orderInfo.startTime = this.formatTime(date)
} else {
// 如果时间解析失败,直接使用原始时间字符串
this.orderInfo.startTime = rawTime
}
} catch (e) {
console.error('时间格式化错误:', e)
this.orderInfo.startTime = rawTime
}
} else {
this.orderInfo.startTime = '未知'
}
// 更新后检查是否成功设置了startTime
console.log('更新后的开始时间:', this.orderInfo.startTime)
} else {
throw new Error(result.msg || '获取订单详情失败')
}
@@ -163,9 +300,7 @@ export default {
// 如果获取订单失败,返回首页
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
this.goToHome()
}, 1500)
} finally {
uni.hideLoading()
@@ -186,8 +321,41 @@ export default {
// 使用后端返回的使用时长和费用数据
updateOrderInfo(orderData) {
console.log('更新订单信息:', JSON.stringify(orderData))
// 处理使用时长
this.orderInfo.usedTime = orderData.usedTime || '0分钟';
this.orderInfo.currentFee = orderData.currentFee || '0.00';
// 处理当前费用
this.orderInfo.currentFee = orderData.currentFee || orderData.actualDeviceAmount || orderData.payAmount || '0.00';
// 更新订单状态
if (orderData.orderStatus) {
this.orderInfo.orderStatus = orderData.orderStatus;
}
// 保存原始开始时间用于调试
this.orderInfo._rawStartTime = orderData.startTime;
// 处理开始时间
if (orderData.startTime) {
try {
console.log('API返回的开始时间:', orderData.startTime);
// 尝试直接显示API返回的时间字符串
this.orderInfo.startTime = orderData.startTime;
} catch (e) {
console.error('更新开始时间错误:', e);
this.orderInfo.startTime = '未知';
}
} else {
console.warn('API返回的订单数据中没有startTime字段');
// 尝试使用createTime作为备选
if (orderData.createTime) {
console.log('使用createTime作为备选:', orderData.createTime);
this.orderInfo.startTime = orderData.createTime;
} else {
this.orderInfo.startTime = '未知';
}
}
// 如果有设备号,更新设备号
if (orderData.deviceNo && !this.deviceId) {
@@ -197,10 +365,22 @@ export default {
// 更新使用时长的定时器
startTimer() {
// 清除现有计时器,确保不重复
this.clearTimer()
// 每分钟更新一次使用时长
this.timer = setInterval(() => {
this.getOrderDetails()
// 只有当页面活跃时才执行更新
if (this.isPageActive) {
console.log('执行定时更新订单信息')
this.getOrderDetails()
} else {
console.log('页面已不活跃,停止计时器')
this.clearTimer()
}
}, 60000)
console.log('已启动使用时长更新计时器')
},
// 清除定时器
@@ -208,72 +388,56 @@ export default {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
console.log('已清除使用时长更新计时器')
}
},
// 处理开锁归还
async handleUnlock() {
if (this.unlocking) return
try {
this.unlocking = true
uni.showLoading({ title: '开锁中' })
// 确认是否归还
const confirmResult = await new Promise((resolve) => {
uni.showModal({
title: '确认归还',
content: '确定要归还设备吗?',
success: (res) => {
resolve(res.confirm)
}
})
})
if (!confirmResult) {
this.unlocking = false
uni.hideLoading()
return
}
console.log(`准备结束订单, orderId: ${this.orderInfo.orderId}`)
// 调用结束订单接口
const result = await overOrderById(this.orderInfo.orderId)
console.log('结束订单结果:', JSON.stringify(result))
if (result.code === 200) {
uni.showToast({
title: '归还成功',
icon: 'success'
})
// 归还成功后,返回首页
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
}, 1500)
} else {
throw new Error(result.msg || '归还失败')
}
} catch (error) {
console.error('归还操作错误:', error)
uni.showToast({
title: error.message || '归还失败,请重试',
icon: 'none'
})
} finally {
this.unlocking = false
uni.hideLoading()
// 清除状态检查定时器
clearStatusCheckTimer() {
if (this.statusCheckTimer) {
clearInterval(this.statusCheckTimer)
this.statusCheckTimer = null
console.log('已清除归还状态检查计时器')
}
},
// 开始状态检查定时器
startStatusCheckTimer() {
this.currentStatusChecks = 0
// 确保之前的计时器被清除
this.clearStatusCheckTimer()
this.statusCheckTimer = setInterval(() => {
// 只有当页面活跃时才执行检查
if (this.isPageActive) {
this.currentStatusChecks++
console.log(`执行归还状态检查 (${this.currentStatusChecks}/${this.maxStatusChecks})`)
this.checkReturnStatus()
// 如果超过最大检查次数,停止定时器
if (this.currentStatusChecks >= this.maxStatusChecks) {
this.clearStatusCheckTimer()
// 提示用户手动刷新
uni.showToast({
title: '请手动刷新查看归还状态',
icon: 'none',
duration: 3000
})
}
} else {
console.log('页面已不活跃,停止状态检查计时器')
this.clearStatusCheckTimer()
}
}, this.statusCheckInterval)
console.log('已启动归还状态检查计时器')
},
// 通过设备号查询使用中的订单
async getOrderByDevice() {
try {
uni.showLoading({ title: '加载中' })
// uni.showLoading({ title: '加载中' })
if (!this.deviceId) {
throw new Error('设备号不能为空')
@@ -281,7 +445,7 @@ export default {
// 这里调用API查询该设备的使用中订单
const inUseRes = await uni.request({
url: `${uni.getStorageSync('baseUrl') || 'http://127.0.0.1:8080'}/app/order/inUse`,
url: `${URL || 'http://127.0.0.1:8080'}/app/order/inUse`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
@@ -293,13 +457,28 @@ export default {
if (inUseRes.statusCode === 200 && inUseRes.data.code === 200 && inUseRes.data.data) {
const inUseOrder = inUseRes.data.data
console.log('使用中的订单:', inUseOrder)
// 更新订单ID
this.orderInfo.orderId = inUseOrder.orderId
// 如果有订单状态,更新订单状态
if (inUseOrder.orderStatus) {
this.orderInfo.orderStatus = inUseOrder.orderStatus
}
// 如果有开始时间,直接更新
if (inUseOrder.startTime) {
console.log('inUse API返回的开始时间:', inUseOrder.startTime)
this.orderInfo.startTime = inUseOrder.startTime
}
// 获取详细订单信息
this.getOrderDetails()
// 启动定时器
this.startTimer()
// 启动状态检查定时器
this.startStatusCheckTimer()
} else {
throw new Error('未找到使用中的订单')
}
@@ -312,13 +491,30 @@ export default {
// 如果获取订单失败,返回首页
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
this.goToHome()
}, 1500)
} finally {
uni.hideLoading()
}
},
// 检查归还状态
async checkReturnStatus() {
try {
// 只有页面活跃时才执行检查
if (this.isPageActive) {
await this.getOrderDetails()
}
} catch (error) {
console.error('检查归还状态失败:', error)
}
},
// 返回首页
goToHome() {
uni.reLaunch({
url: '/pages/index/index'
})
}
}
}
@@ -346,9 +542,9 @@ export default {
margin-bottom: 30rpx;
.title {
font-size: 36rpx;
font-weight: 600;
color: #1976D2;
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.order-no {
@@ -358,15 +554,15 @@ export default {
}
.device-info {
margin-bottom: 20rpx;
margin-bottom: 30rpx;
.device-name {
font-size: 32rpx;
font-weight: 500;
font-size: 28rpx;
color: #333;
margin-right: 20rpx;
display: block;
margin-bottom: 10rpx;
}
.device-id {
font-size: 24rpx;
color: #666;
@@ -374,27 +570,32 @@ export default {
}
.time-info {
background: #f9f9f9;
border-radius: 16rpx;
padding: 20rpx;
.time-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.label {
font-size: 28rpx;
font-size: 26rpx;
color: #666;
}
.value {
font-size: 28rpx;
font-size: 26rpx;
color: #333;
&.highlight {
color: #1976D2;
font-weight: 500;
color: #ff6b00;
font-weight: bold;
}
}
}
@@ -409,18 +610,18 @@ export default {
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.notice-title {
font-size: 32rpx;
font-weight: 600;
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 24rpx;
margin-bottom: 20rpx;
}
.notice-list {
.notice-item {
display: flex;
align-items: center;
align-items: flex-start;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
@@ -428,13 +629,15 @@ export default {
.dot {
width: 12rpx;
height: 12rpx;
background: #1976D2;
background: #07c160;
border-radius: 50%;
margin-top: 10rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
text {
font-size: 28rpx;
font-size: 26rpx;
color: #666;
line-height: 1.5;
}
@@ -447,33 +650,38 @@ export default {
left: 0;
right: 0;
bottom: 0;
padding: 30rpx;
background: #fff;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 -4rpx 16rpx rgba(0,0,0,0.04);
z-index: 10;
display: flex;
justify-content: space-between;
gap: 20rpx;
.unlock-btn {
width: 100%;
.primary-btn, .secondary-btn {
height: 88rpx;
border-radius: 44rpx;
background: linear-gradient(135deg, #FF9800, #FFB74D);
color: #fff;
line-height: 88rpx;
font-size: 32rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 44rpx;
text-align: center;
flex: 1;
}
.primary-btn {
background: #07c160;
color: #fff;
&:active {
transform: scale(0.98);
opacity: 0.8;
}
&:disabled {
opacity: 0.7;
}
.secondary-btn {
background: #f0f0f0;
color: #333;
&:active {
opacity: 0.8;
}
}
}
+136 -72
View File
@@ -1,73 +1,137 @@
<template>
<view>
</view>
</template>
<script>
import {
wxLogin,
} from '../../../util/index'
import {
queryHasOrder
} from '@/config/user.js'
export default {
data() {
return {
}
},
async onLoad(option) {
try {
uni.showLoading({
title: '加载中...'
});
if (!uni.getStorageSync('token')) {
await wxLogin();
}
if (!option.deviceNo) {
uni.hideLoading();
uni.showToast({
title: '设备编号不能为空',
icon: 'none'
});
return;
}
// 查询用户是否有使用中(in_used)的订单
const result = await queryHasOrder(option.deviceNo);
uni.hideLoading();
if (result.data && result.data.data && result.data.data.length > 0) {
// 如果有使用中的订单,直接跳转到归还页面
uni.redirectTo({
url: `/pages/device/return?deviceNo=${option.deviceNo}`
});
} else {
// 如果没有使用中的订单,跳转到设备详情页面进行租借
uni.redirectTo({
url: `/pages/device/detail?deviceNo=${option.deviceNo}`
});
}
} catch (error) {
uni.hideLoading();
uni.showToast({
title: '页面加载失败,请重试',
icon: 'none'
});
console.error('bagCheck onLoad error:', error);
}
},
methods: {
}
}
</script>
<style>
<template>
<view>
</view>
</template>
<script>
import {
wxLogin,
} from '../../../util/index'
import {
getMyIndexInfo
} from "../../../config/user.js";
import {
queryHasOrder
} from "../../../config/user.js";
import {
checkOrdersByStatus
} from "../../../config/user.js";
export default {
data() {
return {
}
},
async onLoad(option) {
console.log('bagCheck onLoad option:', option);
try {
uni.showLoading({
title: '处理中...',
mask: true
});
// 检查是否传入设备编号
if (!option || !option.deviceNo) {
throw new Error('未识别到设备编号');
}
const deviceNo = option.deviceNo;
// 检查用户是否有进行中(in_used)或待支付(waiting_for_payment)的订单
const statusesToCheck = ['in_used', 'waiting_for_payment'];
const res = await checkOrdersByStatus(deviceNo, statusesToCheck);
if (res.code === 200 && res.data && res.data.length > 0) {
// 找到相关订单,取最新的一条
const latestOrder = res.data[0]; // 假设返回结果按时间倒序
if (latestOrder.orderStatus === 'in_used') {
// 如果是使用中的订单,跳转到归还页面
console.log('检测到使用中订单,跳转归还页:', latestOrder.orderId);
uni.redirectTo({
url: `/pages/device/return?orderId=${latestOrder.orderId}`
});
} else if (latestOrder.orderStatus === 'waiting_for_payment') {
// 如果是待支付订单,跳转到支付页面,并传递必要信息
console.log('检测到待支付订单,跳转支付页:', latestOrder.orderId);
// 获取套餐时间(分钟)
const packageTimeMinutes = latestOrder.packageTime || 60;
// 套餐小时数
const packageTimeHours = (packageTimeMinutes / 60).toFixed(1);
// 套餐价格
const packagePrice = latestOrder.packagePrice || '0.00';
// 计算每小时费率
const hourlyRate = (parseFloat(packagePrice) / (packageTimeMinutes / 60)).toFixed(2);
// 押金金额
const depositAmount = latestOrder.depositAmount || '99.00';
// 计算总金额(套餐+押金)
const totalAmount = (parseFloat(depositAmount) + parseFloat(packagePrice)).toFixed(2);
uni.redirectTo({
url: `/pages/order/payment?orderId=${latestOrder.orderId}&packageTimeHours=${packageTimeHours}&packagePrice=${packagePrice}&hourlyRate=${hourlyRate}&totalAmount=${totalAmount}&depositAmount=${depositAmount}`
});
} else {
// 其他状态(理论上不应该到这里,除非statusesToCheck配置错误),默认到详情页
console.log('检测到其他状态订单,跳转详情页:', latestOrder.orderId);
uni.redirectTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
});
}
} else {
// 没有找到相关状态的订单,跳转到设备详情页进行租借
console.log('未检测到相关订单,跳转详情页');
uni.redirectTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
});
}
} catch (error) {
// 只处理真正的错误,不是"没有订单"的情况
if (error.message && (
error.message.includes('未识别到设备编号') ||
error.message.includes('网络请求失败') ||
error.message.includes('服务器错误')
)) {
console.error('扫码检查订单失败:', error);
uni.showToast({
title: error.message || '处理失败,请稍后重试',
icon: 'none',
duration: 2000
});
} else {
// 对于其他错误,包括"没有找到订单",直接跳转到详情页,不显示错误消息
console.log('没有找到符合条件的订单或发生其他错误,直接跳转详情页');
}
// 无论什么情况,都跳转到一个可用页面
setTimeout(() => {
if (option && option.deviceNo) {
uni.redirectTo({
url: `/pages/device/detail?deviceNo=${option.deviceNo}`
});
} else {
// 如果连deviceNo都没有,则返回首页
uni.switchTab({ url: '/pages/index/index' });
}
}, 2000);
} finally {
uni.hideLoading();
}
},
methods: {
}
}
</script>
<style>
</style>
+230
View File
@@ -0,0 +1,230 @@
<template>
<view class="container">
<!-- 用户信息卡片 -->
<view class="user-card">
<view class="avatar">
<image :src="userInfo.avatar || '/static/images/default-avatar.png'" mode="aspectFill"></image>
</view>
<view class="user-info">
<text class="nickname">{{ userInfo.nickName || '未登录' }}</text>
<text class="phone">{{ userInfo.phone || '未绑定手机号' }}</text>
</view>
</view>
<!-- 余额卡片 -->
<view class="balance-card">
<view class="balance-title">余额</view>
<view class="balance-amount">{{ userInfo.balanceAmount || '0.00' }}</view>
<view class="balance-desc">可用于租借设备</view>
</view>
<!-- 功能菜单 -->
<view class="menu-list">
<view class="menu-item" @click="navigateTo('/pages/order/list')">
<text class="menu-icon">📋</text>
<text class="menu-text">我的订单</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" @click="navigateTo('/pages/user/feedback')">
<text class="menu-icon">💬</text>
<text class="menu-text">意见反馈</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" @click="navigateTo('/pages/user/about')">
<text class="menu-icon"></text>
<text class="menu-text">关于我们</text>
<text class="menu-arrow">></text>
</view>
</view>
<!-- 退出登录按钮 -->
<view class="logout-btn" @click="handleLogout" v-if="isLogin">
<text>退出登录</text>
</view>
</view>
</template>
<script>
import { getUserInfo } from '@/api/user'
import { URL } from '@/config/url'
export default {
data() {
return {
userInfo: {},
isLogin: false
}
},
onShow() {
this.checkLoginStatus()
this.loadUserInfo()
},
methods: {
async loadUserInfo() {
try {
const res = await getUserInfo()
if (res.code === 200) {
this.userInfo = res.data
this.isLogin = true
} else {
this.isLogin = false
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
})
}
} catch (error) {
console.error('加载用户信息失败:', error)
this.isLogin = false
}
},
checkLoginStatus() {
const token = uni.getStorageSync('token')
this.isLogin = !!token
if (!this.isLogin) {
uni.redirectTo({
url: '/pages/login/index'
})
}
},
navigateTo(url) {
uni.navigateTo({ url })
},
handleLogout() {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
this.isLogin = false
uni.redirectTo({
url: '/pages/login/index'
})
}
}
})
}
}
}
</script>
<style>
.container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
.user-card {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
display: flex;
align-items: center;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
overflow: hidden;
margin-right: 30rpx;
}
.avatar image {
width: 100%;
height: 100%;
}
.user-info {
flex: 1;
}
.nickname {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.phone {
font-size: 28rpx;
color: #666;
}
.balance-card {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.balance-title {
font-size: 28rpx;
color: #666;
margin-bottom: 20rpx;
}
.balance-amount {
font-size: 48rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.balance-desc {
font-size: 24rpx;
color: #999;
}
.menu-list {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.menu-item {
display: flex;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-icon {
font-size: 36rpx;
margin-right: 20rpx;
}
.menu-text {
flex: 1;
font-size: 28rpx;
color: #333;
}
.menu-arrow {
font-size: 28rpx;
color: #999;
}
.logout-btn {
margin-top: 40rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
text-align: center;
color: #ff4d4f;
font-size: 28rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
</style>
+9 -9
View File
@@ -1,10 +1,10 @@
uni.addInterceptor({
returnValue (res) {
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => res[0] ? reject(res[0]) : resolve(res[1]));
});
},
uni.addInterceptor({
returnValue (res) {
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => res[0] ? reject(res[0]) : resolve(res[1]));
});
},
});
+77 -77
View File
@@ -1,77 +1,77 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
@import 'uview-ui/theme.scss';
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16px;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
@import 'uview-ui/theme.scss';
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16px;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./common/vendor.js"),n=require("./util/index.js"),e=require("./utils/orderMonitor.js");Math;const t={onLaunch:function(){console.log("App Launch")},onShow:async function(){console.log("App Show"),await this.autoLogin()},onHide:function(){console.log("App Hide")},methods:{async autoLogin(){try{const o=await n.wxLogin();console.log("自动登录成功:",o)}catch(o){console.error("自动登录失败:",o)}}}};function r(){const n=o.createSSRApp(t);return n.config.globalProperties.$orderMonitor=e.orderMonitor,{app:n}}r().app.mount("#app"),exports.createApp=r;
+42
View File
@@ -0,0 +1,42 @@
{
"pages": [
"pages/index/index",
"pages/my/index",
"pages/deposit/index",
"pages/order/index",
"pages/order/payment",
"pages/feedback/index",
"pages/help/index",
"pages/device/detail",
"pages/serve/bagCheck/index",
"pages/return/index",
"pages/order/success",
"pages/order/return-success"
],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "共享风扇",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#999999",
"selectedColor": "#1976D2",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-active.png"
},
{
"pagePath": "pages/my/index",
"text": "我的",
"iconPath": "static/user.png",
"selectedIconPath": "static/user-active.png"
}
]
},
"usingComponents": {}
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
"use strict";exports._imports_0="/static/scan-icon.png",exports._imports_0$1="/static/jl.png",exports._imports_1="/static/complaint.png",exports._imports_2="/static/hlep.png";
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../common/vendor.js"),o=require("./url.js");exports.request=a=>new Promise(((t,d)=>{console.log(`发起请求: ${a.method} ${o.URL+a.url}`,a.data),e.index.request({url:o.URL+a.url,method:a.method,data:a.data,header:{"Content-Type":"application/x-www-form-urlencoded",...a.headers,appid:o.appid,Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")},success:e=>(console.log(`请求响应: ${a.url}`,e),200!==e.statusCode?(console.error(`HTTP状态码错误: ${e.statusCode}`,e.data),e.data?void t(e.data):void d({msg:`请求失败,状态码:${e.statusCode}`})):e.data&&200!==e.data.code?(console.warn(`业务状态码错误: ${e.data.code}`,e.data),void t(e.data)):void t(e.data)),fail(e){console.error(`请求失败: ${a.url}`,e),d(e)}})}));
+1
View File
@@ -0,0 +1 @@
"use strict";exports.URL="https://unifans.gxfs123.com",exports.appid="wxe752f45e7f7aa271";
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("./http.js");exports.confirmPaymentAndRent=r=>(console.log(`确认支付并弹出充电宝, orderId: ${r}`),e.request({url:`/app/device/confirmPaymentAndRent?orderId=${r}`,method:"post"})),exports.getDeviceInfo=r=>e.request({url:`/app/device/${r}`,method:"get"}),exports.getMyIndexInfo=r=>e.request({url:"/app/user/userInfo",method:"get",data:r}),exports.getOrderList=r=>e.request({url:"/app/order/list",method:"get",data:r,hideLoading:!0}),exports.login=r=>e.request({url:"/app/user/login",method:"get",data:r}),exports.queryById=r=>(console.log(`查询订单详情, orderId: ${r}`),e.request({url:`/app/order/${r}`,method:"get",hideLoading:!0})),exports.queryHasOrder=r=>e.request({url:`/app/order/list?deviceNo=${r}&orderStatus=in_used`,method:"get"}),exports.rentPowerBank=(r,t)=>e.request({url:"/app/device/rentPowerBank",method:"post",data:{deviceNo:r,phone:t}});
+1
View File
@@ -0,0 +1 @@
"use strict";exports.HELP_CONTENT={FAQ_LIST:[{question:"如何租借风扇?",answer:'点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。'},{question:"收费标准是怎样的?",answer:"使用费用为2元/小时,不足1小时按1小时计算。押金99元,归还后自动退还。"},{question:"如何归还风扇?",answer:'将风扇带到任意归还点,点击首页"扫码归还"按钮,扫描归还点二维码即可完成归还。'},{question:"押金多久能退还?",answer:"归还设备后押金将自动发起退款,预计0-7个工作日到账。"},{question:"设备无法正常使用怎么办?",answer:'您可以通过"我的-投诉与建议"提交故障反馈,或直接拨打客服电话处理。'}],CONTACT:{TITLE:"联系客服",PHONE:{LABEL:"客服电话",VALUE:"400-888-8888"},SERVICE_TIME:{LABEL:"服务时间",VALUE:"周一至周日 09:00-22:00"}}};
@@ -0,0 +1 @@
"use strict";exports.OrderStatusMap={waiting_for_payment:{text:"待支付",class:"status-waiting"},payment_in_progress:{text:"支付中",class:"status-progress"},payment_successful:{text:"支付成功",class:"status-success"},in_used:{text:"使用中",class:"status-using"},payment_failed:{text:"支付失败",class:"status-failed"},order_cancelled:{text:"已取消",class:"status-cancelled"},used_done:{text:"已完成",class:"status-finished"}},exports.OrderStatusTabs=[{text:"全部",status:[]},{text:"待支付",status:["waiting_for_payment","payment_in_progress"]},{text:"使用中",status:["payment_successful","in_used"]},{text:"已完成",status:["used_done","payment_failed","order_cancelled"]}];
+1
View File
@@ -0,0 +1 @@
"use strict";const t=require("../../common/vendor.js"),e={data:()=>({depositAmount:"99.00",records:[{type:"支付",time:"2024-03-20 15:30",amount:"99.00"},{type:"退还",time:"2024-03-19 12:00",amount:"99.00"}]}),methods:{handleWithdraw(){t.index.showModal({title:"确认提现",content:"押金将原路退回,预计0-7个工作日到账",success:e=>{e.confirm&&t.index.showToast({title:"提现申请已提交",icon:"success"})}})}}};const o=t._export_sfc(e,[["render",function(e,o,n,d,s,a){return{a:t.t(s.depositAmount),b:t.o(((...t)=>a.handleWithdraw&&a.handleWithdraw(...t))),c:t.f(s.records,((e,o,n)=>({a:t.t(e.type),b:t.t(e.time),c:t.t("退还"===e.type?"+":"-"),d:t.t(e.amount),e:t.n("退还"===e.type?"refund":""),f:o})))}}],["__scopeId","data-v-a3ef2e56"]]);wx.createPage(o);
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "押金管理",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="deposit-container data-v-a3ef2e56"><view class="deposit-card data-v-a3ef2e56"><view class="title data-v-a3ef2e56">押金余额</view><view class="amount data-v-a3ef2e56">¥{{a}}</view><button class="withdraw-btn data-v-a3ef2e56" bindtap="{{b}}">提现</button></view><view class="notice-card data-v-a3ef2e56"><view class="notice-title data-v-a3ef2e56"><view class="dot data-v-a3ef2e56"></view><text class="data-v-a3ef2e56">提现说明</text></view><view class="notice-content data-v-a3ef2e56"><view class="notice-item data-v-a3ef2e56">1. 提现金额将原路退回支付账户</view><view class="notice-item data-v-a3ef2e56">2. 提现申请提交后预计0-7个工作日到账</view><view class="notice-item data-v-a3ef2e56">3. 如超时未收到,请联系客服处理</view></view></view><view class="record-card data-v-a3ef2e56"><view class="record-title data-v-a3ef2e56">押金记录</view><view class="record-list data-v-a3ef2e56"><view wx:for="{{c}}" wx:for-item="item" wx:key="f" class="record-item data-v-a3ef2e56"><view class="record-info data-v-a3ef2e56"><text class="record-type data-v-a3ef2e56">{{item.a}}</text><text class="record-time data-v-a3ef2e56">{{item.b}}</text></view><text class="{{['record-amount', 'data-v-a3ef2e56', item.e]}}">{{item.c}}¥{{item.d}}</text></view></view></view></view>
@@ -0,0 +1 @@
.deposit-container.data-v-a3ef2e56{min-height:100vh;background:#f8f8f8;padding:30rpx}.deposit-container .deposit-card.data-v-a3ef2e56{background:linear-gradient(135deg,#1976d2,#64b5f6);border-radius:20rpx;padding:40rpx;color:#fff;text-align:center;box-shadow:0 4rpx 20rpx rgba(25,118,210,.2)}.deposit-container .deposit-card .title.data-v-a3ef2e56{font-size:28rpx;opacity:.9;margin-bottom:20rpx}.deposit-container .deposit-card .amount.data-v-a3ef2e56{font-size:72rpx;font-weight:700;margin-bottom:40rpx}.deposit-container .deposit-card .withdraw-btn.data-v-a3ef2e56{background:#fff;color:#1976d2;width:80%;height:80rpx;line-height:80rpx;border-radius:40rpx;font-size:32rpx;font-weight:500;margin:0 auto}.deposit-container .deposit-card .withdraw-btn.data-v-a3ef2e56:active{transform:scale(.98)}.deposit-container .notice-card.data-v-a3ef2e56{margin-top:30rpx;background:#fff;border-radius:20rpx;padding:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.deposit-container .notice-card .notice-title.data-v-a3ef2e56{display:flex;align-items:center;margin-bottom:20rpx}.deposit-container .notice-card .notice-title .dot.data-v-a3ef2e56{width:12rpx;height:12rpx;background:#1976d2;border-radius:50%;margin-right:10rpx}.deposit-container .notice-card .notice-title text.data-v-a3ef2e56{font-size:30rpx;font-weight:500;color:#333}.deposit-container .notice-card .notice-content .notice-item.data-v-a3ef2e56{font-size:26rpx;color:#666;line-height:1.8;padding-left:22rpx}.deposit-container .record-card.data-v-a3ef2e56{margin-top:30rpx;background:#fff;border-radius:20rpx;padding:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.deposit-container .record-card .record-title.data-v-a3ef2e56{font-size:30rpx;font-weight:500;color:#333;margin-bottom:20rpx;border-left:8rpx solid #1976D2;padding-left:20rpx}.deposit-container .record-card .record-list .record-item.data-v-a3ef2e56{display:flex;justify-content:space-between;align-items:center;padding:20rpx 0;border-bottom:1rpx solid #f5f5f5}.deposit-container .record-card .record-list .record-item.data-v-a3ef2e56:last-child{border-bottom:none}.deposit-container .record-card .record-list .record-item .record-info .record-type.data-v-a3ef2e56{font-size:28rpx;color:#333;margin-bottom:6rpx;display:block}.deposit-container .record-card .record-list .record-item .record-info .record-time.data-v-a3ef2e56{font-size:24rpx;color:#999}.deposit-container .record-card .record-list .record-item .record-amount.data-v-a3ef2e56{font-size:32rpx;color:#333;font-weight:500}.deposit-container .record-card .record-list .record-item .record-amount.refund.data-v-a3ef2e56{color:#4caf50}
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),t=require("../../config/user.js"),i={data:()=>({deviceInfo:{},deviceId:"",deviceLocation:"一号教学楼大厅",batteryLevel:95,hasActiveOrder:!1,deviceStatus:{text:"可使用",class:"available"},selectedPackage:1,packages:[{time:"1小时",price:"2.00",unitPrice:"2.00"},{time:"4小时",price:"6.00",unitPrice:"1.50"},{time:"12小时",price:"15.00",unitPrice:"1.25"}],isLoggedIn:!0,phoneNumber:""}),onLoad(e){this.deviceId=e.deviceNo,console.log(e.deviceNo),this.getDeviceInfo()},methods:{async getDeviceInfo(){const e=await t.getDeviceInfo(this.deviceId);200==e.code&&(this.deviceInfo=e.data)},showLoginTip(){e.index.showModal({title:"提示",content:"请先登录后再操作",confirmText:"去登录",success:t=>{t.confirm&&e.index.navigateTo({url:"/pages/login/index"})}})},selectPackage(e){this.selectedPackage=e},async checkOrderStatus(){try{(await this.$api.checkActiveOrder()).hasOrder&&e.index.redirectTo({url:`/pages/device/return?deviceId=${this.deviceId}`})}catch(t){e.index.showToast({title:"订单状态查询失败",icon:"none"})}},handleRent(){if(!this.isLoggedIn)return void this.showLoginTip();if(!this.phoneNumber)return void e.index.showToast({title:"请输入手机号码",icon:"none"});if(!/^1[3-9]\d{9}$/.test(this.phoneNumber))return void e.index.showToast({title:"请输入正确的手机号码",icon:"none"});const t=this.packages[this.selectedPackage];e.index.showModal({title:"确认租借",content:`确认支付押金¥99.00及${t.time}套餐费用¥${t.price}`,success:e=>{e.confirm&&this.submitRentOrder()}})},async submitRentOrder(){try{e.index.showLoading({title:"处理中"});const i=this.packages[this.selectedPackage],c=await t.rentPowerBank(this.deviceId,this.phoneNumber);if(200!==c.code)throw new Error(c.msg||"设备租借失败");const n=c.data;e.index.hideLoading(),e.index.redirectTo({url:`/pages/order/payment?orderId=${n.orderId}&packageTime=${i.time}&packagePrice=${i.price}`})}catch(i){e.index.hideLoading(),e.index.showToast({title:i.message||"租借失败,请重试",icon:"none"})}}}};const c=e._export_sfc(i,[["render",function(t,i,c,n,a,r){return e.e({a:e.t(a.deviceId),b:e.t(a.deviceStatus.text),c:e.n(a.deviceStatus.class),d:e.t(a.deviceLocation),e:e.t(a.batteryLevel),f:!a.hasActiveOrder},a.hasActiveOrder?{}:{g:e.f(a.packages,((t,i,c)=>({a:e.t(t.time),b:e.t(t.price),c:e.t(t.unitPrice),d:i,e:a.selectedPackage===i?1:"",f:e.o((e=>r.selectPackage(i)),i)})))},{h:!a.hasActiveOrder},a.hasActiveOrder?{}:{i:a.phoneNumber,j:e.o((e=>a.phoneNumber=e.detail.value))},{k:!a.hasActiveOrder},(a.hasActiveOrder,{}),{l:e.t(a.hasActiveOrder?"归还设备":"立即租借"),m:e.n(a.hasActiveOrder?"return":"rent"),n:e.o(((...e)=>r.handleRent&&r.handleRent(...e)))})}],["__scopeId","data-v-b8e15e19"]]);wx.createPage(c);
@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "设备详情",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="detail-container data-v-b8e15e19"><view class="device-card data-v-b8e15e19"><view class="device-header data-v-b8e15e19"><view class="device-title data-v-b8e15e19"><text class="name data-v-b8e15e19">共享风扇</text><text class="id data-v-b8e15e19">设备号:{{a}}</text></view><view class="{{['status', 'data-v-b8e15e19', c]}}">{{b}}</view></view><view class="device-info data-v-b8e15e19"><view class="info-item data-v-b8e15e19"><text class="label data-v-b8e15e19">设备位置</text><text class="value data-v-b8e15e19">{{d}}</text></view><view class="info-item data-v-b8e15e19"><text class="label data-v-b8e15e19">电池电量</text><text class="value data-v-b8e15e19">{{e}}%</text></view></view></view><view wx:if="{{f}}" class="package-section data-v-b8e15e19"><view class="section-title data-v-b8e15e19">选择套餐</view><view class="package-list data-v-b8e15e19"><view wx:for="{{g}}" wx:for-item="pkg" wx:key="d" class="{{['package-item', 'data-v-b8e15e19', pkg.e && 'active']}}" bindtap="{{pkg.f}}"><view class="package-content data-v-b8e15e19"><text class="time data-v-b8e15e19">{{pkg.a}}</text><text class="price data-v-b8e15e19">¥{{pkg.b}}</text></view><text class="unit-price data-v-b8e15e19">约{{pkg.c}}元/小时</text></view></view></view><view wx:if="{{h}}" class="phone-section data-v-b8e15e19"><view class="section-title data-v-b8e15e19">联系方式</view><view class="phone-input-wrap data-v-b8e15e19"><input type="number" class="phone-input data-v-b8e15e19" maxlength="11" placeholder="请输入手机号码" value="{{i}}" bindinput="{{j}}"/></view></view><view class="notice-section data-v-b8e15e19"><view class="section-title data-v-b8e15e19">使用说明</view><view class="notice-list data-v-b8e15e19"><view class="notice-item data-v-b8e15e19"><view class="dot data-v-b8e15e19"></view><text class="data-v-b8e15e19">请在使用前检查设备是否完好</text></view><view class="notice-item data-v-b8e15e19"><view class="dot data-v-b8e15e19"></view><text class="data-v-b8e15e19">超出使用时间将自动按小时计费</text></view><view class="notice-item data-v-b8e15e19"><view class="dot data-v-b8e15e19"></view><text class="data-v-b8e15e19">请在指定区域内使用设备</text></view></view></view><view class="bottom-bar data-v-b8e15e19"><view wx:if="{{k}}" class="price-info data-v-b8e15e19"><text class="deposit-text data-v-b8e15e19">押金:</text><text class="deposit-amount data-v-b8e15e19">¥99</text></view><button class="{{['action-btn', 'data-v-b8e15e19', m]}}" bindtap="{{n}}">{{l}}</button></view></view>
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),t={data:()=>({types:["设备故障","收费问题","使用建议","其他"],selectedType:-1,description:"",images:[],contact:""}),methods:{selectType(e){this.selectedType=e},chooseImage(){e.index.chooseImage({count:3-this.images.length,success:e=>{this.images=[...this.images,...e.tempFilePaths]}})},deleteImage(e){this.images.splice(e,1)},submitFeedback(){-1!==this.selectedType?this.description.trim()?this.contact?e.index.showToast({title:"提交成功",icon:"success"}):e.index.showToast({title:"请留下联系方式",icon:"none"}):e.index.showToast({title:"请描述您的问题",icon:"none"}):e.index.showToast({title:"请选择问题类型",icon:"none"})}}};const s=e._export_sfc(t,[["render",function(t,s,i,c,o,a){return e.e({a:e.f(o.types,((t,s,i)=>({a:e.t(t),b:s,c:o.selectedType===s?1:"",d:e.o((e=>a.selectType(s)),s)}))),b:o.description,c:e.o((e=>o.description=e.detail.value)),d:e.t(o.description.length),e:e.f(o.images,((t,s,i)=>({a:t,b:e.o((e=>a.deleteImage(s)),s),c:s}))),f:o.images.length<3},o.images.length<3?{g:e.o(((...e)=>a.chooseImage&&a.chooseImage(...e)))}:{},{h:o.contact,i:e.o((e=>o.contact=e.detail.value)),j:e.o(((...e)=>a.submitFeedback&&a.submitFeedback(...e)))})}],["__scopeId","data-v-229c69af"]]);wx.createPage(s);
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "投诉与建议",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="feedback-container data-v-229c69af"><view class="type-section data-v-229c69af"><view class="section-title data-v-229c69af">问题类型</view><view class="type-grid data-v-229c69af"><view wx:for="{{a}}" wx:for-item="type" wx:key="b" class="{{['type-item', 'data-v-229c69af', type.c && 'active']}}" bindtap="{{type.d}}">{{type.a}}</view></view></view><view class="description-section data-v-229c69af"><view class="section-title data-v-229c69af">问题描述</view><block wx:if="{{r0}}"><textarea class="description-input data-v-229c69af" placeholder="请详细描述您遇到的问题,以便我们更好地为您解决" maxlength="500" value="{{b}}" bindinput="{{c}}"/></block><view class="word-count data-v-229c69af">{{d}}/500</view></view><view class="upload-section data-v-229c69af"><view class="section-title data-v-229c69af">图片上传(选填)</view><view class="upload-grid data-v-229c69af"><view wx:for="{{e}}" wx:for-item="img" wx:key="c" class="upload-item data-v-229c69af"><image class="data-v-229c69af" src="{{img.a}}" mode="aspectFill"/><view class="delete-btn data-v-229c69af" bindtap="{{img.b}}">×</view></view><view wx:if="{{f}}" class="upload-btn data-v-229c69af" bindtap="{{g}}"><text class="plus data-v-229c69af">+</text><text class="tip data-v-229c69af">上传图片</text></view></view></view><view class="contact-section data-v-229c69af"><view class="section-title data-v-229c69af">联系方式</view><input class="contact-input data-v-229c69af" placeholder="请留下您的手机号,方便我们联系您" type="number" maxlength="11" value="{{h}}" bindinput="{{i}}"/></view><view class="submit-section data-v-229c69af"><button class="submit-btn data-v-229c69af" bindtap="{{j}}">提交反馈</button></view></view>
@@ -0,0 +1 @@
.feedback-container.data-v-229c69af{min-height:100vh;background:#f8f8f8;padding:30rpx}.feedback-container .section-title.data-v-229c69af{font-size:30rpx;color:#333;font-weight:500;margin-bottom:20rpx}.feedback-container .type-section.data-v-229c69af{background:#fff;border-radius:20rpx;padding:30rpx;margin-bottom:20rpx}.feedback-container .type-section .type-grid.data-v-229c69af{display:flex;flex-wrap:wrap;margin:0 -10rpx}.feedback-container .type-section .type-grid .type-item.data-v-229c69af{width:calc(50% - 20rpx);margin:10rpx;height:80rpx;display:flex;align-items:center;justify-content:center;background:#f5f5f5;border-radius:10rpx;font-size:28rpx;color:#666;transition:all .3s}.feedback-container .type-section .type-grid .type-item.active.data-v-229c69af{background:#e3f2fd;color:#1976d2}.feedback-container .description-section.data-v-229c69af{background:#fff;border-radius:20rpx;padding:30rpx;margin-bottom:20rpx}.feedback-container .description-section .description-input.data-v-229c69af{width:100%;height:240rpx;background:#f8f8f8;border-radius:10rpx;padding:20rpx;font-size:28rpx;color:#333;box-sizing:border-box}.feedback-container .description-section .word-count.data-v-229c69af{text-align:right;font-size:24rpx;color:#999;margin-top:10rpx}.feedback-container .upload-section.data-v-229c69af{background:#fff;border-radius:20rpx;padding:30rpx;margin-bottom:20rpx}.feedback-container .upload-section .upload-grid.data-v-229c69af{display:flex;flex-wrap:wrap}.feedback-container .upload-section .upload-grid .upload-item.data-v-229c69af{width:200rpx;height:200rpx;margin-right:20rpx;margin-bottom:20rpx;position:relative}.feedback-container .upload-section .upload-grid .upload-item image.data-v-229c69af{width:100%;height:100%;border-radius:10rpx}.feedback-container .upload-section .upload-grid .upload-item .delete-btn.data-v-229c69af{position:absolute;right:-10rpx;top:-10rpx;width:40rpx;height:40rpx;background:rgba(0,0,0,.5);color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:32rpx}.feedback-container .upload-section .upload-grid .upload-btn.data-v-229c69af{width:200rpx;height:200rpx;background:#f5f5f5;border-radius:10rpx;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#999}.feedback-container .upload-section .upload-grid .upload-btn .plus.data-v-229c69af{font-size:60rpx;line-height:1;margin-bottom:10rpx}.feedback-container .upload-section .upload-grid .upload-btn .tip.data-v-229c69af{font-size:24rpx}.feedback-container .contact-section.data-v-229c69af{background:#fff;border-radius:20rpx;padding:30rpx;margin-bottom:40rpx}.feedback-container .contact-section .contact-input.data-v-229c69af{width:100%;height:80rpx;background:#f8f8f8;border-radius:10rpx;padding:0 20rpx;font-size:28rpx;color:#333;box-sizing:border-box}.feedback-container .submit-section.data-v-229c69af{padding:0 40rpx}.feedback-container .submit-section .submit-btn.data-v-229c69af{width:100%;height:88rpx;background:#1976d2;color:#fff;border-radius:44rpx;font-size:32rpx;font-weight:500;display:flex;align-items:center;justify-content:center}.feedback-container .submit-section .submit-btn.data-v-229c69af:active{transform:scale(.98)}
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),T=require("../../constants/help.js"),E={data:()=>({HELP_CONTENT:T.HELP_CONTENT,faqList:T.HELP_CONTENT.FAQ_LIST.map((e=>({...e,isOpen:!1})))}),methods:{toggleFaq(e){this.faqList[e].isOpen=!this.faqList[e].isOpen},makePhoneCall(){e.index.makePhoneCall({phoneNumber:T.HELP_CONTENT.CONTACT.PHONE.VALUE})}}};const t=e._export_sfc(E,[["render",function(T,E,t,N,C,a){return{a:e.f(C.faqList,((T,E,t)=>({a:e.t(T.question),b:T.isOpen?1:"",c:e.t(T.answer),d:T.isOpen,e:E,f:e.o((e=>a.toggleFaq(E)),E)}))),b:e.t(C.HELP_CONTENT.CONTACT.TITLE),c:e.t(C.HELP_CONTENT.CONTACT.PHONE.LABEL),d:e.t(C.HELP_CONTENT.CONTACT.PHONE.VALUE),e:e.o(((...e)=>a.makePhoneCall&&a.makePhoneCall(...e))),f:e.t(C.HELP_CONTENT.CONTACT.SERVICE_TIME.LABEL),g:e.t(C.HELP_CONTENT.CONTACT.SERVICE_TIME.VALUE)}}],["__scopeId","data-v-8f1810be"]]);wx.createPage(t);
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "帮助中心",
"usingComponents": {}
}
+1
View File
@@ -0,0 +1 @@
<view class="help-container data-v-8f1810be"><view class="faq-list data-v-8f1810be"><view wx:for="{{a}}" wx:for-item="item" wx:key="e" class="faq-item data-v-8f1810be" bindtap="{{item.f}}"><view class="faq-header data-v-8f1810be"><text class="question data-v-8f1810be">{{item.a}}</text><view class="{{['arrow', 'data-v-8f1810be', item.b && 'open']}}"></view></view><view class="answer data-v-8f1810be" hidden="{{!item.d}}">{{item.c}}</view></view></view><view class="contact-card data-v-8f1810be"><view class="contact-title data-v-8f1810be">{{b}}</view><view class="contact-content data-v-8f1810be"><view class="contact-item data-v-8f1810be"><text class="label data-v-8f1810be">{{c}}</text><text class="value data-v-8f1810be" bindtap="{{e}}">{{d}}</text></view><view class="contact-item data-v-8f1810be"><text class="label data-v-8f1810be">{{f}}</text><text class="value data-v-8f1810be">{{g}}</text></view></view></view></view>
+1
View File
@@ -0,0 +1 @@
.help-container.data-v-8f1810be{min-height:100vh;background:#f8f8f8;padding:30rpx}.help-container .faq-list.data-v-8f1810be{background:#fff;border-radius:20rpx;padding:20rpx;margin-bottom:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.help-container .faq-list .faq-item.data-v-8f1810be{border-bottom:1rpx solid #f5f5f5}.help-container .faq-list .faq-item.data-v-8f1810be:last-child{border-bottom:none}.help-container .faq-list .faq-item .faq-header.data-v-8f1810be{display:flex;justify-content:space-between;align-items:center;padding:30rpx 20rpx}.help-container .faq-list .faq-item .faq-header .question.data-v-8f1810be{font-size:30rpx;color:#333;flex:1;padding-right:20rpx}.help-container .faq-list .faq-item .faq-header .arrow.data-v-8f1810be{width:16rpx;height:16rpx;border-right:4rpx solid #999;border-bottom:4rpx solid #999;transform:rotate(45deg);transition:all .3s}.help-container .faq-list .faq-item .faq-header .arrow.open.data-v-8f1810be{transform:rotate(-135deg)}.help-container .faq-list .faq-item .answer.data-v-8f1810be{font-size:28rpx;color:#666;line-height:1.6;padding:0 20rpx 30rpx;background:#f9f9f9;border-radius:10rpx;margin:0 20rpx 20rpx}.help-container .contact-card.data-v-8f1810be{background:#fff;border-radius:20rpx;padding:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.help-container .contact-card .contact-title.data-v-8f1810be{font-size:32rpx;color:#333;font-weight:500;margin-bottom:20rpx;border-left:8rpx solid #1976D2;padding-left:20rpx}.help-container .contact-card .contact-content .contact-item.data-v-8f1810be{display:flex;justify-content:space-between;align-items:center;padding:20rpx 0}.help-container .contact-card .contact-content .contact-item .label.data-v-8f1810be{font-size:28rpx;color:#666}.help-container .contact-card .contact-content .contact-item .value.data-v-8f1810be{font-size:28rpx;color:#333;font-weight:500}.help-container .contact-card .contact-content .contact-item .value.data-v-8f1810be:active{opacity:.7}
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),o=require("../../util/index.js"),t=require("../../config/url.js"),n=require("../../common/assets.js"),a={methods:{async handleScan(){try{const n=await new Promise(((o,t)=>{e.index.scanCode({success:o,fail:t})}));let a=o.getQueryString(n.path,"deviceNo");if(console.log("扫码路径:",n.path),console.log("解析到的设备号:",a),!a)return void e.index.showToast({title:"无效的设备二维码",icon:"none"});e.index.getStorageSync("token")||await o.wxLogin();const d=await e.index.request({url:`${t.URL||"http://127.0.0.1:8080"}/app/order/inUse`,method:"GET",header:{Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")}});if(console.log("使用中订单检查结果:",JSON.stringify(d)),200==d.statusCode&&200==d.data.code&&d.data.data){const o=d.data.data;return console.log("检测到使用中订单,准备跳转:",o),e.index.reLaunch({url:`/pages/return/index?orderId=${o.orderId}&deviceId=${a||o.deviceNo}`}),void console.log("已发起页面跳转")}const i=await e.index.request({url:`${t.URL||"http://127.0.0.1:8080"}/app/order/unpaid`,method:"GET",header:{Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")}});if(console.log("待支付订单检查结果:",JSON.stringify(i)),200==i.statusCode&&200==i.data.code&&i.data.data){const o=i.data.data;console.log("检测到待支付订单,准备跳转:",o),e.index.navigateTo({url:`/pages/order/payment?orderId=${o.orderId}`})}else console.log("无待支付订单,直接跳转到设备详情页面, deviceNo:",a),e.index.navigateTo({url:`/pages/device/detail?deviceNo=${a}`})}catch(n){console.error("扫码处理失败:",n),e.index.showToast({title:"扫码失败",icon:"none"})}}}};const d=e._export_sfc(a,[["render",function(o,t,a,d,i,r){return{a:n._imports_0,b:e.o(((...e)=>r.handleScan&&r.handleScan(...e)))}}],["__scopeId","data-v-8df762f3"]]);wx.createPage(d);
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "共享风扇",
"usingComponents": {}
}
+1
View File
@@ -0,0 +1 @@
<view class="container data-v-8df762f3"><view class="banner data-v-8df762f3"><view class="temp-banner data-v-8df762f3"><text class="banner-text data-v-8df762f3">共享风扇</text><text class="banner-subtitle data-v-8df762f3">让清凉随身携带</text><view class="banner-bg data-v-8df762f3"></view></view></view><view class="scan-area data-v-8df762f3"><view class="scan-btn data-v-8df762f3" bindtap="{{b}}"><view class="btn-content data-v-8df762f3"><image class="btn-icon data-v-8df762f3" src="{{a}}" mode="aspectFit"/><text class="btn-text data-v-8df762f3">扫一扫</text></view><text class="btn-desc data-v-8df762f3">扫描设备二维码使用或归还</text></view></view><view class="tips-section data-v-8df762f3"><view class="tips-header data-v-8df762f3"><view class="tips-title data-v-8df762f3">使用小贴士</view></view><view class="tips-list data-v-8df762f3"><view class="tip-item data-v-8df762f3"><view class="tip-dot data-v-8df762f3"></view><text class="data-v-8df762f3">租借时间:每次最长可租借12小时</text></view><view class="tip-item data-v-8df762f3"><view class="tip-dot data-v-8df762f3"></view><text class="data-v-8df762f3">押金说明:租借需支付99元押金,归还后自动退还</text></view><view class="tip-item data-v-8df762f3"><view class="tip-dot data-v-8df762f3"></view><text class="data-v-8df762f3">收费标准:2元/小时,不足1小时按1小时计算</text></view><view class="tip-item data-v-8df762f3"><view class="tip-dot data-v-8df762f3"></view><text class="data-v-8df762f3">爱护提示:请勿将设备带离指定区域,保持设备清洁</text></view></view></view></view>
+1
View File
@@ -0,0 +1 @@
.container.data-v-8df762f3{height:87.5vh;background:#f8f8f8;padding-bottom:40rpx}.container .banner.data-v-8df762f3{padding:30rpx}.container .banner .temp-banner.data-v-8df762f3{height:300rpx;background:linear-gradient(135deg,#1976d2,#42a5f5);border-radius:30rpx;position:relative;overflow:hidden;display:flex;flex-direction:column;justify-content:center;align-items:center;color:#fff;box-shadow:0 8rpx 32rpx rgba(25,118,210,.2)}.container .banner .temp-banner .banner-text.data-v-8df762f3{font-size:56rpx;font-weight:700;margin-bottom:20rpx;position:relative;z-index:1;text-shadow:0 2rpx 4rpx rgba(0,0,0,.1)}.container .banner .temp-banner .banner-subtitle.data-v-8df762f3{font-size:32rpx;opacity:.95;position:relative;z-index:1;text-shadow:0 2rpx 4rpx rgba(0,0,0,.1)}.container .banner .temp-banner .banner-bg.data-v-8df762f3{position:absolute;right:-60rpx;bottom:-60rpx;width:300rpx;height:300rpx;background:rgba(255,255,255,.1);border-radius:50%;transform:rotate(-15deg)}.container .banner .temp-banner.data-v-8df762f3:after{content:"";position:absolute;left:-80rpx;top:-80rpx;width:240rpx;height:240rpx;background:rgba(255,255,255,.08);border-radius:50%}.container .scan-area.data-v-8df762f3{padding:20rpx 30rpx 40rpx;display:flex;justify-content:center}.container .scan-area .scan-btn.data-v-8df762f3{width:460rpx;height:200rpx;display:flex;flex-direction:column;align-items:center;justify-content:center;background:linear-gradient(135deg,#00c853,#69f0ae);border-radius:30rpx;box-shadow:0 8rpx 32rpx rgba(0,200,83,.2);transition:all .3s ease;position:relative;overflow:hidden}.container .scan-area .scan-btn.data-v-8df762f3:active{transform:scale(.98);box-shadow:0 4rpx 16rpx rgba(0,200,83,.15)}.container .scan-area .scan-btn.data-v-8df762f3:after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(rgba(255,255,255,.1),transparent)}.container .scan-area .scan-btn .btn-content.data-v-8df762f3{display:flex;align-items:center;justify-content:center;margin-bottom:12rpx;position:relative;z-index:1}.container .scan-area .scan-btn .btn-content .btn-icon.data-v-8df762f3{width:48rpx;height:48rpx;margin-right:16rpx}.container .scan-area .scan-btn .btn-content .btn-text.data-v-8df762f3{font-size:42rpx;font-weight:600;color:#fff;text-shadow:0 2rpx 4rpx rgba(0,0,0,.1)}.container .scan-area .scan-btn .btn-desc.data-v-8df762f3{font-size:26rpx;color:rgba(255,255,255,.95);position:relative;z-index:1}.container .tips-section.data-v-8df762f3{margin:0 30rpx;background:#fff;border-radius:24rpx;box-shadow:0 8rpx 32rpx rgba(0,0,0,.05);overflow:hidden}.container .tips-section .tips-header.data-v-8df762f3{padding:30rpx;background:linear-gradient(to right,#f5f9ff,#fff);border-bottom:2rpx solid #f0f0f0}.container .tips-section .tips-header .tips-title.data-v-8df762f3{font-size:32rpx;font-weight:600;color:#333;position:relative;padding-left:24rpx}.container .tips-section .tips-header .tips-title.data-v-8df762f3:before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:8rpx;height:32rpx;background:#1976d2;border-radius:4rpx}.container .tips-section .tips-list.data-v-8df762f3{padding:20rpx 30rpx}.container .tips-section .tips-list .tip-item.data-v-8df762f3{display:flex;align-items:center;margin-bottom:24rpx;padding:0 10rpx}.container .tips-section .tips-list .tip-item.data-v-8df762f3:last-child{margin-bottom:0}.container .tips-section .tips-list .tip-item .tip-dot.data-v-8df762f3{width:12rpx;height:12rpx;background:#1976d2;border-radius:50%;margin-right:16rpx;flex-shrink:0;box-shadow:0 2rpx 6rpx rgba(25,118,210,.2)}.container .tips-section .tips-list .tip-item text.data-v-8df762f3{font-size:28rpx;color:#666;line-height:1.6}
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),o=require("../../util/index.js"),t=require("../../common/assets.js"),n={data:()=>({userInfo:{},deposit:"0.00",tempAvatar:"",tempNickname:"",show:!1}),onShow(){this.getInfo()},methods:{async getInfo(){try{if(!e.index.getStorageSync("token"))return await o.wxLogin(),void this.getInfo();const t=await o.getUserInfo();if(console.log(t),200===t.code){const o={nickName:t.data.nickname,phone:t.data.phone,avatar:t.data.iconUrl,isAdmin:t.data.isAdmin};this.userInfo=o,e.index.setStorageSync("userInfo",o),this.deposit=t.data.balanceAmount||"0.00"}}catch(t){console.error("获取用户信息失败:",t),e.index.showToast({title:"获取用户信息失败",icon:"none"})}},navigateTo(o){e.index.navigateTo({url:o})}}};const a=e._export_sfc(n,[["render",function(o,n,a,s,i,r){return e.e({a:i.userInfo.avatar||"/static/user.png",b:i.userInfo},i.userInfo?{c:e.t(i.userInfo.nickName),d:e.t(i.userInfo.phone||"")}:{},{e:e.o(((...e)=>o.showPopup&&o.showPopup(...e))),f:e.t(i.deposit),g:e.o((e=>r.navigateTo("/pages/deposit/index"))),h:t._imports_0$1,i:e.o((e=>r.navigateTo("/pages/order/index"))),j:t._imports_1,k:e.o((e=>r.navigateTo("/pages/feedback/index"))),l:t._imports_2,m:e.o((e=>r.navigateTo("/pages/help/index")))})}],["__scopeId","data-v-b106ba06"]]);wx.createPage(a);
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "个人中心",
"usingComponents": {}
}
+1
View File
@@ -0,0 +1 @@
<view class="my-container data-v-b106ba06"><view class="user-info data-v-b106ba06"><view class="floating-dots data-v-b106ba06"></view><view class="user-info-content data-v-b106ba06" bindtap="{{e}}"><view class="avatar-wrap data-v-b106ba06"><image class="avatar data-v-b106ba06" src="{{a}}" mode="aspectFill"/></view><view wx:if="{{b}}" class="info-content data-v-b106ba06"><view class="text-group data-v-b106ba06"><text class="nickname data-v-b106ba06">{{c}}</text><text class="phone data-v-b106ba06">{{d}}</text></view></view><view wx:else class="info-content not-login data-v-b106ba06"><text class="login-text data-v-b106ba06">点击登录</text><text class="login-desc data-v-b106ba06">登录后享受更多服务</text></view></view><view class="wave-decoration data-v-b106ba06"></view></view><view class="balance-card data-v-b106ba06"><view class="balance-content data-v-b106ba06"><text class="label data-v-b106ba06">押金余额</text><text class="amount data-v-b106ba06">¥{{f}}</text></view><view class="withdraw-btn data-v-b106ba06" bindtap="{{g}}"> 提现 <view class="arrow data-v-b106ba06"></view></view></view><view class="function-list data-v-b106ba06"><view class="function-item data-v-b106ba06" bindtap="{{i}}"><view class="item-left data-v-b106ba06"><view class="icon-wrap order data-v-b106ba06"><image src="{{h}}" mode="aspectFit" class="icon-image data-v-b106ba06"/></view><text class="title data-v-b106ba06">租借记录</text></view><view class="arrow data-v-b106ba06"></view></view><view class="function-item data-v-b106ba06" bindtap="{{k}}"><view class="item-left data-v-b106ba06"><view class="icon-wrap feedback data-v-b106ba06"><image src="{{j}}" mode="aspectFit" class="icon-image data-v-b106ba06"/></view><text class="title data-v-b106ba06">投诉与建议</text></view><view class="arrow data-v-b106ba06"></view></view><view class="function-item data-v-b106ba06" bindtap="{{m}}"><view class="item-left data-v-b106ba06"><view class="icon-wrap help data-v-b106ba06"><image src="{{l}}" mode="aspectFit" class="icon-image data-v-b106ba06"/></view><text class="title data-v-b106ba06">帮助中心</text></view><view class="arrow data-v-b106ba06"></view></view></view></view>
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
"use strict";const t=require("../../common/vendor.js"),e=require("../../config/user.js"),r=require("../../constants/orderStatus.js"),s={data:()=>({currentTab:0,OrderStatusMap:r.OrderStatusMap,OrderStatusTabs:r.OrderStatusTabs,orderList:[]}),async onLoad(t){if(t&&t.orderId)try{const r=await e.queryById(t.orderId);if(200===r.code&&r.data){const t=r.data;console.log("特定订单数据:",JSON.stringify(t)),console.log("特定订单的开始时间:",t.startTime),console.log("特定订单的创建时间:",t.createTime);const e=t.startTime||t.createTime||"";console.log("特定订单最终显示的开始时间:",e);const s={orderNo:t.orderId,status:t.orderStatus,deviceId:t.deviceNo,startTime:e,endTime:t.endTime||"",amount:t.payAmount||t.actualDeviceAmount||"0.00"};this.orderList=[s,...this.orderList];const o=this.OrderStatusTabs.findIndex((e=>e.status.includes(t.orderStatus)));-1!==o&&this.switchTab(o)}}catch(r){console.error("获取订单详情失败:",r)}await this.getOrderList()},methods:{async getOrderList(r=[]){try{const t=await e.getOrderList(r);200===t.code&&t.data&&t.data.records&&(console.log("API返回的订单列表数据:",JSON.stringify(t.data.records)),this.orderList=t.data.records.map((t=>{console.log(`订单 ${t.orderId} 的开始时间:`,t.startTime),console.log(`订单 ${t.orderId} 的创建时间:`,t.createTime);const e=t.startTime||t.createTime||"";return console.log(`订单 ${t.orderId} 最终显示的开始时间:`,e),{orderNo:t.orderId,status:t.orderStatus,deviceId:t.deviceNo,startTime:e,endTime:t.endTime||"",amount:t.payAmount||t.actualDeviceAmount||"0.00"}})))}catch(s){console.error("获取订单列表失败:",s),t.index.showToast({title:"获取订单列表失败",icon:"none"})}},async switchTab(t){this.currentTab=t;const e=this.OrderStatusTabs[t].status;await this.getOrderList(e)}}};const o=t._export_sfc(s,[["render",function(e,r,s,o,a,d){return t.e({a:t.f(a.OrderStatusTabs,((e,r,s)=>({a:t.t(e.text),b:r,c:a.currentTab===r?1:"",d:t.o((t=>d.switchTab(r)),r)}))),b:t.f(a.orderList,((e,r,s)=>{var o,d;return t.e({a:t.t(e.orderNo),b:t.t(null==(o=a.OrderStatusMap[e.status])?void 0:o.text),c:t.n(null==(d=a.OrderStatusMap[e.status])?void 0:d.class),d:1===e.status},1===e.status?{e:`/pages/return/index?deviceId=${e.deviceId}&orderId=${e.orderNo}`}:{},{f:t.t(e.deviceId),g:t.t(e.startTime),h:t.t(e.endTime||"-"),i:t.t(e.amount),j:r})})),c:0===a.orderList.length},(a.orderList.length,{}))}],["__scopeId","data-v-d5ec5c8e"]]);wx.createPage(o);
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "租借记录",
"usingComponents": {}
}
+1
View File
@@ -0,0 +1 @@
<view class="order-container data-v-d5ec5c8e"><view class="tab-bar data-v-d5ec5c8e"><view wx:for="{{a}}" wx:for-item="tab" wx:key="b" class="{{['tab-item', 'data-v-d5ec5c8e', tab.c && 'active']}}" bindtap="{{tab.d}}">{{tab.a}}</view></view><view class="order-list data-v-d5ec5c8e"><view wx:for="{{b}}" wx:for-item="order" wx:key="j" class="order-item data-v-d5ec5c8e"><view class="order-header data-v-d5ec5c8e"><text class="order-no data-v-d5ec5c8e">订单号:{{order.a}}</text><text class="{{['order-status', 'data-v-d5ec5c8e', order.c]}}">{{order.b}}</text><navigator wx:if="{{order.d}}" url="{{order.e}}" class="return-btn data-v-d5ec5c8e">归还设备</navigator></view><view class="order-content data-v-d5ec5c8e"><view class="device-info data-v-d5ec5c8e"><text class="device-name data-v-d5ec5c8e">共享风扇</text><text class="device-id data-v-d5ec5c8e">设备号:{{order.f}}</text></view><view class="time-info data-v-d5ec5c8e"><view class="time-item data-v-d5ec5c8e"><text class="label data-v-d5ec5c8e">开始时间:</text><text class="value data-v-d5ec5c8e">{{order.g}}</text></view><view class="time-item data-v-d5ec5c8e"><text class="label data-v-d5ec5c8e">结束时间:</text><text class="value data-v-d5ec5c8e">{{order.h}}</text></view></view><view class="price-info data-v-d5ec5c8e"><text class="amount data-v-d5ec5c8e">¥{{order.i}}</text></view></view></view></view><view wx:if="{{c}}" class="empty-tip data-v-d5ec5c8e"><view class="empty-icon data-v-d5ec5c8e"></view><text class="data-v-d5ec5c8e">暂无订单记录</text></view></view>
+1
View File
@@ -0,0 +1 @@
.order-container.data-v-d5ec5c8e{min-height:100vh;background:#f8f8f8}.order-container .tab-bar.data-v-d5ec5c8e{display:flex;background:#fff;padding:20rpx 0;position:-webkit-sticky;position:sticky;top:0;z-index:100;box-shadow:0 2rpx 10rpx rgba(0,0,0,.05)}.order-container .tab-bar .tab-item.data-v-d5ec5c8e{flex:1;text-align:center;font-size:28rpx;color:#666;position:relative;padding:20rpx 0}.order-container .tab-bar .tab-item.active.data-v-d5ec5c8e{color:#1976d2;font-weight:500}.order-container .tab-bar .tab-item.active.data-v-d5ec5c8e:after{content:"";position:absolute;bottom:0;left:50%;transform:translate(-50%);width:40rpx;height:4rpx;background:#1976d2;border-radius:2rpx}.order-container .order-list.data-v-d5ec5c8e{padding:20rpx}.order-container .order-list .order-item.data-v-d5ec5c8e{background:#fff;border-radius:20rpx;margin-bottom:20rpx;padding:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.order-container .order-list .order-item .order-header.data-v-d5ec5c8e{display:flex;justify-content:space-between;align-items:center;padding-bottom:20rpx;border-bottom:1rpx solid #f5f5f5}.order-container .order-list .order-item .order-header .order-no.data-v-d5ec5c8e{font-size:26rpx;color:#666}.order-container .order-list .order-item .order-header .order-status.data-v-d5ec5c8e{font-size:26rpx}.order-container .order-list .order-item .order-header .order-status.status-waiting.data-v-d5ec5c8e{color:#ff9800}.order-container .order-list .order-item .order-header .order-status.status-progress.data-v-d5ec5c8e{color:#2196f3}.order-container .order-list .order-item .order-header .order-status.status-success.data-v-d5ec5c8e{color:#4caf50}.order-container .order-list .order-item .order-header .order-status.status-using.data-v-d5ec5c8e{color:#1976d2}.order-container .order-list .order-item .order-header .order-status.status-failed.data-v-d5ec5c8e{color:#f44336}.order-container .order-list .order-item .order-header .order-status.status-cancelled.data-v-d5ec5c8e{color:#9e9e9e}.order-container .order-list .order-item .order-header .order-status.status-finished.data-v-d5ec5c8e{color:#4caf50}.order-container .order-list .order-item .order-content.data-v-d5ec5c8e{padding-top:20rpx}.order-container .order-list .order-item .order-content .device-info.data-v-d5ec5c8e{margin-bottom:20rpx}.order-container .order-list .order-item .order-content .device-info .device-name.data-v-d5ec5c8e{font-size:32rpx;color:#333;font-weight:500;margin-right:20rpx}.order-container .order-list .order-item .order-content .device-info .device-id.data-v-d5ec5c8e{font-size:26rpx;color:#999}.order-container .order-list .order-item .order-content .time-info .time-item.data-v-d5ec5c8e{font-size:26rpx;color:#666;margin-bottom:10rpx}.order-container .order-list .order-item .order-content .time-info .time-item .label.data-v-d5ec5c8e{color:#999}.order-container .order-list .order-item .order-content .price-info.data-v-d5ec5c8e{text-align:right;margin-top:20rpx}.order-container .order-list .order-item .order-content .price-info .amount.data-v-d5ec5c8e{font-size:36rpx;color:#ff9800;font-weight:500}.order-container .empty-tip.data-v-d5ec5c8e{padding:100rpx 0;text-align:center;color:#999;font-size:28rpx}.order-container .empty-tip .empty-icon.data-v-d5ec5c8e{width:200rpx;height:200rpx;margin:0 auto 20rpx;background:#f0f0f0;border-radius:50%}
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),t=require("../../config/user.js"),o=require("../../config/url.js"),r={data:()=>({orderId:null,orderInfo:{},packageInfo:{time:"",price:"0.00"},orderStatus:{text:"等待支付",desc:"请在15分钟内完成支付",class:"waiting"},paymentMethods:[{name:"微信支付",icon:"wechat"},{name:"支付宝",icon:"alipay"}],selectedMethod:0}),computed:{totalAmount(){return(parseFloat(this.orderInfo.deposit||99)+parseFloat(this.orderInfo.amount||this.packageInfo.price||0)).toFixed(2)}},onLoad(t){t&&t.orderId?(this.orderId=t.orderId,t.packageTime&&t.packagePrice&&(this.packageInfo={time:t.packageTime,price:t.packagePrice}),this.loadOrderInfo()):(e.index.showToast({title:"订单信息不存在",icon:"none"}),setTimeout((()=>{e.index.redirectTo({url:"/pages/index/index"})}),1500))},methods:{async loadOrderInfo(){try{e.index.showLoading({title:"加载中"});const o=await t.queryById(this.orderId);if(200!==o.code||!o.data)throw new Error("获取订单信息失败");{const e=o.data;this.orderInfo={orderNo:e.orderNo||e.orderId,deviceNo:e.deviceNo,createTime:this.formatTime(new Date(e.createTime)),phone:e.phone,deposit:"99.00",amount:e.amount||this.packageInfo.price||"0.00"},!e.packageTime&&this.packageInfo.time&&(this.orderInfo.packageTime=this.packageInfo.time,this.orderInfo.packagePrice=this.packageInfo.price)}e.index.hideLoading()}catch(o){e.index.hideLoading(),e.index.showToast({title:o.message||"获取订单信息失败",icon:"none"})}},selectMethod(e){this.selectedMethod=e},async handlePayment(){try{e.index.showLoading({title:"处理中"});const t=await e.index.request({url:`${o.URL||"http://127.0.0.1:8080"}/app/wx-payment/create/${this.orderInfo.orderNo}`,method:"GET",header:{Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")}});if(200!==t.statusCode||200!==t.data.code)throw new Error(t.data.msg||"创建支付订单失败");{const o=t.data.data;await e.index.requestPayment({...o,success:()=>{this.pollOrderStatus()},fail:e=>{throw console.error("支付失败:",e),new Error("支付失败,请重试")}})}}catch(t){e.index.hideLoading(),e.index.showToast({title:t.message||"支付失败",icon:"none"})}},async sendRentCommand(){try{e.index.showLoading({title:"处理中"});const t=await this.sendRentRequest();if(200!==t.code)throw new Error(t.msg||"租借失败");e.index.hideLoading(),e.index.showToast({title:"租借成功",icon:"success"}),setTimeout((()=>{e.index.redirectTo({url:`/pages/order/index?orderId=${this.orderId}`})}),1500)}catch(t){e.index.hideLoading(),e.index.showToast({title:t.message||"租借失败",icon:"none"})}},sendRentRequest(){return new Promise(((t,r)=>{e.index.request({url:`${o.URL}/app/device/sendRentCommand`,method:"POST",data:{orderId:this.orderId},header:{"Content-Type":"application/x-www-form-urlencoded",Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")},success(e){200===e.statusCode?t(e.data):r(new Error("请求失败"))},fail(e){r(e)}})}))},formatTime:e=>`${e.getFullYear()}-${(e.getMonth()+1).toString().padStart(2,"0")}-${e.getDate().toString().padStart(2,"0")} ${e.getHours().toString().padStart(2,"0")}:${e.getMinutes().toString().padStart(2,"0")}`,async pollOrderStatus(){let t=0;const r=async()=>{try{const a=await e.index.request({url:`${o.URL||"http://127.0.0.1:8080"}/app/wx-payment/status/${this.orderInfo.orderNo}`,method:"GET",header:{Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")}});if(200===a.statusCode&&200===a.data.code){if("in_used"===a.data.data.orderStatus)return e.index.showToast({title:"支付成功",icon:"success"}),void setTimeout((()=>{e.index.redirectTo({url:`/pages/order/index?orderId=${this.orderId}`})}),1500)}if(!(t<10))throw new Error("订单状态查询超时");t++,setTimeout(r,1e3)}catch(a){e.index.showToast({title:a.message||"查询订单状态失败",icon:"none"})}};r()}}};const a=e._export_sfc(r,[["render",function(t,o,r,a,n,d){return{a:e.n(n.orderStatus.class),b:e.t(n.orderStatus.text),c:e.t(n.orderStatus.desc),d:e.t(n.orderInfo.orderNo||"-"),e:e.t(n.orderInfo.deviceNo||"-"),f:e.t(n.orderInfo.createTime||"-"),g:e.t(n.orderInfo.phone||"-"),h:e.t(n.orderInfo.deposit||"99.00"),i:e.t(n.packageInfo.time),j:e.t(n.packageInfo.price),k:e.t(n.orderInfo.amount||n.packageInfo.price),l:e.t(d.totalAmount),m:e.f(n.paymentMethods,((t,o,r)=>({a:e.n(t.icon),b:e.t(t.name),c:o,d:n.selectedMethod===o?1:"",e:e.o((e=>d.selectMethod(o)),o)}))),n:e.t(d.totalAmount),o:e.o(((...e)=>d.handlePayment&&d.handlePayment(...e)))}}],["__scopeId","data-v-a18b4e4b"]]);wx.createPage(a);
@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "订单支付",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="payment-container data-v-a18b4e4b"><view class="status-card data-v-a18b4e4b"><view class="{{['status-icon', 'data-v-a18b4e4b', a]}}"></view><view class="status-text data-v-a18b4e4b">{{b}}</view><view class="status-desc data-v-a18b4e4b">{{c}}</view></view><view class="order-card data-v-a18b4e4b"><view class="card-title data-v-a18b4e4b">订单信息</view><view class="info-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">订单号</text><text class="value data-v-a18b4e4b">{{d}}</text></view><view class="info-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">设备号</text><text class="value data-v-a18b4e4b">{{e}}</text></view><view class="info-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">创建时间</text><text class="value data-v-a18b4e4b">{{f}}</text></view><view class="info-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">联系电话</text><text class="value data-v-a18b4e4b">{{g}}</text></view></view><view class="price-card data-v-a18b4e4b"><view class="card-title data-v-a18b4e4b">费用信息</view><view class="price-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">押金</text><text class="value data-v-a18b4e4b">¥{{h}}</text></view><view class="price-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">套餐</text><text class="value data-v-a18b4e4b">{{i}} (¥{{j}})</text></view><view class="price-item data-v-a18b4e4b"><text class="label data-v-a18b4e4b">租借费用</text><text class="value data-v-a18b4e4b">¥{{k}}</text></view><view class="price-item total data-v-a18b4e4b"><text class="label data-v-a18b4e4b">合计</text><text class="value data-v-a18b4e4b">¥{{l}}</text></view></view><view class="payment-methods data-v-a18b4e4b"><view class="card-title data-v-a18b4e4b">支付方式</view><view wx:for="{{m}}" wx:for-item="method" wx:key="c" class="{{['method-item', 'data-v-a18b4e4b', method.d && 'active']}}" bindtap="{{method.e}}"><view class="{{['method-icon', 'data-v-a18b4e4b', method.a]}}"></view><view class="method-name data-v-a18b4e4b">{{method.b}}</view><view class="method-check data-v-a18b4e4b"></view></view></view><view class="bottom-bar data-v-a18b4e4b"><view class="total-amount data-v-a18b4e4b"><text class="data-v-a18b4e4b">合计:</text><text class="amount data-v-a18b4e4b">¥{{n}}</text></view><button class="pay-btn data-v-a18b4e4b" bindtap="{{o}}">立即支付</button></view></view>
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),t=require("../../config/user.js"),r=require("../../config/url.js"),o={data:()=>({orderId:"",orderInfo:{orderNo:"",deviceNo:"",usedTime:"",currentFee:"0.00",deposit:"99.00",refundAmount:"99.00",endTime:"",withdrawStatus:"waiting",isWithdrawn:!1}}),onLoad(t){t&&t.orderId?(this.orderId=t.orderId,this.loadOrderInfo()):(e.index.showToast({title:"订单ID不能为空",icon:"none"}),setTimeout((()=>{this.goToHome()}),1500))},methods:{getWithdrawStatusText(){return{waiting:"待申请",processing:"处理中",success:"已退款",failed:"退款失败"}[this.orderInfo.withdrawStatus]||"待申请"},async loadOrderInfo(){try{e.index.showLoading({title:"加载中"});const o=await t.queryById(this.orderId);if(200!==o.code||!o.data)throw new Error(o.msg||"获取订单信息失败");{const e=o.data;let t=60,d=0,n=0,i="0.00",a="0.00";if(e.remark)try{const r=e.remark,o=r.match(/使用时长:(\d+)分钟/);o&&o[1]&&(n=parseInt(o[1]));const s=r.match(/套餐时长:(\d+)分钟/);s&&s[1]&&(t=parseInt(s[1]));const c=r.match(/超出时长:(\d+)分钟/);c&&c[1]&&(d=parseInt(c[1]));const h=r.match(/套餐费用:([\d.]+)元/);h&&h[1]&&(i=h[1]);const u=r.match(/超时费用:([\d.]+)元/);u&&u[1]&&(a=u[1]),console.log("从remark解析到的信息:",{usedMinutes:n,packageMinutes:t,extraMinutes:d,packagePrice:i,extraFee:a})}catch(r){console.error("解析remark字段失败:",r)}this.orderInfo={orderNo:e.orderNo||"",deviceNo:e.deviceNo||"",usedTime:n+"分钟",packageTime:t+"分钟",extraTime:d+"分钟",packagePrice:i,extraFee:a,currentFee:e.actualDeviceAmount||"0.00",deposit:e.depositAmount||"99.00",refundAmount:e.residueAmount||"99.00",endTime:e.endTime||"",withdrawStatus:e.withdrawStatus||"waiting",isWithdrawn:"success"===e.withdrawStatus}}}catch(o){console.error("加载订单信息错误:",o),e.index.showToast({title:o.message||"获取订单信息失败",icon:"none"})}finally{e.index.hideLoading()}},async handleWithdraw(){try{e.index.showLoading({title:"处理中"});const t=await e.index.request({url:`${r.URL||"http://127.0.0.1:8080"}/app/withdraw/add/${this.orderInfo.orderNo}`,method:"GET",header:{"Content-Type":"application/json",Authorization:"Bearer "+e.index.getStorageSync("token"),Clientid:e.index.getStorageSync("client_id")}});if(200!==t.statusCode||200!==t.data.code)throw new Error(t.data.msg||"退款申请失败");e.index.showToast({title:"退款申请成功",icon:"success"}),this.orderInfo.withdrawStatus="processing",this.orderInfo.isWithdrawn=!0,setTimeout((()=>{this.loadOrderInfo()}),1500)}catch(t){console.error("退款申请错误:",t),e.index.showToast({title:t.message||"退款申请失败",icon:"none"})}finally{e.index.hideLoading()}},goToHome(){e.index.reLaunch({url:"/pages/index/index"})}}};const d=e._export_sfc(o,[["render",function(t,r,o,d,n,i){return e.e({a:e.t(n.orderInfo.orderNo||"-"),b:e.t(n.orderInfo.deviceNo||"-"),c:e.t(n.orderInfo.usedTime||"-"),d:e.t(n.orderInfo.packageTime||"1小时"),e:e.t(n.orderInfo.extraTime||"0分钟"),f:e.t(n.orderInfo.endTime||"-"),g:e.t(n.orderInfo.packagePrice||"0.00"),h:e.t(n.orderInfo.extraFee||"0.00"),i:e.t(n.orderInfo.currentFee||"0.00"),j:e.t(n.orderInfo.deposit||"99.00"),k:e.t(n.orderInfo.refundAmount||"99.00"),l:e.t(i.getWithdrawStatusText()),m:e.n(n.orderInfo.withdrawStatus||"waiting"),n:!n.orderInfo.isWithdrawn},n.orderInfo.isWithdrawn?{}:{o:e.o(((...e)=>i.handleWithdraw&&i.handleWithdraw(...e)))},{p:e.o(((...e)=>i.goToHome&&i.goToHome(...e)))})}],["__scopeId","data-v-845b5869"]]);wx.createPage(d);
@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "归还成功",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="success-container data-v-845b5869"><view class="status-card data-v-845b5869"><view class="status-icon success data-v-845b5869"></view><view class="status-text data-v-845b5869">归还成功</view><view class="status-desc data-v-845b5869">您的充电宝已归还,费用已从押金中扣除</view></view><view class="order-card data-v-845b5869"><view class="card-title data-v-845b5869">订单信息</view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">订单号</text><text class="value data-v-845b5869">{{a}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">设备号</text><text class="value data-v-845b5869">{{b}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">使用时长</text><text class="value data-v-845b5869">{{c}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">套餐时长</text><text class="value data-v-845b5869">{{d}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">超出时长</text><text class="value data-v-845b5869">{{e}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">归还时间</text><text class="value data-v-845b5869">{{f}}</text></view></view><view class="refund-card data-v-845b5869"><view class="card-title data-v-845b5869">费用信息</view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">套餐费用</text><text class="value data-v-845b5869">¥{{g}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">超时费用</text><text class="value data-v-845b5869">¥{{h}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">总费用</text><text class="value data-v-845b5869">¥{{i}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">押金</text><text class="value data-v-845b5869">¥{{j}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">退还金额</text><text class="value highlight data-v-845b5869">¥{{k}}</text></view><view class="info-item data-v-845b5869"><text class="label data-v-845b5869">退还状态</text><text class="{{['value', 'data-v-845b5869', m]}}">{{l}}</text></view></view><view class="notice-card data-v-845b5869"><view class="card-title data-v-845b5869">退款说明</view><view class="notice-content data-v-845b5869"><text class="data-v-845b5869">1. 押金剩余金额需要您手动申请提现</text><text class="data-v-845b5869">2. 提现申请提交后将在1-3个工作日内退还到原支付账户</text><text class="data-v-845b5869">3. 如有疑问,请联系客服</text></view></view><view class="button-group data-v-845b5869"><button wx:if="{{n}}" class="primary-btn data-v-845b5869" bindtap="{{o}}">申请退款</button><button class="primary-btn data-v-845b5869" bindtap="{{p}}">返回首页</button></view></view>
@@ -0,0 +1 @@
.success-container.data-v-845b5869{padding:20px;background-color:#f8f8f8;min-height:100vh}.status-card.data-v-845b5869{background-color:#fff;border-radius:12px;padding:30px;text-align:center;margin-bottom:20px;box-shadow:0 2px 8px rgba(0,0,0,.04)}.status-card .status-icon.data-v-845b5869{width:60px;height:60px;margin:0 auto 16px}.status-card .status-icon.success.data-v-845b5869{background-color:#07c160;border-radius:50%;position:relative}.status-card .status-icon.success.data-v-845b5869:after{content:"";position:absolute;left:50%;top:50%;width:30px;height:20px;border:3px solid #fff;border-top:none;border-right:none;transform-origin:center;transform:translate(-50%,-70%) rotate(-45deg)}.status-card .status-text.data-v-845b5869{font-size:24px;font-weight:700;color:#07c160;margin-bottom:8px}.status-card .status-desc.data-v-845b5869{font-size:14px;color:#666}.order-card.data-v-845b5869,.refund-card.data-v-845b5869{background-color:#fff;border-radius:12px;padding:20px;margin-bottom:20px;box-shadow:0 2px 8px rgba(0,0,0,.04)}.order-card .card-title.data-v-845b5869,.refund-card .card-title.data-v-845b5869{font-size:16px;font-weight:700;margin-bottom:16px;color:#333;border-bottom:1px solid #f0f0f0;padding-bottom:10px}.order-card .info-item.data-v-845b5869,.refund-card .info-item.data-v-845b5869{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.order-card .info-item.data-v-845b5869:last-child,.refund-card .info-item.data-v-845b5869:last-child{margin-bottom:0}.order-card .info-item .label.data-v-845b5869,.refund-card .info-item .label.data-v-845b5869{color:#666;font-size:14px}.order-card .info-item .value.data-v-845b5869,.refund-card .info-item .value.data-v-845b5869{color:#333;font-size:14px}.order-card .info-item .value.highlight.data-v-845b5869,.refund-card .info-item .value.highlight.data-v-845b5869{color:#ff6b00;font-weight:700;font-size:16px}.order-card .info-item .value.success.data-v-845b5869,.refund-card .info-item .value.success.data-v-845b5869{color:#07c160}.button-group.data-v-845b5869{margin-top:40rpx;display:flex;justify-content:space-between;gap:20rpx}.button-group .primary-btn.data-v-845b5869,.button-group .secondary-btn.data-v-845b5869{flex:1;height:88rpx;line-height:88rpx;border-radius:44rpx;text-align:center;font-size:32rpx}.button-group .primary-btn.data-v-845b5869{background:#07c160;color:#fff}.button-group .primary-btn.data-v-845b5869:active{opacity:.8}.button-group .secondary-btn.data-v-845b5869{background:#f0f0f0;color:#333}.button-group .secondary-btn.data-v-845b5869:active{opacity:.8}.notice-card.data-v-845b5869{background-color:#fff;border-radius:12px;padding:20px;margin-bottom:20px;box-shadow:0 2px 8px rgba(0,0,0,.04)}.notice-card .card-title.data-v-845b5869{font-size:16px;font-weight:700;margin-bottom:16px;color:#333;border-bottom:1px solid #f0f0f0;padding-bottom:10px}.notice-card .notice-content.data-v-845b5869{text-align:left;color:#666;font-size:14px}.waiting.data-v-845b5869{color:#fa0;font-weight:700}
+1
View File
@@ -0,0 +1 @@
"use strict";const e=require("../../common/vendor.js"),o=require("../../config/user.js"),r={data:()=>({orderId:"",orderInfo:{},isLoading:!0,deviceMessage:"正在准备您的设备,请稍候...",hasTriggeredDevice:!1}),onLoad(o){o&&o.orderId?(this.orderId=o.orderId,this.loadOrderInfo(),e.index.$once("orderSuccess:"+this.orderId,(()=>{console.log("已经触发过弹出逻辑,不再重复触发"),this.hasTriggeredDevice=!0}))):(e.index.showToast({title:"订单信息不存在",icon:"none"}),setTimeout((()=>{this.goToHome()}),1500))},methods:{async loadOrderInfo(){try{e.index.showLoading({title:"加载中"});const r=await o.queryById(this.orderId);if(200!==r.code||!r.data)throw new Error("获取订单信息失败");{const o=r.data;this.orderInfo={orderNo:o.orderNo||o.orderId,deviceNo:o.deviceNo,amount:o.payAmount||o.amount,payTime:o.payTime||this.formatTime(new Date)},"IN_USED"===o.orderStatus?(this.deviceMessage="设备已弹出,请取走您的充电宝",this.isLoading=!1,this.hasTriggeredDevice||(e.index.$emit("orderSuccess:"+this.orderId),this.hasTriggeredDevice=!0)):this.triggerDeviceEject()}e.index.hideLoading()}catch(r){e.index.hideLoading(),e.index.showToast({title:r.message||"获取订单信息失败",icon:"none"})}},async triggerDeviceEject(){if(this.hasTriggeredDevice)console.log("已经触发过弹出充电宝,不重复触发");else{this.hasTriggeredDevice=!0,e.index.$emit("orderSuccess:"+this.orderId),this.isLoading=!0,this.deviceMessage="正在准备您的设备,请稍候...";try{console.log(`准备触发弹出充电宝,orderId: ${this.orderId}`);const r=await o.confirmPaymentAndRent(this.orderId);if(console.log("确认支付并弹出充电宝结果:",JSON.stringify(r)),!r||200!==r.code)throw new Error(r&&r.msg||"弹出充电宝失败");this.deviceMessage="设备已弹出,请取走您的充电宝",e.index.showToast({title:"充电宝已弹出",icon:"success"})}catch(r){console.error("弹出充电宝错误:",r),this.deviceMessage="弹出设备失败,请联系客服",e.index.showToast({title:r.message||"弹出充电宝失败,请联系客服",icon:"none"})}finally{this.isLoading=!1}}},formatTime:e=>`${e.getFullYear()}-${(e.getMonth()+1).toString().padStart(2,"0")}-${e.getDate().toString().padStart(2,"0")} ${e.getHours().toString().padStart(2,"0")}:${e.getMinutes().toString().padStart(2,"0")}:${e.getSeconds().toString().padStart(2,"0")}`,goToHome(){e.index.switchTab({url:"/pages/index/index"})},goToOrderList(){e.index.redirectTo({url:"/pages/order/index"})}}};const i=e._export_sfc(r,[["render",function(o,r,i,t,d,s){return e.e({a:e.t(d.orderInfo.orderNo||"-"),b:e.t(d.orderInfo.deviceNo||"-"),c:e.t(d.orderInfo.amount||"0.00"),d:e.t(d.orderInfo.payTime||"-"),e:e.t(d.deviceMessage),f:d.isLoading},(d.isLoading,{}),{g:e.o(((...e)=>s.goToHome&&s.goToHome(...e))),h:e.o(((...e)=>s.goToOrderList&&s.goToOrderList(...e)))})}],["__scopeId","data-v-174f45e8"]]);wx.createPage(i);
@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "支付成功",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="success-container data-v-174f45e8"><view class="status-card data-v-174f45e8"><view class="status-icon success data-v-174f45e8"></view><view class="status-text data-v-174f45e8">支付成功</view><view class="status-desc data-v-174f45e8">您的订单已支付成功</view></view><view class="order-card data-v-174f45e8"><view class="card-title data-v-174f45e8">订单信息</view><view class="info-item data-v-174f45e8"><text class="label data-v-174f45e8">订单号</text><text class="value data-v-174f45e8">{{a}}</text></view><view class="info-item data-v-174f45e8"><text class="label data-v-174f45e8">设备号</text><text class="value data-v-174f45e8">{{b}}</text></view><view class="info-item data-v-174f45e8"><text class="label data-v-174f45e8">支付金额</text><text class="value data-v-174f45e8">¥{{c}}</text></view><view class="info-item data-v-174f45e8"><text class="label data-v-174f45e8">支付时间</text><text class="value data-v-174f45e8">{{d}}</text></view></view><view class="device-status data-v-174f45e8"><view class="status-message data-v-174f45e8">{{e}}</view><view wx:if="{{f}}" class="loading-animation data-v-174f45e8"><view class="loading-circle data-v-174f45e8"></view></view></view><view class="button-group data-v-174f45e8"><button class="primary-btn data-v-174f45e8" bindtap="{{g}}">返回首页</button><button class="secondary-btn data-v-174f45e8" bindtap="{{h}}">查看订单</button></view></view>
@@ -0,0 +1 @@
.success-container.data-v-174f45e8{padding:20px;background-color:#f5f5f5;min-height:100vh}.status-card.data-v-174f45e8{background-color:#fff;border-radius:12px;padding:30px;text-align:center;margin-bottom:20px}.status-card .status-icon.data-v-174f45e8{width:60px;height:60px;margin:0 auto 16px;background-color:#07c160;border-radius:50%;position:relative}.status-card .status-icon.data-v-174f45e8:after{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:30px;height:20px;border:3px solid #fff;border-top:none;border-right:none;transform-origin:center;transform:translate(-50%,-70%) rotate(-45deg)}.status-card .status-text.data-v-174f45e8{font-size:24px;font-weight:700;color:#07c160;margin-bottom:8px}.status-card .status-desc.data-v-174f45e8{font-size:14px;color:#666}.order-card.data-v-174f45e8{background-color:#fff;border-radius:12px;padding:20px;margin-bottom:20px}.order-card .card-title.data-v-174f45e8{font-size:16px;font-weight:700;margin-bottom:16px;color:#333}.order-card .info-item.data-v-174f45e8{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.order-card .info-item .label.data-v-174f45e8{color:#666;font-size:14px}.order-card .info-item .value.data-v-174f45e8{color:#333;font-size:14px}.device-status.data-v-174f45e8{background-color:#fff;border-radius:12px;padding:20px;margin-bottom:20px;text-align:center}.device-status .status-message.data-v-174f45e8{font-size:16px;color:#333;margin-bottom:12px}.device-status .loading-animation.data-v-174f45e8{display:flex;justify-content:center;align-items:center;height:40px}.device-status .loading-animation .loading-circle.data-v-174f45e8{width:30px;height:30px;border-radius:50%;border:3px solid #f0f0f0;border-top-color:#07c160;animation:spin-174f45e8 1s linear infinite}@keyframes spin-174f45e8{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.button-group.data-v-174f45e8{margin-top:30px;display:flex;flex-direction:column;gap:16px}.button-group .primary-btn.data-v-174f45e8{background-color:#07c160;color:#fff;border:none;border-radius:24px;padding:12px;font-size:16px}.button-group .primary-btn.data-v-174f45e8:active{opacity:.8}.button-group .secondary-btn.data-v-174f45e8{background-color:#fff;color:#07c160;border:1px solid #07c160;border-radius:24px;padding:12px;font-size:16px}.button-group .secondary-btn.data-v-174f45e8:active{background-color:#f5f5f5}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "归还设备",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view class="return-container data-v-44a2261b"><view class="order-card data-v-44a2261b"><view class="order-header data-v-44a2261b"><text class="title data-v-44a2261b">{{a}}</text><text class="order-no data-v-44a2261b">订单号:{{b}}</text></view><view class="device-info data-v-44a2261b"><text class="device-name data-v-44a2261b">共享风扇</text><text class="device-id data-v-44a2261b">设备号:{{c}}</text></view><view class="time-info data-v-44a2261b"><view class="time-item data-v-44a2261b"><text class="label data-v-44a2261b">开始时间</text><text class="value data-v-44a2261b">{{d}}</text></view><view class="time-item data-v-44a2261b"><text class="label data-v-44a2261b">已使用时长</text><text class="value highlight data-v-44a2261b">{{e}}</text></view><view class="time-item data-v-44a2261b"><text class="label data-v-44a2261b">当前费用</text><text class="value data-v-44a2261b">¥{{f}}</text></view></view><view wx:if="{{false}}" class="debug-info data-v-44a2261b"><view class="debug-title data-v-44a2261b">调试信息</view><view class="debug-item data-v-44a2261b">原始开始时间: {{g}}</view><view class="debug-item data-v-44a2261b">处理后开始时间: {{h}}</view><view class="debug-item data-v-44a2261b">订单状态: {{i}}</view></view></view><view class="notice-card data-v-44a2261b"><view class="notice-title data-v-44a2261b">归还说明</view><view class="notice-list data-v-44a2261b"><view class="notice-item data-v-44a2261b"><view class="dot data-v-44a2261b"></view><text class="data-v-44a2261b">请确保设备完好无损</text></view><view class="notice-item data-v-44a2261b"><view class="dot data-v-44a2261b"></view><text class="data-v-44a2261b">将充电宝插入原位置或空闲插口</text></view><view class="notice-item data-v-44a2261b"><view class="dot data-v-44a2261b"></view><text class="data-v-44a2261b">系统将自动检测归还并处理退款</text></view><view class="notice-item data-v-44a2261b"><view class="dot data-v-44a2261b"></view><text class="data-v-44a2261b">归还成功后将自动跳转到成功页面</text></view></view></view><view class="bottom-bar data-v-44a2261b"><button class="secondary-btn data-v-44a2261b" bindtap="{{j}}">刷新状态</button><button class="primary-btn data-v-44a2261b" bindtap="{{k}}">返回首页</button></view></view>
@@ -0,0 +1 @@
.return-container.data-v-44a2261b{min-height:100vh;background:#f8f8f8;padding:30rpx 30rpx 180rpx;box-sizing:border-box}.return-container .order-card.data-v-44a2261b{background:#fff;border-radius:24rpx;padding:30rpx;margin-bottom:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.return-container .order-card .order-header.data-v-44a2261b{display:flex;justify-content:space-between;align-items:center;margin-bottom:30rpx}.return-container .order-card .order-header .title.data-v-44a2261b{font-size:32rpx;font-weight:700;color:#333}.return-container .order-card .order-header .order-no.data-v-44a2261b{font-size:24rpx;color:#999}.return-container .order-card .device-info.data-v-44a2261b{margin-bottom:30rpx}.return-container .order-card .device-info .device-name.data-v-44a2261b{font-size:28rpx;color:#333;display:block;margin-bottom:10rpx}.return-container .order-card .device-info .device-id.data-v-44a2261b{font-size:24rpx;color:#666}.return-container .order-card .time-info.data-v-44a2261b{background:#f9f9f9;border-radius:16rpx;padding:20rpx}.return-container .order-card .time-info .time-item.data-v-44a2261b{display:flex;justify-content:space-between;align-items:center;margin-bottom:16rpx}.return-container .order-card .time-info .time-item.data-v-44a2261b:last-child{margin-bottom:0}.return-container .order-card .time-info .time-item .label.data-v-44a2261b{font-size:26rpx;color:#666}.return-container .order-card .time-info .time-item .value.data-v-44a2261b{font-size:26rpx;color:#333}.return-container .order-card .time-info .time-item .value.highlight.data-v-44a2261b{color:#ff6b00;font-weight:700}.return-container .notice-card.data-v-44a2261b{background:#fff;border-radius:24rpx;padding:30rpx;margin-bottom:30rpx;box-shadow:0 4rpx 16rpx rgba(0,0,0,.04)}.return-container .notice-card .notice-title.data-v-44a2261b{font-size:28rpx;font-weight:700;color:#333;margin-bottom:20rpx}.return-container .notice-card .notice-list .notice-item.data-v-44a2261b{display:flex;align-items:flex-start;margin-bottom:16rpx}.return-container .notice-card .notice-list .notice-item.data-v-44a2261b:last-child{margin-bottom:0}.return-container .notice-card .notice-list .notice-item .dot.data-v-44a2261b{width:12rpx;height:12rpx;background:#07c160;border-radius:50%;margin-top:10rpx;margin-right:16rpx;flex-shrink:0}.return-container .notice-card .notice-list .notice-item text.data-v-44a2261b{font-size:26rpx;color:#666;line-height:1.5}.return-container .bottom-bar.data-v-44a2261b{position:fixed;left:0;right:0;bottom:0;padding:30rpx;background:#fff;box-shadow:0 -4rpx 16rpx rgba(0,0,0,.04);z-index:10;display:flex;justify-content:space-between;gap:20rpx}.return-container .bottom-bar .primary-btn.data-v-44a2261b,.return-container .bottom-bar .secondary-btn.data-v-44a2261b{height:88rpx;line-height:88rpx;font-size:32rpx;border-radius:44rpx;text-align:center;flex:1}.return-container .bottom-bar .primary-btn.data-v-44a2261b{background:#07c160;color:#fff}.return-container .bottom-bar .primary-btn.data-v-44a2261b:active{opacity:.8}.return-container .bottom-bar .secondary-btn.data-v-44a2261b{background:#f0f0f0;color:#333}.return-container .bottom-bar .secondary-btn.data-v-44a2261b:active{opacity:.8}
@@ -0,0 +1 @@
"use strict";const e=require("../../../common/vendor.js"),i=require("../../../util/index.js"),o=require("../../../config/user.js"),d={data:()=>({}),async onLoad(d){try{if(e.index.showLoading({title:"加载中..."}),e.index.getStorageSync("token")||await i.wxLogin(),!d.deviceNo)return e.index.hideLoading(),void e.index.showToast({title:"设备编号不能为空",icon:"none"});const n=await o.queryHasOrder(d.deviceNo);e.index.hideLoading(),n.data&&n.data.data&&n.data.data.length>0?e.index.redirectTo({url:`/pages/device/return?deviceNo=${d.deviceNo}`}):e.index.redirectTo({url:`/pages/device/detail?deviceNo=${d.deviceNo}`})}catch(n){e.index.hideLoading(),e.index.showToast({title:"页面加载失败,请重试",icon:"none"}),console.error("bagCheck onLoad error:",n)}},methods:{}};const n=e._export_sfc(d,[["render",function(e,i,o,d,n,t){return{}}]]);wx.createPage(n);
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "共享风扇",
"usingComponents": {}
}
@@ -0,0 +1 @@
<view></view>
+36
View File
@@ -0,0 +1,36 @@
{
"description": "项目配置文件。",
"packOptions": {
"ignore": []
},
"setting": {
"urlCheck": false,
"es6": true,
"postcss": false,
"minified": false,
"newFeature": true,
"bigPackageSizeSupport": true
},
"compileType": "miniprogram",
"libVersion": "",
"appid": "wxe752f45e7f7aa271",
"projectname": "fs",
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"game": {
"current": -1,
"list": []
},
"miniprogram": {
"current": -1,
"list": []
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#1677FF" d="M23.8535534,15.1464466 C24.0488155,15.3417088 24.0488155,15.6582912 23.8535534,15.8535534 L15.8535534,23.8535534 C15.6582912,24.0488155 15.3417088,24.0488155 15.1464466,23.8535534 L0.146446609,8.85355339 C-0.0488155365,8.65829124 -0.0488155365,8.34170876 0.146446609,8.14644661 L8.14644661,0.146446609 C8.34170876,-0.0488155365 8.65829124,-0.0488155365 8.85355339,0.146446609 L23.8535534,15.1464466 Z M17.0355339,17.0355339 L19.0355339,15.0355339 L15.0355339,11.0355339 L13.0355339,13.0355339 L17.0355339,17.0355339 Z M11.0355339,15.0355339 L13.0355339,17.0355339 L9.03553391,21.0355339 L7.03553391,19.0355339 L11.0355339,15.0355339 Z M9.03553391,9.03553391 L11.0355339,11.0355339 L7.03553391,15.0355339 L5.03553391,13.0355339 L9.03553391,9.03553391 Z M3.03553391,11.0355339 L5.03553391,13.0355339 L3.03553391,15.0355339 L1.03553391,13.0355339 L3.03553391,11.0355339 Z M13.0355339,7.03553391 L15.0355339,9.03553391 L11.0355339,13.0355339 L9.03553391,11.0355339 L13.0355339,7.03553391 Z M17.0355339,3.03553391 L19.0355339,5.03553391 L15.0355339,9.03553391 L13.0355339,7.03553391 L17.0355339,3.03553391 Z M21.0355339,7.03553391 L23.0355339,9.03553391 L19.0355339,13.0355339 L17.0355339,11.0355339 L21.0355339,7.03553391 Z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#07C160" d="M9.82727273,24 C9.82727273,24 9.82727273,24 9.82727273,24 L9.82727273,24 C7.41773163,24 4.95318182,23.5318182 4.95318182,23.5318182 C4.95318182,23.5318182 3,23.1136364 1.5,22.2272727 C1.5,22.2272727 0.954545455,22.0863636 1.04318182,21.5454545 C1.13181818,21.0045455 1.36363636,20.25 1.36363636,20.25 L2.25,17.7272727 C0.409090909,16.0227273 0,14.0454545 0,12.8181818 C0,8.45454545 4.90909091,4.90909091 9.82727273,4.90909091 C13.7454545,4.90909091 17.1818182,7.10454545 18.5454545,10.2272727 C19.0909091,10.1318182 19.6363636,10.0909091 20.1818182,10.0909091 C24.5454545,10.0909091 28.0909091,13.1818182 28.0909091,16.9090909 C28.0909091,18.8181818 26.7272727,20.5909091 24.7272727,21.7272727 L25.3636364,23.5909091 C25.3636364,23.5909091 25.5,24.0454545 25.5909091,24.4090909 C25.6818182,24.7727273 25.3636364,24.9545455 25.3636364,24.9545455 C24.2727273,25.6363636 22.7272727,26.0454545 22.7272727,26.0454545 C22.7272727,26.0454545 20.7272727,26.4545455 18.7272727,26.4545455 C16.7272727,26.4545455 14.7272727,26.0454545 14.7272727,26.0454545 C13.6363636,25.7727273 12.5454545,25.4090909 11.5454545,24.9545455 C10.9090909,24.6818182 10.3636364,24.3636364 9.82727273,24 Z M6.13636364,11.3181818 C5.04545455,11.3181818 4.18181818,12.1818182 4.18181818,13.2727273 C4.18181818,14.3636364 5.04545455,15.2272727 6.13636364,15.2272727 C7.22727273,15.2272727 8.09090909,14.3636364 8.09090909,13.2727273 C8.09090909,12.1818182 7.22727273,11.3181818 6.13636364,11.3181818 Z M13.5,11.3181818 C12.4090909,11.3181818 11.5454545,12.1818182 11.5454545,13.2727273 C11.5454545,14.3636364 12.4090909,15.2272727 13.5,15.2272727 C14.5909091,15.2272727 15.4545455,14.3636364 15.4545455,13.2727273 C15.4545455,12.1818182 14.5909091,11.3181818 13.5,11.3181818 Z M20.1818182,16.5 C19.0909091,16.5 18.2272727,17.3636364 18.2272727,18.4545455 C18.2272727,19.5454545 19.0909091,20.4090909 20.1818182,20.4090909 C21.2727273,20.4090909 22.1363636,19.5454545 22.1363636,18.4545455 C22.1363636,17.3636364 21.2727273,16.5 20.1818182,16.5 Z M25.5,16.5 C24.4090909,16.5 23.5454545,17.3636364 23.5454545,18.4545455 C23.5454545,19.5454545 24.4090909,20.4090909 25.5,20.4090909 C26.5909091,20.4090909 27.4545455,19.5454545 27.4545455,18.4545455 C27.4545455,17.3636364 26.5909091,16.5 25.5,16.5 Z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Some files were not shown because too many files have changed in this diff Show More