first commit

This commit is contained in:
PC-202306242200\Administrator
2026-03-31 10:53:43 +08:00
commit f529129c93
770 changed files with 86065 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
unpackage/

20
.hbuilderx/launch.json Normal file
View File

@@ -0,0 +1,20 @@
{ // launch.json 配置了启动调试时相关设置configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtype项可配置值为local或remote, local代表前端连本地云函数remote代表前端连云端云函数
"version": "0.0",
"configurations": [{
"app-plus" :
{
"launchtype" : "local"
},
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]
}

5
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/云充电.iml" filepath="$PROJECT_DIR$/.idea/云充电.iml" />
</modules>
</component>
</project>

12
.idea/云充电.iml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

25
App.vue Normal file
View File

@@ -0,0 +1,25 @@
<script>
import { login } from '@/common/js/user.js';
import { init } from '@/utils/sok.js';
export default {
onLaunch: function () {
// login()
if(uni.getStorageSync('token')){
init()
}
console.log('App Launch');
},
onShow: function () {
console.log('App Show');
},
onHide: function () {
console.log('App Hide');
}
};
</script>
<style lang="scss">
/*每个页面公共css */
@import '@/uni_modules/uview-plus/index.scss';
@import '@/common/index.scss';
</style>

150
api/api.js Normal file
View File

@@ -0,0 +1,150 @@
import {
http
} from '@/request/index.js'
// 登录
export const loginApi = (params, config = {}) => http('/api/v0/login/loginByWx', params)
export const loginCodeApi = (params, config = {}) => http('/api/v0/login/loginByWxCode', params)
export const loginByZfbCode = (params, config = {}) => http('/api/v0/login/loginByZfbCode', params)
// 首页
// 获取附近站点
export const aroundAreaApi = (params, config = {}) => http('/api/v0/stations/aroundArea', params, 'GET')
export const infoAroundApi = (params, config = {}) => http('/api/v0/stations/info', params, 'GET')
export const listByStationId = (params, config = {}) => http('/api/v0/device/gun/listByStationId', params, 'GET')
// 开始充电
export const startCharging = (params, config = {}) => http('/api/v0/orders/startCharging', params)
//获取电枪详情
export const gunInfo = (params, config = {}) => http('/api/v0/device/gun/info', params, 'GET')
//用户信息
export const userInfo = (params, config = {}) => http('/api/v0/user/info', params, 'GET')
//订单
export const ordersList = (params, config = {}) => http('/api/v0/orders/list', params, 'GET')
// 开始充电-钱包
export const startChargingByWallet = (params, config = {}) => http('/api/v0/orders/startChargingByWallet', params)
// 开始充电-电卡
export const startChargingByCard = (params, config = {}) => http('/api/v0/orders/startChargingByCard', params)
// 开始充电-预付款-上海汇付
export const startChargingByAdaPay = (params, config = {}) => http('/api/v0/orders/startChargingByAdaPay', params)
// 结束停止充电
export const stopCharging = (params, config = {}) => http('/api/v0/orders/stopCharging', params)
// 轮播图
export const bannerList = (params, config = {}) => http('/api/v0/banner/list', params, 'GET')
// 修改用户昵称
export const updateNickName = (params, config = {}) => http('/api/v0/user/updateNickName', params)
// 修改用户头像
export const updateAvatar = (params, config = {}) => http('/api/v0/user/updateAvatar', params)
// 获取OSS
export const getOssUploadParams = (params, config = {}) => http('/api/v0/user/getOssUploadParams', params, 'GET')
// 实时充电详情
export const realtimeInfo = (params, config = {}) => http('/api/v0/orders/realtimeInfo', params, 'GET')
// 钱包记录
export const walletRecord = (params, config = {}) => http('/api/v0/wallet/record', params, 'GET')
export const userCardList = (params, config = {}) => http('/api/v0/card/userCardList', params, 'GET')
export const userCardRecord = (params, config = {}) => http('/api/v0/card/userCardRecord', params, 'GET')
// 充值
export const jqbPay = (params, config = {}) => http('/api/v0/wallet/charge/jqbPay', params)
// 汇付
export const adaPay = (params, config = {}) => http('/api/v0/wallet/charge/adaPay', params)
// 地图获取附近站点
export const aroundAreaMap = (params, config = {}) => http('/api/v0/stations/aroundAreaMap', params, 'GET')
// 协议详情获取
export const selectProtocolInfo = (params, config = {}) => http('/api/v0/protocol/info', params, 'GET')
//发票列表
export const invoiceList = (params, config = {}) => http('/api/v0/invoice/list', params, 'GET')
// 可开发票列表
export const orderList = (params, config = {}) => http('/api/v0/invoice/orderList', params, 'GET')
// 申请开具发票列表
export const preApply = (params, config = {}) => http('/api/v0/invoice/preApply', params)
// 申请开具发票请求
export const apply = (params, config = {}) => http('/api/v0/invoice/apply', params)
// 查询可用电卡
export const userCardUsableList = (params, config = {}) => http('/api/v0/card/userCardUsableList', params, 'GET')
// 退款
export const refund = (params, config = {}) => http('/api/v0/wallet/refund', params)
// 订单详情
export const ordersInfo = (params, config = {}) => http('/api/v0/orders/info', params, 'GET')
export const findSignInRecord = (params, config = {}) => http('/api/v0/user/findSignInRecord', params, 'GET')
export const signIn = (params, config = {}) => http('/api/v0/user/signIn')
export const getMerchantSelect = (params, config = {}) => http('/user/article/getMerchantSelect', params, 'POST')
export const articleAdd = (params, config = {}) => http('/user/article/add', params, 'POST')
// 文章编辑
export const articleUpdate = (params, config = {}) => http('/user/article/update', params,'POST')
// 文章详情
export const articleDetails = (params, config = {}) => http('/user/article/details', params,'GET')
// 删除文章
export const articleDelete = (params, config = {}) => http('/user/article/deleteBatchByIds', params,'POST')
// 获取用户新闻列表
export const getUserArticleList = (params, config = {}) => http('/user/article/getUserArticleList', params,'GET')
export const carAdd = (params, config = {}) => http('/user/car/add', params, 'POST')
export const carList = (params, config = {}) => http('/user/car/list', params, 'POST')
export const carDel = (params, config = {}) => http(`/user/car/deleteById?id=${params}`, params, 'DELETE')
export const shareMiniProgram = (params, config = {}) => http('/api/v0/user/fenxiangGetPoint', params,'POST')
// =========================
// 投资者平台
// =========================
// 商品列表
export const goodsList = (params, config = {}) => http('/user/goods/list', params, 'GET')
export const categoryList = (params, config = {}) => http('/user/goods/categoryList', params, 'GET')
export const shopInfo = (params, config = {}) => http('/user/goods/details', params, 'GET')
export const addGoodsOrders = (params, config = {}) => http('/api/invest/orders/submit', params)
export const orderPage = (params, config = {}) => http('/api/invest/orders/list', params, 'GET')
export const payAllinPay = (params, config = {}) => http('/api/v0/payment/order/pay/allinPay', params)
export const payMoney = (params, config = {}) => http('/api/v0/payment/order/pay/money', params)
export const handleSubmit = (params, config = {}) => http('/api/invest/orders/handleSubmit', params)
export const getDeviceInfo = (params, config = {}) => http('/invest/user/device/query/user/deviceInfo', params, 'GET')
export const addUsersAccountInfo = (params, config = {}) => http('/api/v0/extract/account/add', params)
export const getUsersAccountInfo = (params, config = {}) => http('/api/v0/extract/account/list', params, 'GET')
// 用户提现
export const pointsExtract = (params, config = {}) => http('/api/v0/extract/pointsExtract', params,'POST')
// 提现列表
export const extractList = (params, config = {}) => http('/api/v0/extract/list', params,'GET')
// 用户收益记录
export const extractRecordList = (params, config = {}) => http('/api/v0/extract/recordList', params,'GET')
// 配置列表
export const getAppConfig = (params, config = {}) => http('/api/v0/config/list', params,'GET')
export const loginByPassword = (params, config = {}) => http('/api/v0/invest/user/loginByPassword', params)
export const saveOpenIdByWxCode = (params, config = {}) => http('/api/v0/invest/user/saveOpenIdByWxCode', params)
export const registerApi = (params, config = {}) => http('/api/v0/invest/user/register', params)
export const findUserName = (params, config = {}) => http('/api/v0/invest/user/findUserName', params)
export const findPassword = (params, config = {}) => http('/api/v0/invest/user/findPassword', params)
export const smsCode = (params, config = {}) => http('/api/v0/invest/user/sendSmsCode', params)
export const userInfoIsInvest = (params, config = {}) => http('/api/v0/invest/user/info', params, 'GET')
export const rechargeAllinPay = (params, config = {}) => http('/api/v0/payment/money/recharge/allinPay', params)
export const investUserModify = (params, config = {}) => http('/api/v0/invest/user/modify', params, 'POST')

21
common/index.scss Normal file
View File

@@ -0,0 +1,21 @@
view {
box-sizing: border-box;
}
page {
background: #f7f7f7;
}
.p30 {
padding: 0 30rpx;
}
.mt10 {
margin-bottom: 10rpx;
}
.flex-acsb {
display: flex;
align-items: center;
justify-content: space-between;
}
.flex1 {
flex: 1;
}

122
common/js/user.js Normal file
View File

@@ -0,0 +1,122 @@
import {
loginApi,
loginCodeApi,
loginByZfbCode
} from "@/api/api.js"
import {
init
} from '@/utils/sok.js';
export const login = async (params, type = 1) => {
if (type == 1) {
var {
code: loginCode
} = await uni.login({
provider: 'weixin'
});
try {
let {
token,
userInfo
} = await loginCodeApi({
loginCode
})
uni.setStorageSync('token', token);
uni.setStorageSync('user', userInfo);
uni.setStorageSync('isInvest', false);
} catch (err) {
if (err.code == 10) {
uni.setStorageSync('token', false);
}
}
} else if (type == 2) {
var {
code: phoneCode
} = params.detail;
var {
code: loginCode
} = await uni.login({
provider: 'alipay'
});
try {
// #ifdef MP-WEIXIN
let {
token,
user
} = await loginApi({
phoneCode,
loginCode
});
// #endif
// #ifdef MP-ALIPAY
let {
token,
user
} = await loginByZfbCode({
phoneCode,
loginCode
});
// #endif
uni.setStorageSync('token', token);
uni.setStorageSync('user', user);
uni.setStorageSync('isInvest', false);
uni.reLaunch({
url: '/pages/home/home'
});
// uni.navigateBack()
// uni.navigateBack()
init()
} catch (err) {
console.log(err);
}
}
}
const download = (e, type) => {
const base64 = uni.arrayBufferToBase64(e.data);
const fs = wx.getFileSystemManager()
var imgPath = ''11
if (type == 'video') {
imgPath = wx.env.USER_DATA_PATH + '/base64Video' + '.mp4' //自定义下载图片的名称
} else {
imgPath = wx.env.USER_DATA_PATH + '/base64img' + '.png' //自定义下载图片的名称
}
fs.writeFile({
filePath: imgPath, //设置下载图片的地址
data: base64, //slice(22)的目的是去掉data:image/png;base64,如果本身就不带的话就直接this.data.codeImg就好了
encoding: 'base64',
success: function(res) {
//读取文件
wx.getImageInfo({
src: imgPath,
success: function(ret) {
console.log("请求到了");
var path = ret.path;
wx.saveImageToPhotosAlbum({
filePath: imgPath, //设置下载图片的地址
success(result) {
console.log("保存成功"); //保存成功
}
})
}
})
// console.log(res);
// console.log("请求到了");
// wx.saveImageToPhotosAlbum({
// filePath: imgPath, //设置下载图片的地址
// success: function() {
// console.log("保存成功"); //保存成功
// }
// })
}
})
}

105
common/money.json Normal file
View File

@@ -0,0 +1,105 @@
[{
"name": "充值",
"id": 1100
},
{
"name": "后台充值",
"id": 1200
},
{
"name": "后台划扣",
"id": 1201
},
{
"name": "购买商品",
"id": 2100
},
{
"name": "商品推广",
"id": 2110
},
{
"name": "商品培育津贴",
"id": 2120
},
{
"name": "商品服务津贴",
"id": 2130
},
{
"name": "购买商品-退单",
"id": 2200
},
{
"name": "商品推广-退单",
"id": 2210
},
{
"name": "商品培育津贴-退单",
"id": 2220
},
{
"name": "商品服务津贴-退单",
"id": 2230
},
{
"name": "充电桩收益",
"id": 3100
},
{
"name": "充电桩推广",
"id": 3110
},
{
"name": "充电桩培育津贴",
"id": 3120
},
{
"name": "充电桩服务津贴",
"id": 3130
},
{
"name": "充电桩收益-退单",
"id": 3200
},
{
"name": "充电桩推广-退单",
"id": 3210
},
{
"name": "充电桩培育津贴-退单",
"id": 3220
},
{
"name": "充电桩服务津贴-退单",
"id": 3230
},
{
"name": "提现",
"id": 4100
},
{
"name": "提现失败",
"id": 4200
},
{
"name": "转赠付款",
"id": 5100
},
{
"name": "转赠收款",
"id": 5200
},
{
"name": "转换减少",
"id": 6100
},
{
"name": "转换增加",
"id": 6200
},
{
"name": "转账-星梦",
"id": 7100
}
]

BIN
components/.DS_Store vendored Normal file

Binary file not shown.

BIN
components/orange-user/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,85 @@
<template>
<view :class="Fixed ? 'Fixed' : ''">
<view :style="{ height: statusBarHeight }" v-if="top"></view>
<view style="height: 44px" v-if="top"></view>
<view class="search">
<!-- <view class="search_left" :class="Fixed ? 'opacityLeft' : ''">
<image class="search_left_img" src="/static/icon/xai.png" mode="widthFix"></image>
<view>郑州市</view>
</view> -->
<view class="search_right p30">
<up-input placeholder="查找地点、电站" confirmType="search" suffixIcon="/static/icon/search.png" border="none" v-model="value" @change="change" @confirm="confirm"></up-input>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
let value = ref('');
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
const emits = defineEmits(['change', 'search']);
const data = defineProps({
Fixed: {
type: Boolean,
default: false
},
top: {
type: Boolean,
default: true
}
});
let change = (e) => {
emits('change', e);
};
let confirm = (e) => {
emits('search', e);
};
</script>
<style lang="scss">
.Fixed {
position: fixed;
left: 0;
width: 100%;
padding: 0 30rpx;
z-index: 99;
}
.search {
@include flex($space: space-between);
&_left {
@include flex;
font-weight: bold;
font-size: 40rpx;
color: #232323;
height: 86rpx;
&_img {
width: 36rpx;
height: 36rpx;
margin-right: 15rpx;
}
}
.opacityLeft {
background: rgba(255, 255, 255, 0.27);
border-radius: 10rpx 10rpx 10rpx 10rpx;
padding: 0 10rpx;
}
&_right {
flex: 1;
@include flex;
// max-width: 500rpx;
height: 86rpx;
background: #ffffff;
box-shadow: inset 0rpx 0rpx 22rpx 2rpx #f9fbff;
border-radius: 20rpx 20rpx 20rpx 20rpx;
}
}
</style>

View File

@@ -0,0 +1,83 @@
<template>
<view class="slide-filter-container">
<view class="progress-bar-bg">
<view class="progress-bar-length" :style="{width: `${(scaleIndex / (option?.length - 1) * 100)}%`}"></view>
<view class="scale-area">
<view
class="scale-area-item"
v-for="(item, index) in option"
:class="{'scale-area-item-active': index == scaleIndex}"
@click="clickScale(item, index)"
>
{{ item }}
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive, defineProps, defineEmits } from 'vue';
const props = defineProps({
option: { type: Array, default: () => [] },
modelValue: { type: Number, default: "" },
});
const emit = defineEmits(['update:modelValue', 'change']);
const scaleIndex = ref(0);
const clickScale = (item, index) => {
scaleIndex.value = index;
emit("update:modelValue", item)
emit("change")
}
</script>
<style lang="scss" scoped>
.slide-filter-container {
width: 100%;
.progress-bar-bg {
height: 20rpx;
background: #EEEEEE;
position: relative;
border-radius: 4rpx;
.progress-bar-length {
width: 50%;
height: 100%;
background: #6FA256;
border-radius: 4rpx 0 0 4rpx;
position: relative;
}
.progress-bar-length::after {
content: '';
position: absolute;
width: 2rpx;
height: 26rpx;
right: -2rpx;
top: -3rpx;
background: #6FA256;
}
.scale-area {
position: absolute;
height: 46rpx;
top: 0;
left: 0;
font-weight: bold;
font-size: 20rpx;
color: #232323;
display: flex;
justify-content: space-between;
width: 100%;
&-item {
padding-top: 26rpx;
width: 20rpx;
text-align: center;
}
&-item-active {
color: #6FA256;
}
}
}
}
</style>

BIN
components/static/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,30 @@
<template>
<view style="position: relative">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px"></view>
<view class="statusBar_blur"></view>
</view>
</template>
<script setup>
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
</script>
<style lang="scss">
.statusBar_blur {
width: 100%;
height: 185rpx;
position: absolute;
top: 0;
left: 0;
background: #dbe6ff;
opacity: 0.8;
filter: blur(50px);
/* #ifdef MP-ALIPAY */
z-index: 0;
/* #endif */
/* #ifdef MP-WEIXIN */
z-index: -1;
/* #endif */
}
</style>

10
config.js Normal file
View File

@@ -0,0 +1,10 @@
export default {
// baseUrl: 'http://192.168.1.63:1017',
baseUrl: 'https://dianxr.com',
sok: 'dianxr.com',
// sok: '192.168.1.63:1017',
// baseUrl: 'http://192.168.1.63:1017',
isInvest: true
}

73
hooks/useNav.js Normal file
View File

@@ -0,0 +1,73 @@
import {
ref,
watch
} from 'vue';
export function useNav() {
const nav = (e) => {
if (e.call) {
uni.makePhoneCall({
phoneNumber: '4008005326' //仅为示例
});
return
}
if (!uni.getStorageSync('token')) {
uni.showModal({
title: '提示',
content: '为提供更好的服务,请前往登录',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/login/login'
})
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
return
}
uni[e.type == 'nav' || !e.type ? 'navigateTo' : e.type == 'switchTab' ? 'switchTab' : 'navigateTo']({
url: e.path
})
}
const relTo = (path, token, call) => {
uni.reLaunch({
url: path
})
}
const navTo = (path, token, call) => {
// if (!uni.getStorageSync('token')) {
// uni.showModal({
// title: '提示',
// content: '为提供更好的服务,请前往登录',
// success: (res) => {
// if (res.confirm) {
// uni.navigateTo({
// url: '/pages/login/login'
// })
// } else if (res.cancel) {
// console.log('用户点击取消');
// }
// }
// })
// return
// }
uni.navigateTo({
url: path
})
}
return {
nav,
navTo,
relTo
}
}
export default useNav

127
hooks/userInfo.js Normal file
View File

@@ -0,0 +1,127 @@
import {
userInfo,
userInfoIsInvest
} from '@/api/api.js';
import config from '@/config'
import {
onShow,
onLoad
} from '@dcloudio/uni-app';
import {
reactive,
ref,
onMounted
} from 'vue';
export function userHook() {
const user = reactive({});
const isInvest = ref(false)
const tabbar = ref([])
const fetchUserData = async () => {
if (!uni.getStorageSync('token')) {
return
}
try {
const data = isInvest.value ? await userInfoIsInvest() : await userInfo();
Object.assign(user, data);
} catch (error) {
console.log(error);
}
};
const tabbarData = async () => {
// let isInvest = uni.getStorageSync('isInvest') || false;
tabbar.value = isInvest.value ? [{
index: 0,
name: '首页',
img: '/static/tabbar/select_home.png',
acImg: '/static/tabbar/home.png'
},
{
index: 1,
name: '订单',
img: '/static/tabbar/orderIs1.png',
acImg: '/static/tabbar/orderIs.png'
},
{
index: 2,
name: '充电桩',
img: '/static/tabbar/cds.png',
acImg: '/static/tabbar/cd.png'
},
{
index: 3,
name: '我的',
img: '/static/tabbar/select_my.png',
acImg: '/static/tabbar/my.png'
}
] : [{
index: 0,
name: '首页',
img: '/static/tabbar/select_home.png',
acImg: '/static/tabbar/home.png'
},
{
index: 1,
name: '地图',
img: '/static/tabbar/select_sq.png',
acImg: '/static/tabbar/sq.png'
},
{
index: 2,
name: '扫一扫',
img: '/static/tabbar/find.png',
acImg: '/static/tabbar/find.png',
type: 'big'
},
{
index: 3,
name: '发现',
img: '/static/tabbar/select_order.png',
acImg: '/static/tabbar/order.png'
},
{
index: 4,
name: '我的',
img: '/static/tabbar/select_my.png',
acImg: '/static/tabbar/my.png'
}
];
};
// onMounted(() => {
// console.log('onMounted-Hook');
// tabbarData()
// })
onLoad(() => {
console.log('onLoad-Hook');
isInvest.value = uni.getStorageSync('isInvest');
if (isInvest.value === '') {
isInvest.value = config.isInvest;
}
tabbarData()
})
onShow(async () => {
console.log('onShow Hook');
isInvest.value = uni.getStorageSync('isInvest');
if (isInvest.value === '') {
isInvest.value = config.isInvest;
}
await fetchUserData();
});
return {
user,
isInvest,
fetchUserData,
tabbar
};
}

20
index.html Normal file
View File

@@ -0,0 +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>

34
main.js Normal file
View File

@@ -0,0 +1,34 @@
import App from './App'
import store from './store/index.js'
import uviewPlus from '@/uni_modules/uview-plus'
// 引入uview-plus对小程序分享的mixin封装
import mpShare from '@/uni_modules/uview-plus/libs/mixin/mpShare'
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
export function createApp() {
const app = createSSRApp(App)
app.mixin(mpShare)
app.use(uviewPlus)
app.use(store)
return {
app,
}
}
// #endif

79
manifest.json Normal file
View File

@@ -0,0 +1,79 @@
{
"name" : "电小芮",
"appid" : "__UNI__334883D",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx9c307554d0e5edb0",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于小程序位置接口的效果展示"
}
},
"requiredPrivateInfos" : [ "getLocation" ]
},
"mp-alipay" : {
"usingComponents" : true,
"appid" : "2021004150609395"
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3"
}

17
package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"id": "itsse-20230104",
"name": "顶部导航栏滚动渐变",
"displayName": "顶部导航栏滚动渐变",
"version": "1.0",
"description": "顶部导航栏滚动渐变适用于微信小程序其他小程序APP没有测试过",
"keywords": [
"滚动渐变",
"导航栏滚动渐变"
],
"dcloudext": {
"category": [
"前端组件",
"通用组件"
]
}
}

View File

@@ -0,0 +1,213 @@
<template>
<view class="p30 piles">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view class="piles_card">
<view class="piles_card_title">充电桩汇总</view>
<view class="piles_card_view">
<view>
<text>{{ count.installCount || 0 }}</text>
<text>已安装</text>
</view>
<view>
<text>{{ count.installNotCount || 0 }}</text>
<text>未安装数量</text>
</view>
<view>
<text>0</text>
<text>团队</text>
</view>
</view>
</view>
<up-subsection :list="list" keyName="name" :current="current" @change="upChange"></up-subsection>
<view class="order_view" v-for="i in dataList" :key="i">
<view class="piles_list" v-if="current == 0">
<view class="piles_list_title">安装电站{{ i.stationName || '-' }}</view>
<view class="piles_list_view">
<view>设备ID</view>
<view>{{ i.id }}</view>
</view>
<view class="piles_list_view">
<view>设备功率</view>
<view>{{ i.deviceType }}KW</view>
</view>
<view class="piles_list_view" v-if="i.purposeType">
<view>设备类型</view>
<view>{{ i.purposeType == 1 ? '商用运维版' : i.purposeType == 2 ? '商用合作版' : i.purposeType == 3 ? '家用专业版' : '' }}</view>
</view>
<view class="piles_list_view">地址{{ i.stationAddress || '-' }}</view>
<!-- <view class="piles_list_view">
<view>电费费用</view>
<view>
<text>1.00</text>
/
</view>
</view>
<view class="piles_list_view">
<view>昨日收益</view>
<view>
<text>100.00 </text>
</view>
</view> -->
<view class="piles_list_view">
<view>下单时间</view>
<view>{{ timeFormat(new Date(i.createTime).getTime(), 'yyyy-mm-dd hh:MM') }}</view>
</view>
</view>
<view class="piles_list" v-if="current == 1">
<view class="piles_list_view">
<view>设备ID</view>
<view>{{ i.id }}</view>
</view>
<view class="piles_list_view">
<view>设备功率</view>
<view>{{ i.deviceType }}KW</view>
</view>
<view class="piles_list_view" v-if="i.purposeType">
<view>设备类型</view>
<view>{{ i.purposeType == 1 ? '商用运维版' : i.purposeType == 2 ? '商用合作版' : i.purposeType == 3 ? '家用专业版' : '' }}</view>
</view>
<view class="piles_list_view">
<view>下单时间</view>
<view>{{ timeFormat(new Date(i.createTime).getTime(), 'yyyy-mm-dd hh:MM') }}</view>
</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
// import { getDeviceInfo, getDeviceCount } from '@/api/api.js';
import { reactive, ref } from 'vue';
import { onPullDownRefresh, onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app';
import { timeFormat } from '@/uni_modules/uview-plus';
const paging = ref(null);
let dataList = ref([]);
let dataFrom = reactive({
deviceStatus: 1
});
let count = ref({});
onLoad(async () => {
count.value = await getDeviceCount();
});
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize,
...dataFrom
};
getDeviceInfo(params)
.then((res) => {
paging.value.complete(res.records);
})
.catch((res) => {
paging.value.complete(false);
});
};
const list = ref([
{
name: '已安装',
id: 1
},
{
name: '待安装',
id: 0
}
]);
const current = ref(0);
const upChange = (e) => {
current.value = e;
dataFrom.deviceStatus = list.value[e].id;
paging.value.reload();
};
</script>
<style scoped lang="scss">
.piles {
&_card {
width: 690rpx;
height: 192rpx;
background: linear-gradient(179deg, #4874e5 0%, #3864d6 100%);
border-radius: 8rpx 8rpx 0rpx 0rpx;
padding: 30rpx;
&_title {
font-weight: bold;
font-size: 28rpx;
color: #ffffff;
margin-bottom: 20rpx;
}
&_view {
padding: 0 150rpx;
flex-direction: column;
@include flex($space: space-between);
view {
@include flex($direction: column, $space: space-between);
text:nth-child(1) {
font-weight: bold;
font-size: 32rpx;
color: #ffffff;
margin-bottom: 15rpx;
}
text:nth-child(2) {
font-size: 26rpx;
color: #ffffff;
}
}
}
}
&_list {
padding: 25rpx;
width: 690rpx;
background: #ffffff;
border-radius: 16rpx 16rpx 16rpx 16rpx;
margin-top: 30rpx;
&_title {
font-weight: bold;
font-size: 28rpx;
color: #232323;
}
&_view {
@include flex;
color: #555555;
font-size: 28rpx;
margin-top: 15rpx;
view:nth-child(2) {
font-weight: bold;
font-size: 28rpx;
color: #232323;
}
text {
color: #ff2727;
}
}
}
}
</style>

View File

@@ -0,0 +1,152 @@
<template>
<view class="login">
<view class="orderdetail_header p30">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px; display: flex; align-items: center">
<up-icon name="arrow-left" bold color="#000" @click="back"></up-icon>
</view>
</view>
<image class="login_bei" src="/static/logoB.png"></image>
<statusBar />
<view class="login_logo">
<image class="login_logo_img" src="/static/logo.png"></image>
<view class="login_logo_tit">欢迎来到投资者平台</view>
</view>
<view style="margin-top: 150rpx">
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.userName" placeholder="请输入您的用户名" border="bottom" clearable></up-input>
</view>
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.passwd" type="password" placeholder="请输入您的密码" border="bottom" clearable></up-input>
</view>
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.confirmPasswd" type="password" placeholder="请再次输入您的密码" border="bottom" clearable></up-input>
</view>
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.phone" placeholder="请输入您的手机号" border="bottom" clearable></up-input>
</view>
<view style="margin-bottom: 30rpx; display: flex; align-items: center">
<up-input fontSize="30rpx" v-model="dataFrom.smsCode" placeholder="请输入验证码" border="bottom" clearable></up-input>
<up-code ref="uCode" @change="codeChange2" keep-running start-text="点我获取验证码"></up-code>
<text @click="getCode2" :text="tips" style="font-size: 28rpx; color: rgba(111, 162, 86, 1)">{{ tips }}</text>
</view>
</view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="login_btn" @click="submit">确认</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { findPassword, smsCode } from '@/api/api.js';
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
let tips = ref('');
let uCode = ref(null);
let dataFrom = reactive({
userName: '',
passwd: '',
phone: '',
smsCode: '',
confirmPasswd:""
});
let toLogin = () => {
uni.navigateBack();
};
let codeChange2 = (text) => {
tips.value = text;
};
let getCode2 = () => {
if (!dataFrom.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (uCode.value.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: '正在获取验证码'
});
smsCode({
phone: dataFrom.phone
}).then((res) => {
uni.hideLoading();
uni.$u.toast('验证码已发送');
uCode.value.start();
});
} else {
uni.$u.toast('倒计时结束后再发送');
}
};
let submit = async () => {
if (!dataFrom.userName) return uni.showToast({ title: '请输入用户名', icon: 'none' });
if (!dataFrom.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (dataFrom.phone.length != 11) return uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
if (!dataFrom.smsCode) return uni.showToast({ title: '请输入验证码', icon: 'none' });
if (!dataFrom.passwd) return uni.showToast({ title: '请输入密码', icon: 'none' });
if (!dataFrom.confirmPasswd) return uni.showToast({ title: '请再次输入密码', icon: 'none' });
if (dataFrom.passwd != dataFrom.confirmPasswd) return uni.showToast({ title: '两次密码输入不一致', icon: 'none' });
let _res = await findPassword(dataFrom);
uni.showToast({ title: '修改成功', icon: 'none' });
setTimeout(() => {
uni.navigateBack();
}, 200);
};
let back = () => {
uni.navigateBack();
};
</script>
<style scoped lang="scss">
.login {
padding: 0 60rpx;
&_bei {
position: fixed;
right: -120rpx;
top: -206rpx;
width: 728rpx;
height: 728rpx;
}
&_logo {
margin-top: 150rpx;
&_img {
width: 280rpx;
height: 200rpx;
// background: #e6e6e6;
// box-shadow: 0rpx 0rpx 110rpx 2rpx rgba(115, 192, 76, 0.19);
border-radius: 28rpx 28rpx 28rpx 28rpx;
margin-bottom: 20rpx;
}
&_tit {
font-weight: bold;
font-size: 44rpx;
color: #232323;
}
}
&_btn {
width: 474rpx;
height: 78rpx;
background: rgba(111, 162, 86, 1);
border-radius: 54rpx 54rpx 54rpx 54rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 30rpx;
color: #ffffff;
}
}
.orderdetail_header {
width: 750rpx;
position: fixed;
left: 0;
top: 0;
z-index: 99;
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<view class="login">
<view class="orderdetail_header p30">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px; display: flex; align-items: center">
<up-icon name="arrow-left" bold color="#000" @click="back"></up-icon>
</view>
</view>
<image class="login_bei" src="/static/logoB.png"></image>
<statusBar />
<view class="login_logo">
<image class="login_logo_img" src="/static/logo.png"></image>
<view class="login_logo_tit">欢迎来到投资者平台</view>
</view>
<view style="margin-top: 150rpx">
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.phone" placeholder="请输入您的手机号" border="bottom" clearable></up-input>
</view>
<view style="margin-bottom: 30rpx; display: flex; align-items: center">
<up-input fontSize="30rpx" v-model="dataFrom.smsCode" placeholder="请输入验证码" border="bottom" clearable></up-input>
<up-code ref="uCode" @change="codeChange2" keep-running start-text="点我获取验证码"></up-code>
<text @click="getCode2" :text="tips" style="font-size: 28rpx; color: rgba(111, 162, 86, 1)">{{ tips }}</text>
</view>
</view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="login_btn" @click="submit">确认</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { findUserName, smsCode } from '@/api/api.js';
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
let tips = ref('');
let uCode = ref(null);
let dataFrom = reactive({
phone: '',
smsCode: '',
});
let toLogin = () => {
uni.navigateBack();
};
let codeChange2 = (text) => {
tips.value = text;
};
let getCode2 = () => {
if (!dataFrom.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (uCode.value.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: '正在获取验证码'
});
smsCode({
phone: dataFrom.phone
}).then((res) => {
uni.hideLoading();
uni.$u.toast('验证码已发送');
uCode.value.start();
});
} else {
uni.$u.toast('倒计时结束后再发送');
}
};
let submit = async () => {
if (!dataFrom.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (dataFrom.phone.length != 11) return uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
if (!dataFrom.smsCode) return uni.showToast({ title: '请输入验证码', icon: 'none' });
let _res = await findUserName(dataFrom);
if (_res.userNames.length == 0) {
uni.showModal({
title: '提示',
content: '该手机号还未注册',
showCancel: false,
confirmText: "我知道了"
})
} else {
uni.showModal({
title: '已找回的用户名',
content: _res.userNames.join(','),
showCancel: false,
confirmText: "确认",
success: () => {
uni.setClipboardData({
data: _res.userNames.join(','), //要被复制的内容
success: () => { //复制成功的回调函数
uni.showToast({ //提示
title: '已复制用户名'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
});
}
})
}
};
let back = () => {
uni.navigateBack();
};
</script>
<style scoped lang="scss">
.login {
padding: 0 60rpx;
&_bei {
position: fixed;
right: -120rpx;
top: -206rpx;
width: 728rpx;
height: 728rpx;
}
&_logo {
margin-top: 150rpx;
&_img {
width: 280rpx;
height: 200rpx;
// background: #e6e6e6;
// box-shadow: 0rpx 0rpx 110rpx 2rpx rgba(115, 192, 76, 0.19);
border-radius: 28rpx 28rpx 28rpx 28rpx;
margin-bottom: 20rpx;
}
&_tit {
font-weight: bold;
font-size: 44rpx;
color: #232323;
}
}
&_btn {
width: 474rpx;
height: 78rpx;
background: rgba(111, 162, 86, 1);
border-radius: 54rpx 54rpx 54rpx 54rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 30rpx;
color: #ffffff;
}
}
.orderdetail_header {
width: 750rpx;
position: fixed;
left: 0;
top: 0;
z-index: 99;
}
</style>

178
pageInvest/login/login.vue Normal file
View File

@@ -0,0 +1,178 @@
<template>
<view class="login">
<view class="orderdetail_header p30">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px; display: flex; align-items: center">
<up-icon name="arrow-left" bold color="#000" @click="back"></up-icon>
</view>
</view>
<image class="login_bei" src="/static/logoB.png"></image>
<statusBar />
<view class="login_logo">
<image class="login_logo_img" src="/static/logo.png"></image>
<view class="login_logo_tit">欢迎来到投资者平台</view>
</view>
<view style="margin-top: 150rpx">
<view style="margin-bottom: 50rpx">
<up-input fontSize="30rpx" v-model="dataFrom.userName" placeholder="请输入您的用户名" border="bottom" clearable></up-input>
</view>
<view>
<up-input fontSize="30rpx" v-model="dataFrom.passwd" type="password" placeholder="请输入您的密码" border="bottom" clearable></up-input>
</view>
<!-- <view style="display: flex; align-items: center">
<up-input fontSize="30rpx" v-model="dataFrom.captcha" placeholder="请输入验证码" border="bottom" clearable></up-input>
<image @click="getCaptcha" :src="captchaImg" style="width: 154rpx; height: 66rpx"></image>
</view> -->
</view>
<view style="font-size: 28rpx; color: #666; margin-top: 20rpx; display: flex; align-items: center; justify-content: space-between">
<view>
忘记账号
<text style="color: rgba(111, 162, 86, 1)" @click="getBackAccout">找回用户名</text>
</view>
<view>
<text style="color: rgba(111, 162, 86, 1)" @click="toGetBack">忘记密码</text>
</view>
</view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="login_btn" @click="login">登录</view>
</view>
<view style="display: flex; justify-content: center; margin-top: 40rpx; opacity: 0.5">
<view class="login_btn" @click="toRegister">还没有账号立即注册</view>
</view>
<!-- <view style="display: flex; justify-content: center; margin-top: 20rpx;font-size: 26rpx;">
登录即表示接受
<navigator url="/pages/agreement/agreement?id=9" style="color: rgba(111, 162, 86, 1);">隐私政策</navigator>
<navigator url="/pages/agreement/agreement?10" style="color: rgba(111, 162, 86, 1);">用户注册服务协议</navigator>
</view> -->
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { loginByPassword, saveOpenIdByWxCode } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
import store from '@/store/index.js';
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
let captchaImg = ref('');
let dataFrom = reactive({
userName: '',
passwd: '',
uuid: '',
captcha: ''
});
// onLoad(async () => {
// getCaptcha();
// });
let back = () => {
uni.navigateBack();
};
let getCaptcha = async () => {
let { captcha, uuid } = await captchaApi();
dataFrom.uuid = uuid;
captchaImg.value = 'data:image/png;base64,' + captcha;
};
let toRegister = () => {
uni.navigateTo({
url: '/pageInvest/login/register'
});
};
let getBackAccout = () => {
uni.navigateTo({
url: '/pageInvest/login/getBackAccout'
});
};
let toGetBack = () => {
uni.navigateTo({
url: '/pageInvest/login/getBack'
});
};
let login = async () => {
try {
const { code } = await uni.login();
let _res = await loginByPassword(dataFrom);
// uni.setStorageSync('tokenInvest', _res.token);
// uni.setStorageSync('userInvest', _res);
uni.setStorageSync('token', _res.token);
uni.setStorageSync('user', _res);
uni.setStorageSync('isInvest', true);
store.commit('setToken', _res.token);
// #ifdef MP-WEIXIN
let saveOpenId = await saveOpenIdByWxCode({ loginCode: code });
// #endif
// #ifdef MP-ALIPAY
let saveOpenId = await saveOpenIdByZfbCode({ loginCode: code });
// #endif
uni.showToast({ title: '登录成功', icon: 'none' });
setTimeout(() => {
uni.reLaunch({
url: '/pages/home/home'
});
// uni.navigateBack();
}, 200);
} catch (err) {
// getCaptcha();
}
};
</script>
<style scoped lang="scss">
.login {
padding: 0 60rpx;
&_bei {
position: fixed;
right: -120rpx;
top: -206rpx;
width: 728rpx;
height: 728rpx;
}
&_logo {
margin-top: 150rpx;
&_img {
width: 280rpx;
height: 200rpx;
// background: #e6e6e6;
// box-shadow: 0rpx 0rpx 110rpx 2rpx rgba(115, 192, 76, 0.19);
border-radius: 28rpx 28rpx 28rpx 28rpx;
margin-bottom: 20rpx;
}
&_tit {
font-weight: bold;
font-size: 44rpx;
color: #232323;
}
}
&_btn {
width: 474rpx;
height: 78rpx;
background: rgba(111, 162, 86, 1);
border-radius: 54rpx 54rpx 54rpx 54rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 30rpx;
color: #ffffff;
}
}
.orderdetail_header {
width: 750rpx;
position: fixed;
left: 0;
top: 0;
z-index: 99;
}
</style>

View File

@@ -0,0 +1,192 @@
<template>
<view class="login">
<view class="orderdetail_header p30">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px; display: flex; align-items: center">
<up-icon name="arrow-left" bold color="#000" @click="back"></up-icon>
</view>
</view>
<image class="login_bei" src="/static/logoB.png"></image>
<view style="padding: 0 60rpx">
<statusBar />
<view class="login_logo">
<image class="login_logo_img" src="/static/logo.png"></image>
<view class="login_logo_tit">欢迎来到投资者平台</view>
</view>
<view style="margin-top: 100rpx">
<view>
<up-input fontSize="30rpx" v-model="dataFrom.userName" placeholder="请输入您的用户名" border="bottom" clearable></up-input>
</view>
<view style="font-size: 26rpx; color: #ff9900; margin: 10rpx 0 10rpx; padding-left: 9px">用户名由字母或数字组成长度6-32</view>
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.phone" placeholder="请输入您的手机号" border="bottom" clearable></up-input>
</view>
<view style="margin-bottom: 30rpx; display: flex; align-items: center">
<up-input fontSize="30rpx" v-model="dataFrom.smsCode" placeholder="请输入验证码" border="bottom" clearable></up-input>
<up-code ref="uCode" @change="codeChange2" keep-running start-text="点我获取验证码"></up-code>
<text @click="getCode2" :text="tips" style="font-size: 28rpx; color: rgba(111, 162, 86, 1)">{{ tips }}</text>
</view>
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.shareCode" placeholder="请输入您的邀请码" border="bottom" clearable></up-input>
</view>
<view>
<up-input fontSize="30rpx" v-model="dataFrom.passwd" type="password" placeholder="请输入您的密码" border="bottom" clearable></up-input>
</view>
<view style="font-size: 26rpx; color: #ff9900; margin: 10rpx 0 10rpx; padding-left: 9px">密码必须包含字母数字长度8-32</view>
<view style="margin-bottom: 30rpx">
<up-input fontSize="30rpx" v-model="dataFrom.confirmPasswd" type="password" placeholder="请再次输入您的密码" border="bottom" clearable></up-input>
</view>
</view>
<view style="font-size: 28rpx; color: #666; margin-top: 20rpx">
已有账号
<text style="color: rgba(111, 162, 86, 1)" @click="toLogin">立即登录</text>
</view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="login_btn" @click="submit">注册</view>
</view>
</view>
<view style="display: flex; flex-wrap: wrap; justify-content: center; margin-top: 20rpx; font-size: 26rpx; align-items: center">
<up-checkbox @change="changeChex" :customStyle="{ marginRight: '15rpx', marginBotton: 0 }"></up-checkbox>
已阅读并同意
<navigator url="/pages/agreement/agreement?id=9" style="color: rgba(111, 162, 86, 1)">用户注册服务协议</navigator>
<navigator url="/pages/agreement/agreement?id=10" style="color: rgba(111, 162, 86, 1)">隐私政策</navigator>
</view>
<view style="height: 150rpx"></view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { registerApi, smsCode } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
let tips = ref('');
let uCode = ref(null);
let passwd = ref('');
let dataFrom = reactive({
userName: '',
passwd: '',
shareCode: '',
phone: '',
platform: 1,
smsCode: '',
confirmPasswd: ''
});
let xieyi = ref(false);
onLoad(() => {
const invite_code = uni.getStorageSync('invite_code');
if (invite_code) {
dataFrom.shareCode = invite_code;
}
});
let changeChex = (e) => {
xieyi.value = e;
};
let toLogin = () => {
uni.navigateBack();
};
let codeChange2 = (text) => {
tips.value = text;
};
let getCode2 = () => {
if (!dataFrom.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (uCode.value.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: '正在获取验证码'
});
smsCode({
phone: dataFrom.phone
}).then((res) => {
uni.hideLoading();
uni.$u.toast('验证码已发送');
uCode.value.start();
});
} else {
uni.$u.toast('倒计时结束后再发送');
}
};
let submit = async () => {
if (!xieyi.value) return uni.showToast({ title: '请先阅读并勾选隐私政策和用户注册服务协议', icon: 'none' });
if (!dataFrom.userName) return uni.showToast({ title: '请输入用户名', icon: 'none' });
if (!dataFrom.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (dataFrom.phone.length != 11) return uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
if (!dataFrom.smsCode) return uni.showToast({ title: '请输入验证码', icon: 'none' });
if (!dataFrom.shareCode) return uni.showToast({ title: '请输入邀请码', icon: 'none' });
if (!dataFrom.passwd) return uni.showToast({ title: '请输入密码', icon: 'none' });
if (!dataFrom.confirmPasswd) return uni.showToast({ title: '请再次输入密码', icon: 'none' });
if (dataFrom.passwd != dataFrom.confirmPasswd) return uni.showToast({ title: '两次密码输入不一致', icon: 'none' });
let _res = await registerApi(dataFrom);
uni.showToast({ title: '注册成功', icon: 'none' });
setTimeout(() => {
uni.navigateBack();
}, 200);
};
let back = () => {
uni.navigateBack();
};
</script>
<style scoped lang="scss">
.login {
&_bei {
position: fixed;
right: -120rpx;
top: -206rpx;
width: 728rpx;
height: 728rpx;
}
&_logo {
margin-top: 150rpx;
&_img {
width: 280rpx;
height: 200rpx;
// background: #e6e6e6;
// box-shadow: 0rpx 0rpx 110rpx 2rpx rgba(115, 192, 76, 0.19);
border-radius: 28rpx 28rpx 28rpx 28rpx;
margin-bottom: 20rpx;
}
&_tit {
font-weight: bold;
font-size: 44rpx;
color: #232323;
}
}
&_btn {
width: 474rpx;
height: 78rpx;
background: rgba(111, 162, 86, 1);
border-radius: 54rpx 54rpx 54rpx 54rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 30rpx;
color: #ffffff;
}
}
.orderdetail_header {
width: 750rpx;
position: fixed;
left: 0;
top: 0;
z-index: 99;
}
</style>

View File

@@ -0,0 +1,121 @@
<template>
<view style="padding: 30rpx">
<view>
<view style="font-size: 30rpx; color: #949494">当前增值收益 {{ user.money2 }}</view>
<view style="height: 20rpx"></view>
<up-input :customStyle="{ backgroundColor: '#ffffff' }" type="number" placeholder="请输入充值金额" border="surround" v-model="form.money"></up-input>
<view style="font-size: 30rpx; color: #949494; margin-top: 16rpx;">最小充值金额为{{ rechargeConfig.min_money }}</view>
</view>
<view style="height: 30rpx"></view>
<view style="background-color: #fff; padding: 30rpx; border-radius: 10rpx">
<view style="font-size: 28rpx;#606266">支付方式</view>
<view style="height: 20rpx"></view>
<up-radio-group v-model="form.pay_type" iconPlacement="right" :borderBottom="true" placement="column">
<up-radio :name="1">
<view class="up-flex up-flex-y-center" style="display: flex; align-items: center">
<up-icon name="/static/icon/weixin.png" imgMode="widthFix" size="50rpx" />
<view style="width: 20rpx"></view>
<view>
<view style="font-size: 30rpx">微信支付</view>
<view style="font-size: 28rpx; color: #909399">微信快捷支付</view>
</view>
</view>
</up-radio>
</up-radio-group>
</view>
<view style="height: 100rpx"></view>
<up-button type="primary" @click="getRecharge">立即支付</up-button>
<view style="height: 100rpx"></view>
</view>
</template>
<script setup>
import { rechargeAllinPay, getAppConfig } from '@/api/api.js';
import { ref, reactive } from 'vue';
import { onShow, onLoad } from '@dcloudio/uni-app';
import { userHook } from '@/hooks/userInfo.js';
const { user } = userHook();
const form = reactive({
money: '',
pay_type: 1
});
let rechargeConfig = ref();
onLoad(() => {
getAppConfig().then((res) => {
console.log(res);
const walletConfig = res?.find(item => item.configKey === "shop_recharge")
const configValue = walletConfig ? walletConfig.configValue : {}
rechargeConfig.value = JSON.parse(configValue);
});
});
onShow(async () => {
let options = uni.getEnterOptionsSync();
const shop_order_pay_show = uni.getStorageSync('shop_order_pay_show');
let appId = 'wxef277996acc166c3';
if (options.scene == '1038' && options.referrerInfo.appId == appId && shop_order_pay_show == 1) {
uni.setStorageSync('shop_order_pay_show', 0);
// 代表从收银台小程序返回
let extraData = options.referrerInfo.extraData;
if (!extraData) {
// "当前通过物理按键返回,未接收到返参,建议自行查询交易结果";
uni.showModal({
title: '提示',
content: '未检测到支付结果',
success: (res) => {
if (res.confirm) {
}
}
});
} else {
if (extraData.code == 'success') {
// "支付成功";
uni.showToast({
title: '支付成功',
icon: 'none'
});
uni.navigateBack();
} else if (extraData.code == 'cancel') {
// "支付已取消";
uni.showToast({
title: '支付已取消',
icon: 'none'
});
} else {
// "支付失败:" + extraData.errmsg;
uni.showToast({
title: '支付失败:' + extraData.errmsg,
icon: 'none'
});
}
}
}
});
const getRecharge = () => {
rechargeAllinPay(form).then((res) => {
uni.openEmbeddedMiniProgram({
appId: res.appid,
extraData: res.extraData,
success(res) {
// 打开成功
uni.setStorageSync('shop_order_pay_show', 1);
}
});
});
};
</script>
<style lang="scss">
.xkl-no {
background-color: #f1f1f1;
}
.xkl-cur {
background-color: #2cce7f;
color: #ffffff;
}
</style>

190
pageInvest/money/wallet.vue Normal file
View File

@@ -0,0 +1,190 @@
<template>
<view class="wallet p30">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view class="wallet_pall">
<view>
<view class="wallet_pall_header">
基础收益
<!-- <view @click="navTo(`/pages/mine/transferBalance`, true)">收益转入</view> -->
</view>
<view class="wallet_pall_ye">
<view>{{ user.money || '0.00' }}</view>
<!-- <view style="margin-top: 10rpx" @click="navTo(`/pages/mine/topUp`, true)">充值</view> -->
</view>
</view>
<view>
<view class="wallet_pall_header">增值收益</view>
<view class="wallet_pall_ye">
<view>{{ user.money2 || '0.00' }}</view>
</view>
</view>
</view>
<view class="mt30" style="padding: 15rpx 30rpx; display: flex; align-items: center; background: #6fa256; border-radius: 0 0 16rpx 16rpx">
<view @click="navTo(`/pageInvest/money/recharge`, true)" style="width: 330rpx; text-align: center; color: #fff">充值</view>
<view @click="navTo(`/pageInvest/money/withdraw`, true)" style="width: 330rpx; text-align: center; color: #fff">提现</view>
</view>
<view class="mt30">
<uni-section title="明细" type="line" titleFontSize="32rpx"></uni-section>
</view>
<view class="mt30 wallet_list" v-for="(item, index) in dataList" :key="index">
<view class="wallet_list_left">
<view>{{ moneyJson.find((val) => val.id == item.type).name }}</view>
<view>{{ item.created_at }}</view>
</view>
<view class="wallet_list_right">{{ item.money }}</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { onPullDownRefresh, onPageScroll, onReachBottom, onLoad, onShow } from '@dcloudio/uni-app';
import { timeFormat } from '@/uni_modules/uview-plus';
import { extractRecordList } from '@/api/api.js';
import moneyJson from '@/common/money.json';
import { userHook } from '@/hooks/userInfo.js';
const { user } = userHook();
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
let getInfo = ref({});
const paging = ref(null);
let dataList = ref([]);
let num = ref(1);
let isPagingRefNotFound = () => {
return !paging.value;
};
onShow(async () => {
if (num.value != 1) {
paging.value.reload();
}
num.value++;
});
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize
};
extractRecordList(params)
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
</script>
<style scoped lang="scss">
.wallet_pall {
background: #6fa256;
// border-radius: 16rpx 16rpx 16rpx 16rpx;
height: 272rpx;
// background: linear-gradient(179deg, #4874e5 0%, #3864d6 100%);
border-radius: 16rpx 16rpx 0 0;
padding: 40rpx;
padding-bottom: 0;
border-bottom: 1rpx solid rgba(153, 153, 153, 0.6);
display: flex;
align-items: center;
justify-content: space-between;
&_header {
font-weight: bold;
font-size: 26rpx;
color: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
view {
width: 128rpx;
height: 58rpx;
background: #ffffff;
border-radius: 32rpx 32rpx 32rpx 32rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #6fa256;
}
}
&_ye {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
view:nth-child(1) {
font-weight: bold;
font-size: 68rpx;
color: #ffffff;
}
view:nth-child(2) {
width: 128rpx;
height: 58rpx;
background: #ffffff;
border-radius: 32rpx 32rpx 32rpx 32rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #6fa256;
}
}
}
.wallet_list {
width: 690rpx;
height: 120rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
padding: 15rpx 30rpx;
@include flex($space: space-between);
&_left {
view:nth-child(1) {
font-weight: bold;
font-size: 28rpx;
color: #232323;
margin-bottom: 10rpx;
}
view:nth-child(2) {
font-size: 24rpx;
color: #232323;
}
}
&_right {
font-weight: bold;
font-size: 28rpx;
color: #ff2727;
}
}
.mt30 {
margin-bottom: 30rpx;
}
</style>

View File

@@ -0,0 +1,267 @@
<template>
<view class="withdraw p30">
<!-- #ifdef MP-ALIPAY -->
<view style="height: 30rpx"></view>
<!-- #endif -->
<view class="withdraw_k" @click="toNav">
<view class="withdraw_k_tit">提现到</view>
<view class="withdraw_k_input">请选择银行卡</view>
<image class="withdraw_k_img" src="/static/icon/xia.png"></image>
</view>
<view v-if="bank">
<view style="background-color: #ffffff; border-radius: 12rpx; padding: 20rpx; margin-bottom: 20rpx">
<view class="u-flex u-flex-y-center" style="font-size: 28rpx">
<view>
<u-tag :text="bank.role == 1 ? '个人' : '企业'" size="mini" :type="bank.role == 1 ? 'success' : 'error'" plain plainFill></u-tag>
</view>
<view style="width: 30rpx"></view>
<view style="font-size: 26rpx">{{ bank.realname }}</view>
<view style="width: 30rpx"></view>
<view style="font-size: 26rpx">{{ bank.mobile || '' }}</view>
</view>
<view style="height: 20rpx"></view>
<view style="color: #232323">
<!-- <view style="font-size: 28rpx">开户行{{ bank.bankName }}</view>
<view style="height: 10rpx"></view> -->
<view style="font-size: 28rpx" v-if="bank.role == 2">开户行{{ bank.subname }}</view>
<view style="height: 10rpx"></view>
<view style="font-size: 28rpx">银行卡号{{ bank.num }}</view>
<view style="height: 10rpx"></view>
<!-- <view style="font-size: 28rpx" v-if="bank.type == 2">纳税人识别号{{ bank.taxNo ? maskCardNumber(bank.taxNo) : '' }}</view>
<view style="height: 10rpx"></view> -->
</view>
</view>
</view>
<view class="withdraw_mon">
<view class="withdraw_mon_tit">提现金额</view>
<view class="withdraw_mon_input">
<view class="withdraw_mon_input_fu"></view>
<view>
<up-input fontSize="36rpx" placeholder="请输入金额" :border="false" v-model="dataFrom.money"></up-input>
</view>
<view class="withdraw_mon_input_note" @click="dataFrom.money = getInfo.money">全部提现</view>
</view>
<view>
<up-input :border="false" disabled v-model="getInfo.mobile"></up-input>
</view>
<view class="withdraw_mon_input">
<up-input placeholder="请输入验证码" :border="false" v-model="dataFrom.smsCode"></up-input>
<view style="width: 250rpx">
<up-code ref="uCode" @change="codeChange2" keep-running start-text="点我获取验证码"></up-code>
<up-button @click="getCode" color="#4874e5">{{ tips }}</up-button>
</view>
</view>
<view class="withdraw_mon_note">当前基础收益{{ getInfo.money }}</view>
<view class="withdraw_mon_note">最低提现金额为{{ appConfig.chargeMinAmount }}</view>
<view class="withdraw_mon_note">私户每100.00元提现手续费为{{ appConfig.free }}%</view>
</view>
<view class="withdraw_note">
<view class="withdraw_note_tit" style="font-weight: bold; font-size: 26rpx">提现规则</view>
<!-- <view class="withdraw_note_s">1.现在本软件填写提现账户</view> -->
<!-- <view class="withdraw_note_s">2.然后扫描二维码填写相应的提现账户</view> -->
<view class="withdraw_note_s">1.每月1号1121号可提现到账时间T+(1-3)</view>
<view class="withdraw_note_s">2.提现年龄是18-65</view>
<view class="withdraw_note_s">3.提现银行卡是常用的一类银行否则会有限额</view>
<view class="withdraw_note_s">4.一月不能超{{ appConfig.monthQuota }}如遇超出 提现后管理人员会联系您</view>
<view class="withdraw_note_s">5.提现次数不限公户无限额无手续费</view>
<!-- <view class="withdraw_note_s" style="flex-direction: column; display: flex; align-items: center">
<up-image width="350rpx" height="350rpx" src="https://xingdong-app.oss-cn-beijing.aliyuncs.com/hongjiesuan-xingdong.png" mode="widthFix"></up-image>
<view style="height: 10rpx"></view>
<view>长按保存二维码</view>
</view> -->
</view>
<view style="height: 50rpx"></view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="affirm_btn" @click="payOrder">立即提现</view>
</view>
<view style="height: 50rpx"></view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { userInfoIsInvest, smsCode, getAppConfig, pointsExtract } from '@/api/api.js';
import { onLoad, onShow } from '@dcloudio/uni-app';
let value = ref();
let getInfo = ref({});
let appConfig = ref([]);
let tips = ref('');
let uCode = ref(null);
let dataFrom = reactive({
money: '',
smsCode: '',
accountId: ''
});
let bank = ref();
onLoad(async () => {
let _res = await userInfoIsInvest();
getInfo.value = _res;
const configData = await getAppConfig();
const walletConfig = configData?.find(item => item.configKey === "APP_WALLET")
const configValue = walletConfig ? walletConfig.configValue : {}
appConfig.value = JSON.parse(configValue);
uni.$on('bank', (e) => {
bank.value = e;
dataFrom.accountId = e.id;
console.log(e);
});
});
let toNav = () => {
uni.navigateTo({
url: '/pages/bank/bank?type=xz'
});
};
let codeChange2 = (text) => {
tips.value = text;
};
let getCode = () => {
console.log(123456);
if (!getInfo.value.mobile) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (uCode.value.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: '正在获取验证码'
});
smsCode({
phone: getInfo.value.mobile
}).then((res) => {
uni.hideLoading();
uni.$u.toast('验证码已发送');
uCode.value.start();
});
} else {
uni.$u.toast('倒计时结束后再发送');
}
};
function maskCardNumber(cardNumber) {
if (!cardNumber || typeof cardNumber !== 'string') {
throw new Error('Invalid card number');
}
const sanitizedNumber = cardNumber.replace(/\D/g, '');
if (sanitizedNumber.length < 4) {
throw new Error('Card number is too short');
}
const lastFourDigits = sanitizedNumber.slice(-4);
const maskedNumber = '*'.repeat(sanitizedNumber.length - 4) + lastFourDigits;
return maskedNumber;
}
let payOrder = async () => {
console.log(getInfo.value.money, 'getInfo.value.money');
console.log(dataFrom.money, 'dataFrom.money');
if (Number(getInfo.value.money) < Number(dataFrom.money)) return uni.showToast({ title: '可提现金额不足', icon: 'none' });
if (!dataFrom.accountId) return uni.showToast({ title: '请先选择提现银行卡', icon: 'none' });
if (!dataFrom.money) return uni.showToast({ title: '请输入提现金额', icon: 'none' });
if (!dataFrom.smsCode) return uni.showToast({ title: '请输入验证码', icon: 'none' });
let _res = await pointsExtract(dataFrom);
uni.showModal({
title: '提示',
content: '提交成功',
showCancel: false,
success() {
uni.navigateBack();
}
});
};
</script>
<style scoped lang="scss">
.withdraw {
&_k {
width: 100%;
height: 74rpx;
padding: 0 20rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 30rpx;
&_tit {
font-weight: bold;
font-size: 24rpx;
color: #232323;
margin-right: 100rpx;
}
&_input {
flex: 1;
text-align: right;
font-size: 28rpx;
}
&_img {
width: 44rpx;
height: 44rpx;
}
}
&_mon {
padding: 20rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
&_tit {
font-weight: bold;
font-size: 24rpx;
color: #232323;
}
&_input {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 2rpx solid #cccccc;
padding: 15rpx 0;
margin-bottom: 20rpx;
&_fu {
font-weight: bold;
font-size: 66rpx;
color: #232323;
}
&_note {
font-weight: bold;
font-size: 24rpx;
color: #ff7777;
}
}
&_note {
font-weight: 400;
font-size: 24rpx;
color: #232323;
margin-bottom: 10rpx;
}
}
&_note {
margin-top: 30rpx;
padding: 0 15rpx;
view {
margin-bottom: 15rpx;
font-weight: 400;
font-size: 26rpx;
color: #232323;
line-height: 40rpx;
}
}
}
.affirm_btn {
width: 650rpx;
height: 78rpx;
background: #4874e5;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 24rpx;
color: #ffffff;
}
</style>

246
pageInvest/shop/affirm.vue Normal file
View File

@@ -0,0 +1,246 @@
<template>
<view class="p30">
<view style="height: 20rpx"></view>
<view style="background-color: #ffffff; padding: 20rpx; border-radius: 10rpx; font-size: 30rpx; display: flex">
<image style="width: 220rpx; height: 220rpx; border-radius: 16rpx" :src="shop.cover" mode="aspectFill"></image>
<view style="padding: 20rpx">
<view style="color: #232323">{{ shop.name }}</view>
<view style="height: 20rpx"></view>
<view>
<text>单价</text>
<text style="color: crimson">{{ shop.currentPrice }}</text>
</view>
<view style="height: 20rpx"></view>
<view>
<text>总价</text>
<text style="color: crimson">{{ shop.currentPrice * dataFrom.num }}</text>
</view>
</view>
</view>
<view style="height: 20rpx"></view>
<view style="background-color: #ffffff; padding: 20rpx; border-radius: 10rpx; font-size: 30rpx; display: flex; align-items: center; justify-content: space-between">
<view class="u-flex">
<view>购买数量</view>
<view style="width: 10rpx"></view>
</view>
<view><up-number-box v-model="dataFrom.num" inputWidth="100rpx" @change="changenum"></up-number-box></view>
</view>
<!-- <view
@click="toAddress"
v-if="shop.purposeType != 1"
style="
background-color: #ffffff;
padding: 20rpx;
border-radius: 10rpx;
font-size: 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 30rpx;
"
>
<view class="u-flex" v-if="!addData">
<view>请先选择收货地址</view>
</view>
<view class="address-a" v-else @click="toAddress">
<view class="top">
<view class="top-a">
<view>{{ addData.realName }}</view>
<view>{{ addData.phone }}</view>
</view>
<view class="top-b">{{ addData.province }} {{ addData.city }} {{ addData.district }} {{ addData.detail }}</view>
</view>
</view>
</view> -->
<!-- <view
style="background-color: #ffffff; padding: 20rpx; border-radius: 10rpx; font-size: 30rpx; margin-top: 30rpx"
v-if="shop.purposeType == 2 || (shop.purposeType == 3 && shop.salePrice == 2980)"
>
<view style="font-weight: 700">温馨提示{{ shop.purposeType == 2 ? `${shop.itemType == 7 ? '20' : shop.itemType == 20 ? '5' : ''}台包安装` : '' }}</view>
<view style="height: 20rpx"></view>
<view>套包安装内容仅限50米实际电缆小于50米的以实际安装必要长度为准差值米数不以任何形式赠送或返还;超出50米的超出部分按100元/米补足超出的费用</view>
</view> -->
<view style="background-color: #ffffff; padding: 20rpx; border-radius: 10rpx; font-size: 30rpx; margin-top: 30rpx">
<view style="font-weight: 700">购买须知</view>
<view style="height: 20rpx"></view>
<view style="color: #dd6161">付款成功后立即生效并投入生产安装不支持退款退货</view>
<view style="height: 20rpx"></view>
<view style="display: flex; align-items: center; justify-content: space-between">
<view style="display: flex">
<view>阅读并同意:</view>
<navigator url="/pages/protocol/buy?id=14" style="color: dodgerblue" open-type="navigate">
<text>充电桩购销合同</text>
</navigator>
</view>
<view>
<up-text v-if="policy.is_buy == 1" text="已同意" type="primary"></up-text>
<up-text v-else text="未同意" type="error"></up-text>
</view>
</view>
<view style="height: 20rpx"></view>
<view style="display: flex; align-items: center; justify-content: space-between">
<view style="display: flex">
<view>阅读并同意:</view>
<navigator url="/pages/protocol/trusteeship?id=13" style="color: dodgerblue" open-type="navigate">
<text>充电桩托管协议</text>
</navigator>
</view>
<view>
<up-text v-if="policy.is_trusteeship == 1" text="已同意" type="primary"></up-text>
<up-text v-else text="未同意" type="error"></up-text>
</view>
</view>
</view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="affirm_btn" @click="add">确认订单</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { addGoodsOrders } from '@/api/api.js';
import { shopInfo } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
let dataFrom = ref({
num: 1
});
let shop = ref({});
let policy = ref({
is_trusteeship: 0,
is_buy: 0
});
let address = ref({});
let addData = ref(null);
let typeTrue = computed(() => {
var a = false;
if (
(shop.value.purposeType == 2 && dataFrom.value.num == 20 && shop.value.itemType == 7) ||
(shop.value.purposeType == 2 && dataFrom.value.num == 5 && shop.value.itemType == 20)
) {
a = true;
}
return a;
});
onLoad(async (options) => {
let _res = await shopInfo({
goodId: options.id
});
shop.value = _res;
uni.$on('buy', (e) => {
policy.value.is_buy = e;
});
uni.$on('trusteeship', (e) => {
policy.value.is_trusteeship = e;
});
uni.$on('address', (e) => {
addData.value = e;
address.value = {
takeName: e.realName,
takePhone: e.phone,
takeAddress: `${e.province}${e.city}${e.district}${e.detail}`
};
});
});
let changenum = (e) => {
console.log(e);
};
let toAddress = () => {
uni.navigateTo({
url: '/pages/address/list?type=1'
});
};
let add = async () => {
// if (!address.value.takeName && shop.value.purposeType != 1) return uni.showToast({ title: '请先选择收货地址', icon: 'none' });
if (!policy.value.is_buy) return uni.showToast({ title: '请阅读并同意《充电桩购销合同》', icon: 'none' });
if (!policy.value.is_trusteeship) return uni.showToast({ title: '请阅读并同意《充电桩托管协议》', icon: 'none' });
let _res = await addGoodsOrders({
num: dataFrom.value.num,
goodsId: shop.value.id
// ...address.value
});
uni.redirectTo({
url: `/pageInvest/shop/pay?id=${_res.id}&amount=${_res.payMoney}&type=1&num=${_res.num}&goodsId=${shop.value.id}`
});
};
</script>
<style scoped lang="scss">
.affirm_btn {
width: 650rpx;
height: 78rpx;
background: #4874e5;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 24rpx;
color: #ffffff;
}
.address-a {
.top {
padding: 40rpx;
.top-a {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 30rpx;
font-weight: bold;
color: #222222;
margin-bottom: 45rpx;
}
.top-b {
font-size: 30rpx;
font-weight: bold;
color: #999999;
}
}
.bottom {
padding: 35rpx;
display: flex;
align-items: center;
justify-content: space-between;
.bottom-che {
display: flex;
align-items: center;
image {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
font-size: 24rpx;
font-weight: bold;
color: #222222;
}
.bottom-r {
font-size: 26rpx;
font-weight: bold;
color: #999999;
display: flex;
align-items: center;
}
}
}
</style>

139
pageInvest/shop/details.vue Normal file
View File

@@ -0,0 +1,139 @@
<template>
<view class="shop">
<!-- <view class="orderdetail_header p30">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px; display: flex; align-items: center" @click="">
<up-icon name="arrow-left" bold color="#000" @click="back"></up-icon>
<view @click="back" style="margin-left: 25rpx; transition: all 0.5s">商品详情</view>
</view>
</view> -->
<up-swiper :list="[shop.cover]" height="759rpx"></up-swiper>
<view class="p30">
<view class="shop_info">
<view class="shop_info_mon"> {{ shop.currentPrice }}</view>
<view class="shop_info_tit">{{ shop.name }}</view>
<view class="shop_info_note">
库存{{ shop.stock }}
<view style="width: 50rpx"></view>
销量{{ shop.sales }}
</view>
</view>
</view>
<view style="margin: 30rpx 0; font-size: 30rpx; color: #333; text-align: center">详情介绍</view>
<image style="width: 100%" mode="widthFix" :src="item" v-for="(item, index) in shop.detail.split(',')" :key="index"></image>
<view style="height: 150rpx"></view>
<view class="shop_btn">
<!-- <view>
<view>首页</view>
</view>
<view>
<view>客服</view>
</view> -->
<view class="shop_btn_btn" @click="navTo(`/pageInvest/shop/affirm?id=${shop.id}`)">立即下单</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { useNav } from '@/hooks/useNav.js';
import { shopInfo } from '@/api/api.js';
let shop = ref({});
const { nav, navTo } = useNav();
const headerBg = ref(false);
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
const list3 = ref(['/static/图层 979.png']);
onLoad(async (options) => {
console.log(options);
let _res = await shopInfo({
goodId: options.id
});
shop.value = _res;
});
const back = () => {
uni.navigateBack();
};
onPageScroll((e) => {
if (e.scrollTop > uni.getSystemInfoSync().statusBarHeight + 44) {
headerBg.value = true;
} else {
headerBg.value = false;
}
});
</script>
<style>
page {
background: #f7f7f7;
}
</style>
<style scoped lang="scss">
.orderdetail_header {
width: 750rpx;
transition: all 0.5s;
}
.shop_btn {
position: fixed;
bottom: 0;
left: 0;
padding: 20rpx 60rpx 30rpx;
width: 750rpx;
height: 120rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
image {
width: 40rpx;
height: 40rpx;
margin-right: 30rpx;
}
&_btn {
width: 496rpx;
// height: 64rpx;
padding: 15rpx;
border-radius: 8rpx 8rpx 8rpx 8rpx;
border: 2rpx solid #002ea4;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 28rpx;
color: #002ea4;
}
}
.shop_info {
padding: 30rpx;
background-color: #fff;
border-radius: 8rpx;
margin-top: 30rpx;
&_mon {
font-weight: bold;
font-size: 44rpx;
color: #ff1a1a;
}
&_tit {
font-weight: bold;
font-size: 34rpx;
color: #232323;
margin-bottom: 15rpx;
}
&_note {
display: flex;
align-items: center;
font-weight: 400;
font-size: 30rpx;
color: #666666;
}
}
</style>

214
pageInvest/shop/order.vue Normal file
View File

@@ -0,0 +1,214 @@
<template>
<view class="order">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<up-dropdown>
<!-- <up-dropdown-item @change="upChange" v-model="dataFrom.sourceType" title="商品类型" :options="options1"></up-dropdown-item> -->
<up-dropdown-item @change="upChange" v-model="dataFrom.businessPayType" title="支付类型" :options="options2"></up-dropdown-item>
<up-dropdown-item @change="upChange" v-model="dataFrom.status" title="状态" :options="options3"></up-dropdown-item>
</up-dropdown>
<view class="p30">
<view class="order_view" v-for="i in dataList" :key="i" @click="navTo(`/pages/order/details?id=${i.id}`)">
<view class="order_view_dd">
<view>
<text style="font-weight: 500">订单号</text>
:{{ i.orderNo }}
</view>
<view>
<up-tag size="mini" v-if="i.status == 0" text="待支付" plain></up-tag>
<up-tag size="mini" v-if="i.status == -1" text="已取消" type="warning" plain></up-tag>
<up-tag size="mini" v-if="i.status == 1" text="支付成功" type="success" plain></up-tag>
<up-tag size="mini" v-if="i.status == -2" text="退款" type="error" plain></up-tag>
</view>
</view>
<view class="order_view_info">
<image class="order_view_info_img" :src="JSON.parse(i.picture)[0]" mode="aspectFit"></image>
<view class="order_view_info_right">
<view class="order_view_info_right_tit">
<view style="display: flex; align-items: center">
<up-tag size="mini" :text="i.sourceType == 1 ? '商品' : '套餐'" bgColor="#4874e5" borderColor="#4874e5"></up-tag>
<view style="margin-left: 15rpx">
{{ i.goodName }}
</view>
</view>
</view>
<view class="order_view_info_right_num" style="display: flex; align-items: center; justify-content: space-between">数量:{{ i.num }}</view>
<view class="order_view_info_right_mon">
订单金额:
<text style="color: crimson">{{ i.amount }}</text>
</view>
</view>
</view>
<view
style="
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid rgba(153, 153, 153, 0.5);
margin-top: 15rpx;
padding-top: 15rpx;
"
>
<view style="font-size: 28rpx">{{ timeFormat(new Date(i.createTime).getTime(), 'yyyy-mm-dd hh:MM') }}</view>
<view>
<up-tag size="mini" v-if="i.orderPlatform == 3" text="支付宝" plain></up-tag>
<up-tag size="mini" v-if="i.orderPlatform == 2" text="微信" type="success" plain></up-tag>
<up-tag size="mini" v-if="i.orderPlatform == 1" text="钱包" type="warning" plain></up-tag>
</view>
</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useNav } from '@/hooks/useNav.js';
import { onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { orderPage } from '@/api/api.js';
import { timeFormat } from '@/uni_modules/uview-plus';
const { navTo } = useNav();
const paging = ref(null);
let dataList = ref([]);
let dataFrom = reactive({
status: '',
businessPayType: '',
sourceType: ''
});
let options1 = ref([
{
label: '商品',
value: 1
},
{
label: '套餐',
value: 2
}
]);
let options2 = ref([
{
label: '微信',
value: 1
},
{
label: '支付宝',
value: 2
},
{
label: '钱包',
value: 3
}
]);
let options3 = ref([
{
label: '待支付',
value: 0
},
{
label: '支付成功',
value: 1
},
{
label: '取消',
value: -1
},
{
label: '退款',
value: -2
}
]);
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const upChange = (e) => {
console.log(dataFrom);
paging.value.reload();
};
const queryList = (pageNo, pageSize) => {
let { id } = uni.getStorageSync('user');
const params = {
current: pageNo,
pageSize: pageSize,
...dataFrom
};
orderPage(params)
.then((res) => {
paging.value.complete(res.records);
})
.catch((res) => {
paging.value.complete(false);
});
};
</script>
<style scoped lang="scss">
.order {
&_view {
background: #ffffff;
border-radius: 16rpx;
padding: 25rpx;
margin-bottom: 30rpx;
&_info {
@include flex;
&_img {
width: 208rpx;
height: 208rpx;
margin-right: 15rpx;
border-radius: 10rpx;
}
&_right {
flex: 1;
font-size: 28rpx;
color: #232323;
&_tit {
@include flex($space: space-between);
margin-bottom: 15rpx;
}
&_num {
margin-bottom: 15rpx;
}
&_mon {
margin-bottom: 15rpx;
text {
color: #ff2e24;
}
}
&_time {
}
}
}
&_dd {
@include flex($space: space-between);
font-weight: bold;
font-size: 28rpx;
color: #232323;
margin-bottom: 15rpx;
}
}
}
</style>

184
pageInvest/shop/pay.vue Normal file
View File

@@ -0,0 +1,184 @@
<template>
<view>
<view style="height: 20rpx"></view>
<view style="background-color: #ffffff; border-radius: 10rpx; padding: 30rpx; text-align: center">
<view style="color: #fa3534">
<text style="font-size: 30rpx"></text>
<text style="font-size: 36rpx; font-weight: 700">{{ amount }}</text>
</view>
<view style="color: #909399; font-size: 28rpx">支付金额</view>
</view>
<view style="height: 20rpx"></view>
<view style="background-color: #fff; padding: 30rpx; border-radius: 10rpx">
<view style="font-size: 28rpx;#606266">支付方式</view>
<view style="height: 20rpx"></view>
<up-radio-group v-model="dataFrom.pay_type" iconPlacement="right" :borderBottom="true" placement="column">
<up-radio :name="3" label="123456">
<view style="display: flex; align-items: center">
<up-icon name="/static/icon/money.png" imgMode="widthFix" size="50rpx" />
<view style="width: 20rpx"></view>
<view>
<view style="font-size: 30rpx">余额支付</view>
<view style="font-size: 28rpx; color: #909399">当前余额{{ user.money2 || 0 }}</view>
</view>
</view>
</up-radio>
<up-radio :name="1">
<view style="display: flex; align-items: center">
<up-icon name="/static/icon/weixin.png" imgMode="widthFix" size="50rpx" />
<view style="width: 20rpx"></view>
<view>
<view style="font-size: 30rpx; display: flex; align-items: center">
微信支付
<!-- <view style="padding: 4rpx 15rpx; margin-left: 10rpx; border-radius: 25rpx; background-color: #e03737; font-size: 24rpx; color: #fff">
随机立减0.01-20
</view> -->
</view>
<view style="font-size: 28rpx; color: #909399">微信快捷支付</view>
</view>
</view>
</up-radio>
</up-radio-group>
</view>
<view style="height: 100rpx"></view>
<view style="display: flex; justify-content: center; margin-top: 80rpx">
<view class="affirm_btn" @click="payOrder">确认支付</view>
</view>
</view>
</template>
<script setup>
import { payAllinPay, handleSubmit, payMoney } from '@/api/api.js';
import { ref, reactive } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { userHook } from '@/hooks/userInfo.js';
const { user } = userHook();
let orderId = ref('');
let amount = ref(0);
let money = ref(0);
let goodsId = ref(null);
let num = ref(0);
let type = ref(1);
onLoad(async (options) => {
orderId.value = options.id;
amount.value = options.amount;
type.value = options.type;
num.value = options.num;
goodsId.value = options.goodsId;
// let { points2 } = await userInfo({ id });
// money.value = points2;
});
onShow(async () => {
let options = uni.getEnterOptionsSync();
const shop_order_pay_show = uni.getStorageSync('shop_order_pay_show');
let appId = 'wxef277996acc166c3';
if (options.scene == '1038' && options.referrerInfo.appId == appId && shop_order_pay_show == 1) {
uni.setStorageSync('shop_order_pay_show', 0);
// 代表从收银台小程序返回
let extraData = options.referrerInfo.extraData;
if (!extraData) {
// "当前通过物理按键返回,未接收到返参,建议自行查询交易结果";
uni.showModal({
title:'提示',
content:'未检测到支付结果, 您可以查看订单',
confirmText:'查看订单',
success: (res) => {
if(res.confirm){
uni.reLaunch({
url:'/pages/home/home?tabBarShow=1'
})
}
}
})
} else {
if (extraData.code == 'success') {
// "支付成功";
uni.showToast({
title: '支付成功',
icon: 'none'
});
uni.reLaunch({
url:'/pages/home/home?tabBarShow=1'
})
} else if (extraData.code == 'cancel') {
// "支付已取消";
uni.showToast({
title: '支付已取消',
icon: 'none'
});
} else {
// "支付失败:" + extraData.errmsg;
uni.showToast({
title: '支付失败:' + extraData.errmsg,
icon: 'none'
});
}
}
}
});
let dataFrom = reactive({
pay_type: 3
});
let payOrder = async () => {
// let { username } = uni.getStorageSync('user');
// handleSubmit({
// num: num.value,
// goodsId: goodsId.value,
// userName: username
// }).then((res) => {
// uni.reLaunch({
// url: `/pages/home/home?tabBarShow=1`
// });
// });
// return;
let _res;
if (dataFrom.pay_type == 1 || dataFrom.pay_type == 2) {
payAllinPay({ orderId: orderId.value }).then((res) => {
uni.openEmbeddedMiniProgram({
appId: res.appid,
extraData: res.extraData,
success(res) {
// 打开成功
uni.setStorageSync('shop_order_pay_show', 1);
}
});
});
}
if (dataFrom.pay_type == 3) {
// _res = type.value == 1 ? await walletPaymentGoods({ id: orderId.value }) : await walletPaymentPackages({ id: orderId.value });
// uni.redirectTo({
// url: `/pages/order/success?id=${orderId.value}&amount=${_res.amount}&orderNo=${_res.orderNo ? _res.orderNo : ''}&createTime=${_res.createTime ? _res.createTime : ''}`
// });
payMoney({ orderId: orderId.value }).then((res) => {
uni.reLaunch({
url:'/pages/home/home?tabBarShow=1'
})
})
}
return;
// let _res = type.value == 1 ? await walletPaymentGoods({ id: orderId.value }) : await walletPaymentPackages({ id: orderId.value });
};
</script>
<style lang="scss">
.affirm_btn {
width: 650rpx;
height: 78rpx;
background: #4874e5;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 30rpx;
color: #ffffff;
}
</style>

234
pageInvest/shop/shop.vue Normal file
View File

@@ -0,0 +1,234 @@
<template>
<view class="u-wrap">
<view class="u-search-box">
<view class="u-search-inner">
<up-icon name="search" color="#909399" :size="28"></up-icon>
<text class="u-search-text">请输入您需要的商品名称</text>
</view>
</view>
<view class="u-menu-wrap">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop">
<view
v-for="(item, index) in tabbar"
:key="index"
class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']"
:data-current="index"
@tap.stop="swichMenu(index)"
>
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<block v-for="(item, index) in tabbar" :key="index">
<scroll-view scroll-y class="right-box" v-if="current == index">
<view class="page-view">
<view class="class-item">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container">
<view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1">
<image class="item-menu-image" :src="item1.cover" mode=""></image>
<view class="item-menu-name">{{ item1.name }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</block>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { goodsList, categoryList } from '@/api/api.js';
let tabbar = ref([]);
let scrollTop = ref(0);
let current = ref(0);
let menuHeight = ref(0);
let menuItemHeight = ref(0);
// [
// {
// name: '女装',
// foods: [
// {
// name: 'A字裙',
// key: 'A字裙',
// icon: 'https://cdn.uviewui.com/uview/common/classify/1/1.jpg',
// cat: 10
// }
// ]
// }
// ]
onLoad(() => {
categoryList().then((res) => {
tabbar.value = res.map((item, index) => {
return {
...item,
foods: []
};
});
goodsList({ categoryId: res[0].id }).then((res) => {
tabbar.value[0].foods = res;
});
});
});
async function swichMenu(index) {
if (index == current.value) return;
current.value = index;
goodsList({ categoryId: tabbar.value[index].id }).then((res) => {
tabbar.value[index].foods = res;
});
// 如果为0意味着尚未初始化
if (menuHeight.value == 0 || menuItemHeight.value == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('u-tab-item', 'menuItemHeight');
}
// 将菜单菜单活动item垂直居中
this.scrollTop = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2;
}
function getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query
.select('.' + elClass)
.fields({ size: true }, (res) => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
this[dataVal] = res.height;
})
.exec();
});
}
</script>
<style lang="scss" scoped>
.u-wrap {
height: calc(100vh);
/* #ifdef H5 */
height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
}
.u-search-box {
padding: 18rpx 30rpx;
}
.u-menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: $u-tips-color;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
}
.u-tab-item {
height: 80rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: '';
position: absolute;
border-left: 4px solid rgba(111, 162, 86, 1);
height: 45rpx;
left: 0;
top: calc(50% - 22.5rpx);
}
.u-tab-view {
height: 100%;
}
.right-box {
background-color: rgb(250, 250, 250);
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
}
.item-title {
font-size: 26rpx;
color: $u-main-color;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 24rpx;
color: $u-main-color;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 33.333333%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 20rpx;
}
.item-menu-image {
width: 120rpx;
height: 120rpx;
}
</style>

View File

@@ -0,0 +1,172 @@
<template>
<view class="invoice">
<view class="invoice_tip">
<view style="display: flex; align-items: center">
<up-icon name="error-circle-fill" color="#3c9cff"></up-icon>
发票须知
</view>
<view>1.开票金额为用户实际支付金额(不含返利返佣)</view>
<view>2.未寄出的纸质发票会在开票确认后的20个工作日内寄出</view>
<view>3.单笔订单只支持开具一种发票类型</view>
<view>4.云快充仅为平台方实际开票主体以申请开票时展示的开票运营商公司为准</view>
<view>5.发票由各家电站运营商提供一起申请可能会生成多张发票</view>
<view>6.若超过20个工作日仍未收到发票您可以通过(区号)+12366向开票公司所在区域的主管税务机关进行反馈处理</view>
</view>
<view style="height: 20rpx"></view>
<view>
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<up-checkbox-group v-model="checkboxValue1" placement="column" @change="checkboxChange">
<view class="invoice_list" style="margin-bottom: 20rpx" v-for="(item, index) in dataList" :key="index">
<view style="display: flex; align-items: center; font-weight: bold; font-size: 30rpx; margin-bottom: 30rpx">
<up-checkbox shape="circle" :customStyle="{ margin: '0' }" :name="item.id"></up-checkbox>
充电单号{{ item.orderNo }}
</view>
<view style="display: flex; align-items: center; justify-content: space-between; background-color: #f6f6f6; border-radius: 15rpx; padding: 20rpx">
<view style="font-size: 28rpx">
<view style="margin-bottom: 15rpx">即途展厅</view>
<view style="margin-bottom: 15rpx">{{item.electricityAmount}}电费</view>
<view>{{ item.serviceAmount }}服务费</view>
</view>
<view style="text-align: right">
<view style="margin-bottom: 25rpx; font-size: 36rpx; font-weight: bold; color: #4879e6">
{{ item.actuallyAmount }}
<text style="font-size: 30rpx"></text>
</view>
<view style="font-size: 28rpx">个人支付</view>
</view>
</view>
</view>
</up-checkbox-group>
</z-paging>
</view>
<view
style="
position: fixed;
bottom: 0;
left: 0;
width: 750rpx;
padding: 20rpx 50rpx;
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
"
>
<view style="display: flex; align-items: center">
<up-checkbox label="本页全选" v-model:checked="allCel" shape="circle" usedAlone @change="allCheck" :customStyle="{ margin: '0 10rpx 0 0' }"></up-checkbox>
</view>
<view style="width: 230rpx">
<up-button
@click="navTo(`/pageMake/invoice/applyForDay?list=${encodeURIComponent(JSON.stringify(checkboxValue1))}`)"
:customStyle="{ height: '80rpx', width: '230rpx' }"
color="#4879e6"
text="下一步"
shape="circle"
:disabled="checkboxValue1.length == 0"
></up-button>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad, onShow, onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
import { orderList } from '@/api/api.js';
let checkboxValue1 = ref([]);
const dataList = ref([]);
const paging = ref(null);
let allCel = ref(false);
const allCheck = (e) => {
if (e) {
checkboxValue1.value = dataList.value.map((item, index) => {
return item.id;
});
} else {
checkboxValue1.value = [];
}
allCel.value = e;
console.log(e);
};
const queryList = async (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize
};
orderList(params)
.then((res) => {
paging.value.complete(res);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
const checkboxChange = (e) => {
if (e.length == dataList.value.length) {
allCel.value = true;
} else {
allCel.value = false;
}
console.log(e);
};
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
</script>
<style scoped lang="scss">
.invoice {
&_tip {
padding: 20rpx;
font-size: 24rpx;
color: #3c9cff;
background-color: rgba(60, 156, 255, 0.2);
view {
line-height: 40rpx;
}
}
&_list {
padding: 15rpx 30rpx;
background-color: #fff;
&_view {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
margin-bottom: 25rpx;
&_left {
color: #646368;
}
&_right {
color: #262626;
}
}
}
}
</style>

View File

@@ -0,0 +1,115 @@
<template>
<view class="invoice">
<view class="invoice_tip">
<view style="display: flex; align-items: center">
<up-icon name="error-circle-fill" color="#3c9cff"></up-icon>
发票须知
</view>
<view>1.开票金额为用户实际支付金额(不含返利返佣)</view>
<view>2.未寄出的纸质发票会在开票确认后的20个工作日内寄出</view>
<view>3.单笔订单只支持开具一种发票类型</view>
<view>4.云快充仅为平台方实际开票主体以申请开票时展示的开票运营商公司为准</view>
<view>5.发票由各家电站运营商提供一起申请可能会生成多张发票</view>
<view>6.若超过20个工作日仍未收到发票您可以通过(区号)+12366向开票公司所在区域的主管税务机关进行反馈处理</view>
</view>
<view style="height: 20rpx"></view>
<view>
<view class="invoice_list" style="margin-bottom: 20rpx" v-for="(item, index) in dataList" :key="index">
<view style="display: flex; align-items: center; font-weight: bold; font-size: 30rpx; margin-bottom: 30rpx">
<!-- <up-checkbox shape="circle" :customStyle="{ margin: '0' }" :name="item.transactionNo"></up-checkbox> -->
开票运营商{{ item.merchantName }}
</view>
<view style="display: flex; align-items: center; justify-content: space-between; background-color: #f6f6f6; border-radius: 15rpx; padding: 20rpx">
<view style="font-size: 28rpx">
<view style="margin-bottom: 15rpx">{{ item.electricityAmount }}电费</view>
<view>{{ item.serviceAmount }}服务费</view>
</view>
<view style="text-align: right">
<view style="margin-bottom: 25rpx; font-size: 36rpx; font-weight: bold; color: #4879e6">
{{ item.invoiceAmount }}
<text style="font-size: 30rpx"></text>
</view>
<view style="font-size: 28rpx">个人支付</view>
</view>
</view>
</view>
</view>
<view
style="
position: fixed;
bottom: 0;
left: 0;
width: 750rpx;
padding: 20rpx 50rpx;
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
"
>
<view></view>
<!-- <view style="display: flex; align-items: center">
<up-checkbox label="本页全选" v-model:checked="allCel" shape="circle" usedAlone @change="allCheck" :customStyle="{ margin: '0 10rpx 0 0' }"></up-checkbox>
</view> -->
<view style="width: 230rpx">
<up-button
@click="navTo(`/pageMake/invoice/makeInvoice?list=${encodeURIComponent(JSON.stringify(checkboxValue1))}`)"
:customStyle="{ height: '80rpx', width: '230rpx' }"
color="#4879e6"
text="下一步"
shape="circle"
></up-button>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
import { preApply } from '@/api/api.js';
const dataList = ref([]);
let checkboxValue1 = ref([]);
onLoad(async (options) => {
checkboxValue1.value = JSON.parse(decodeURIComponent(options.list));
console.log(checkboxValue1.value);
let _res = await preApply({ ordersIds: JSON.parse(decodeURIComponent(options.list)) });
dataList.value = _res;
});
</script>
<style scoped lang="scss">
.invoice {
&_tip {
padding: 20rpx;
font-size: 24rpx;
color: #3c9cff;
background-color: rgba(60, 156, 255, 0.2);
view {
line-height: 40rpx;
}
}
&_list {
padding: 15rpx 30rpx;
background-color: #fff;
&_view {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
margin-bottom: 25rpx;
&_left {
color: #646368;
}
&_right {
color: #262626;
}
}
}
}
</style>

View File

@@ -0,0 +1,127 @@
<template>
<view class="invoice">
<view class="invoice_tip">
<view style="display: flex; align-items: center">
<up-icon name="error-circle-fill" color="#3c9cff"></up-icon>
温馨提示
</view>
<view>1.云充电仅为平台方实际开票主体以下方展示的开票公司为准</view>
<view>2.若超过20个工作日仍未收到发票您可以通过(区号)+12366向开票公司所在区域的主管税务机关进行反馈处理</view>
</view>
<view style="height: 20rpx"></view>
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view class="invoice_list" v-for="(item, index) in dataList" :key="index">
<view class="invoice_list_view">
<view class="invoice_list_view_left" style="display: flex; align-items: center">
<up-icon name="clock-fill"></up-icon>
{{item.createTime}}
</view>
<up-icon name="arrow-right"></up-icon>
</view>
<view class="invoice_list_view">
<view class="invoice_list_view_left">发票抬头</view>
<view class="invoice_list_view_right">{{item.invoiceTitle}}</view>
</view>
<view class="invoice_list_view">
<view class="invoice_list_view_left">开票运营商</view>
<view class="invoice_list_view_right">{{item.merchantInvoice || '-'}}</view>
</view>
<view style="border: 1px dashed #eee"></view>
<view style="height: 20rpx"></view>
<view style="display: flex; align-items: center; justify-content: space-between">
<view>
<up-tag v-if="item.status == 0" text="待开票" type="warning" plain plainFill></up-tag>
<up-tag v-if="item.status == 1" text="已开票" type="success" plain plainFill></up-tag>
<up-tag v-if="item.status == -1" text="取消" type="error" plain plainFill></up-tag>
</view>
<view style="font-size: 36rpx; font-weight: bold">
{{item.invoiceAmount}}
<text style="font-size: 30rpx"></text>
</view>
</view>
</view>
</z-paging>
<view style="height: 150rpx;"></view>
<view style="position: fixed; bottom: 0; left: 0; width: 750rpx; padding: 20rpx 50rpx; background-color: #fff">
<up-button @click="navTo('/pageMake/invoice/applyFor')" :customStyle="{ height: '80rpx' }" color="#4879e6" text="申请开票" shape="circle"></up-button>
</view>
</view>
</template>
<script setup>
import { onLoad, onShow, onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
import { ref } from 'vue';
const { nav, navTo } = useNav();
import { invoiceList } from '@/api/api.js';
const dataList = ref([]);
const paging = ref(null);
const queryList = async (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize
};
invoiceList(params)
.then((res) => {
paging.value.complete(res);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
</script>
<style scoped lang="scss">
.invoice {
&_tip {
padding: 20rpx;
font-size: 24rpx;
color: #3c9cff;
background-color: rgba(60, 156, 255, 0.2);
view {
line-height: 40rpx;
}
}
&_list {
padding: 15rpx 30rpx;
background-color: #fff;
&_view {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
margin-bottom: 25rpx;
&_left {
color: #646368;
}
&_right {
color: #262626;
}
}
}
}
</style>

View File

@@ -0,0 +1,296 @@
<template>
<view class="invoice">
<view class="invoice_tip">
<view style="display: flex; align-items: center">
<up-icon name="error-circle-fill" color="#3c9cff"></up-icon>
发票须知
</view>
<view>1.开票金额为用户实际支付金额(不含返利返佣)</view>
<view>2.未寄出的纸质发票会在开票确认后的20个工作日内寄出</view>
<view>3.单笔订单只支持开具一种发票类型</view>
<view>4.云快充仅为平台方实际开票主体以申请开票时展示的开票运营商公司为准</view>
<view>5.发票由各家电站运营商提供一起申请可能会生成多张发票</view>
<view>6.若超过20个工作日仍未收到发票您可以通过(区号)+12366向开票公司所在区域的主管税务机关进行反馈处理</view>
</view>
<view style="height: 30rpx"></view>
<view style="padding: 30rpx; font-size: 28rpx; background-color: #fff">
<view class="flex-acsb" style="height: 80rpx">
<view>
发票主体
<text style="color: #f56c6c">*</text>
</view>
<view class="flex-acsb" @click="show2 = true">
<text :style="{ color: !dataFrom.subjectType ? '#808080' : '' }">
{{ !dataFrom.subjectType ? '请选择' : columns2[0].find((val) => val.id == dataFrom.subjectType).label }}
</text>
<up-icon name="arrow-down"></up-icon>
</view>
</view>
<view class="flex-acsb" style="height: 80rpx">
<view>
发票类型
<text style="color: #f56c6c">*</text>
</view>
<view class="flex-acsb" @click="show1True">
<text :style="{ color: !dataFrom.invoiceType ? '#808080' : '' }">
{{ !dataFrom.invoiceType ? '请选择' : columns1[0].find((val) => val.id == dataFrom.invoiceType).label }}
</text>
<up-icon name="arrow-down"></up-icon>
</view>
</view>
<view class="flex-acsb" style="height: 80rpx">
<view>
发票抬头
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.invoiceTitle" placeholder="请输入发票抬头" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx" v-if="dataFrom.subjectType == 1">
<view>
发票税号
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.taxNumber" placeholder="请输入发票税号" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx" v-if="dataFrom.invoiceType == 2">
<view>
公司地址
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.registrationAddress" placeholder="请输入公司地址" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx" v-if="dataFrom.invoiceType == 2">
<view>
公司电话
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.registrationPhone" placeholder="请输入公司电话" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx" v-if="dataFrom.invoiceType == 2">
<view>
开户行名称
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.bankName" placeholder="请输入开户行名称" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx" v-if="dataFrom.invoiceType == 2">
<view>
开户行账号
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.bankAccount" placeholder="请输入开户行账号" style="text-align: right" type="text" />
</view>
</view>
</view>
<view style="height: 30rpx"></view>
<view style="padding: 30rpx; font-size: 28rpx; background-color: #fff">
<view class="flex-acsb" style="height: 80rpx">
<view>
收票人姓名
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.name" placeholder="请输入收票人姓名" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx">
<view>
收票人手机
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.phone" type="number" placeholder="请输入收票人手机" style="text-align: right" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx">
<view>
收票人地址
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.address" placeholder="请输入收票人地址" style="text-align: right" type="text" />
</view>
</view>
<view class="flex-acsb" style="height: 80rpx">
<view>
收票人邮箱
<text style="color: #f56c6c">*</text>
</view>
<view>
<input v-model="dataFrom.email" placeholder="请输入收票人邮箱" style="text-align: right" type="text" />
</view>
</view>
</view>
<view style="height: 30rpx"></view>
<view class="p30">
<view style="font-weight: bold; font-size: 30rpx">发票备注改内容会打印在发票上</view>
<up-textarea v-model="dataFrom.invoiceRemark" placeholder="请输入内容"></up-textarea>
</view>
<view style="height: 150rpx"></view>
<view
style="
position: fixed;
bottom: 0;
left: 0;
width: 750rpx;
padding: 20rpx 50rpx;
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
"
>
<view style="display: flex; align-items: center; font-size: 28rpx">
<text>合计</text>
<text style="font-size: 36rpx; font-weight: bold; margin: 0 15rpx">14.05</text>
<text></text>
</view>
<view style="width: 230rpx">
<up-button @click="applyCon" :customStyle="{ height: '80rpx', width: '230rpx' }" color="#4879e6" text="确认开票" shape="circle"></up-button>
</view>
</view>
<up-picker @confirm="aaa1" keyName="label" :show="show1" @cancel="show1 = false" :columns="columns1"></up-picker>
<up-picker @confirm="aaa2" keyName="label" :show="show2" @cancel="show2 = false" :columns="columns2"></up-picker>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { apply } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
let checkboxValue1 = ref([]);
let dataFrom = ref({
invoiceType: null,
subjectType: null,
ordersIds: []
});
let show1 = ref(false);
let show2 = ref(false);
onLoad(async (options) => {
console.log(options);
console.log(JSON.parse(decodeURIComponent(options.list)));
dataFrom.value.ordersIds = JSON.parse(decodeURIComponent(options.list));
});
const applyCon = async () => {
if (!dataFrom.value.subjectType) return uni.showToast({ title: '请选择发票主体', icon: 'none' });
if (!dataFrom.value.invoiceType) return uni.showToast({ title: '请选择发票类型', icon: 'none' });
if (!dataFrom.value.invoiceType == 1 && !dataFrom.value.taxNumber) return uni.showToast({ title: '请输入发票税号', icon: 'none' });
if (!dataFrom.value.subjectType == 1 && !dataFrom.value.registrationPhone) return uni.showToast({ title: '请输入发票税号', icon: 'none' });
if (!dataFrom.value.subjectType == 1 && !dataFrom.value.invoiceType == 2 && !dataFrom.value.taxNumber) return uni.showToast({ title: '请输入发票税号', icon: 'none' });
if (!dataFrom.value.subjectType == 1 && !dataFrom.value.invoiceType == 2 && !dataFrom.value.registrationAddress)
return uni.showToast({ title: '请输入公司地址', icon: 'none' });
if (!dataFrom.value.subjectType == 1 && !dataFrom.value.invoiceType == 2 && !dataFrom.value.registrationPhone) return uni.showToast({ title: '请输入公司电话', icon: 'none' });
if (!dataFrom.value.subjectType == 1 && !dataFrom.value.invoiceType == 2 && !dataFrom.value.bankName) return uni.showToast({ title: '请输入开户行名称', icon: 'none' });
if (!dataFrom.value.subjectType == 1 && !dataFrom.value.invoiceType == 2 && !dataFrom.value.bankAccount) return uni.showToast({ title: '请输入开户行账户', icon: 'none' });
if (!dataFrom.value.name) return uni.showToast({ title: '请输入收票人姓名', icon: 'none' });
if (!dataFrom.value.address) return uni.showToast({ title: '请输入收票人地址', icon: 'none' });
if (!dataFrom.value.phone) return uni.showToast({ title: '请输入收票人电话', icon: 'none' });
if (!dataFrom.value.email) return uni.showToast({ title: '请输入收票人邮箱', icon: 'none' });
let _res = await apply(dataFrom.value);
uni.navigateBack({
delta: 3
});
};
const aaa1 = (ee) => {
dataFrom.value.invoiceType = ee.value[0].id;
show1.value = false;
console.log(dataFrom.value.invoiceType);
};
const aaa2 = (ee) => {
dataFrom.value.subjectType = ee.value[0].id;
show2.value = false;
if (ee.value[0].id == 2) {
dataFrom.value.invoiceType = 1;
}
};
const show1True = () => {
if (dataFrom.value.subjectType == 2) {
return;
}
show1.value = true;
};
const columns1 = reactive([
[
{
label: '增值税普通发票',
id: 1
},
{
label: '增值税专用发票',
id: 2
}
]
]);
const columns2 = reactive([
[
{
label: '企业',
id: 1
},
{
label: '个人',
id: 2
}
]
]);
const checkboxChange = (e) => {
console.log(e);
};
</script>
<style>
page {
background-color: #f5f5f5;
}
</style>
<style scoped lang="scss">
.invoice {
&_tip {
padding: 20rpx;
font-size: 24rpx;
color: #3c9cff;
background-color: rgba(60, 156, 255, 0.2);
view {
line-height: 40rpx;
}
}
&_list {
padding: 15rpx 30rpx;
background-color: #fff;
&_view {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
margin-bottom: 25rpx;
&_left {
color: #646368;
}
&_right {
color: #262626;
}
}
}
}
</style>

View File

@@ -0,0 +1,83 @@
<template>
<view class="p30">
<view style="font-size: 36rpx; font-weight: bold; margin-top: 40rpx">
退款信息
<text style="font-size: 26rpx; color: chocolate; font-weight: 500">活动金额不在退款范围内</text>
</view>
<view style="display: flex; align-items: center; height: 100rpx; justify-content: space-between">
<view></view>
<input v-model="dataFrom.amount" :placeholder="`可申请退款${balance}元`" style="width: 500rpx; font-size: 32rpx" type="number" />
<view @click="dataFrom.amount = balance" style="font-size: 28rpx; color: #4879e6">全部</view>
</view>
<view style="font-size: 28rpx; margin-bottom: 20rpx">申请退款理由</view>
<view style="margin-bottom: 30rpx">
<up-textarea v-model="dataFrom.refundReason" placeholder="请输入退款理由"></up-textarea>
</view>
<view style="font-weight: bold; font-size: 30rpx; margin-bottom: 20rpx">退款须知</view>
<view style="font-size: 26rpx; color: #60646b; line-height: 50rpx">1.退款金额不包含充值时使用的第三方优惠抵扣金额退款时充值享受到的优惠金额也将全部扣除</view>
<view style="font-size: 26rpx; color: #60646b; line-height: 50rpx">2.您的退款金额到账时间由各充值渠道微信/支付宝决定请耐心等待约1~3工作日到账</view>
<view style="font-size: 26rpx; color: #60646b; line-height: 50rpx">3.退款按照充值记录进行逐笔退款一次申请可能产生多笔退款到账记录请注意查收</view>
<view style="font-size: 26rpx; color: #60646b; line-height: 50rpx">4.正在充电或存在异常订单时无法进行退款操作</view>
<view style="font-size: 26rpx; color: #60646b; line-height: 50rpx">5.根据各充值渠道规则只可退一年内的充值金额</view>
<view style="position: fixed; bottom: 0; left: 0; width: 750rpx; padding: 20rpx 30rpx; border-top: 1rpx solid #eee" class="flex-acsb">
<view style="width: 230rpx">
<!-- openType="contact" -->
<up-button @click="toKft" :customStyle="{ height: '80rpx' }" text="联系客服" shape="circle"></up-button>
</view>
<view style="width: 400rpx">
<up-button @click="refundTo" :customStyle="{ height: '80rpx' }" color="#4879e6" text="提交" shape="circle"></up-button>
</view>
</view>
</view>
</template>
<script>
import { refund } from '@/api/api.js';
export default {
data() {
return {
balance: 0,
dataFrom: {
amount: '',
refundReason: ''
}
};
},
onLoad(options) {
if (options.balance) {
this.balance = options.balance;
}
},
methods: {
toKft() {
uni.makePhoneCall({
phoneNumber: '4008005326' //仅为示例
});
},
refundTo() {
if (!this.dataFrom.amount) {
return uni.showToast({
title: '请输入退款金额',
icon: 'none'
});
}
refund(this.dataFrom).then((res) => {
uni.showModal({
title: '提示',
content: '提交成功',
showCancel: false,
success: function (res) {
uni.navigateBack();
}
});
});
}
}
};
</script>
<style>
page {
background-color: #fff;
}
</style>

View File

@@ -0,0 +1,285 @@
<template>
<view class="recharge">
<view class="recharge_orderId">
<view>
订单号{{ store.state.dataObj.orderNo }}
<image src="/static/icon/ic-copy1.png" @click="copy(store.state.dataObj.orderNo)" mode="widthFix"></image>
</view>
</view>
<view class="recharge_trn">
<view class="recharge_trn_yuan">
<image class="recharge_trn_yuan_img" src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/bg_charging_turn.png" mode="widthFix"></image>
</view>
<image class="recharge_trn_hei" src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-charging-black-circle.png" mode="widthFix"></image>
<view class="recharge_trn_text">
<view>{{ store.state.dataObj.currentAmount || 0 }}</view>
<view>已用时长</view>
<view>{{ store.state.dataObj.cumulativeTime || 0 }}min</view>
</view>
<view class="recharge_trn_car">
<image class="recharge_trn_car_img" src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-real-time-car-bg.png" mode="widthFix"></image>
<image class="recharge_trn_car_img1" src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-real-time-car-bg1.png" mode="widthFix"></image>
</view>
</view>
<view class="recharge_list p30">
<view class="recharge_list_view">
<image src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-real-time-charged-power.png" mode="widthFix"></image>
<view class="recharge_list_view_num">{{ store.state.dataObj.chargingDegree || 0 }}</view>
<view class="recharge_list_view_name">已充电量()</view>
</view>
<view class="recharge_list_view">
<image src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-real-time-charged-time.png" mode="widthFix"></image>
<view class="recharge_list_view_num">{{ store.state.dataObj.cumulativeTime || 0 }}min</view>
<view class="recharge_list_view_name">已充时长</view>
</view>
<view class="recharge_list_view">
<image src="https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-real-time-charged-amount.png" mode="widthFix"></image>
<view class="recharge_list_view_num">{{ store.state.dataObj.currentAmount || 0 }}</view>
<view class="recharge_list_view_name">已充金额()</view>
</view>
</view>
<view class="recharge_block p30">
<view class="recharge_block_view">
<view>{{ store.state.dataObj.outputVoltage || 0 }}</view>
<view>实时电压(V)</view>
</view>
<view class="recharge_block_view">
<view>{{ store.state.dataObj.outputCurrent || 0 }}</view>
<view>实时电流(A)</view>
</view>
<view class="recharge_block_view">
<view>{{ store.state.dataObj.power || 0 }}</view>
<view>实时功率(KW)</view>
</view>
</view>
<view class="recharge_note p30">
<view>终端名称{{ store.state.dataObj.gunNo }}</view>
<view>终端编码{{ store.state.dataObj.deviceNo || '' }}</view>
</view>
<view class="recharge_btn1" @click="end(1)">结束充电</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { stopCharging, realtimeInfo, ordersInfo } from '@/api/api.js';
import { copy } from '@/utils/fun.js';
import store from '@/store/index.js';
let transactionNo = ref('');
let type = ref('');
onLoad(async (options) => {
transactionNo.value = options.transactionNo;
if (options.type) {
let _res = await realtimeInfo({
transactionNo: options.transactionNo
});
store.commit('setDataObj', _res);
}
});
const end = (e) => {
uni.showModal({
title: '提示',
content: e == 1 ? '是否确认结束充电?' : '结束充电失败,请重试!',
success: function (res) {
if (res.confirm) {
stopCharging({ transactionNo: transactionNo.value }).then((res) => {
uni.showLoading({
title: '停止充电中...'
});
store.commit('setSokStatus', 0);
timeMap(transactionNo.value);
});
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
const timeMap = (_res) => {
var time = setTimeout(async () => {
if (store.state.sokStatus != 1) {
let _data = await ordersInfo({
transactionNo: _res
});
store.commit('setDataObj', _data);
if (_data.status == 3 || _data.status == 4) {
uni.hideLoading();
end(2);
}
if (_data.status == 5 || _data.status == 6) {
uni.hideLoading();
uni.navigateBack();
store.commit('setSokStatus', 0);
}
}
}, 30000);
};
</script>
<style>
page {
background-color: #000;
}
</style>
<style scoped lang="scss">
.recharge {
&_orderId {
width: 1000rpx;
margin-left: -125rpx;
margin-top: -20rpx;
height: 230rpx;
background: url(https://zhongshuai-prod.oss-cn-beijing.aliyuncs.com/appImage/order/order-realtime-pile-number-bg.png) no-repeat 100% 100% / contain;
color: #828282;
text-align: center;
padding-top: 30rpx;
font-size: 26rpx;
view {
@include flex($space: center);
image {
width: 30rpx;
height: 30rpx;
margin-left: 15rpx;
}
}
}
&_trn {
margin-top: -130rpx;
@include flex($direction: column, $space: center);
&_yuan {
width: 500rpx;
height: 500rpx;
position: relative;
&_img {
width: 100%;
height: 100%;
animation: rotate 5s linear infinite;
}
}
&_text {
z-index: 9;
@include flex($direction: column, $space: center);
margin-top: -470rpx;
view:nth-child(1) {
color: #fff;
font-weight: bold;
font-size: 60rpx;
}
view:nth-child(2) {
color: #11927c;
font-size: 28rpx;
margin: 25rpx 0 15rpx;
}
view:nth-child(3) {
color: #24efe8;
font-weight: bold;
font-size: 36rpx;
margin-bottom: 30rpx;
}
}
&_hei {
margin-top: -360rpx;
width: 500rpx;
height: 500rpx;
z-index: 9;
}
&_car {
z-index: 10;
width: 450rpx;
position: relative;
&_img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
&_img1 {
width: 100%;
height: 100%;
}
}
}
&_list {
@include flex($space: space-between);
padding: 0 50rpx;
&_view {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
@include flex($direction: column, $space: center);
image {
width: 75rpx;
height: 75rpx;
}
&_num {
color: #fff;
font-weight: bold;
font-size: 36rpx;
margin: 10rpx 0;
}
&_name {
color: #8b8b8b;
font-weight: bold;
font-size: 28rpx;
}
}
}
&_block {
margin-top: 50rpx;
@include flex($space: space-between);
&_view {
width: 200rpx;
padding: 10rpx;
border-radius: 25rpx;
background: linear-gradient(0deg, #0b1521, #193c65);
font-size: 28rpx;
@include flex($direction: column, $space: center);
view:nth-child(1) {
color: #fff;
}
view:nth-child(2) {
color: #8b98a0;
}
}
}
&_note {
margin-top: 30rpx;
@include flex($space: space-between);
color: #828282;
font-size: 24rpx;
}
&_btn1 {
width: 650rpx;
height: 100rpx;
margin: 0 auto;
font-size: 32rpx;
font-weight: bold;
@include flex($space: center);
background-color: #1879fe;
border-radius: 50rpx;
color: #fff;
margin-top: 150rpx;
}
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>

379
pages.json Normal file
View File

@@ -0,0 +1,379 @@
{
"easycom": {
"autoscan": true,
// 注意一定要放在custom里否则无效https://ask.dcloud.net.cn/question/131175
"custom": {
"^u--(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue"
}
},
"pages": [ //pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/home/home",
"style": {
"navigationBarTitleText": "电小芮",
"enablePullDownRefresh": false
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/mine/mine",
"style": {
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false
}
},
{
"path": "pages/order/order",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/sweep/sweep",
"style": {
"navigationBarTitleText": "扫码充电",
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/order/detail",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/home/detail",
"style": {
"navigationBarTitleText": "电站详情",
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/home/star",
"style": {
"navigationBarTitleText": "开始充电"
}
},
{
"path": "pages/mine/earnings",
"style": {
"navigationBarTitleText": "收益"
}
},
{
"path": "pages/mine/sett",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/mine/incomeList",
"style": {
"navigationBarTitleText": "余额明细"
}
},
{
"path": "pages/mine/card",
"style": {
"navigationBarTitleText": "我的电卡"
}
},
{
"path": "pages/mine/cardList",
"style": {
"navigationBarTitleText": "电卡记录"
}
},
{
"path": "pages/money/recharge",
"style": {
"navigationBarTitleText": "充值"
}
},
{
"path": "pages/agreement/agreement",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/mine/car/car",
"style": {
"navigationBarTitleText": "我的爱车"
}
},
{
"path": "pages/mine/car/add",
"style": {
"navigationBarTitleText": "绑定爱车"
}
},
{
"path": "pages/find/find",
"style": {
"navigationBarTitleText": "电小芮"
}
},
{
"path": "pages/find/myArticle",
"style": {
"navigationBarTitleText": "我的文章"
}
},
{
"path": "pages/find/detail",
"style": {
"navigationBarTitleText": "详情"
}
},
{
"path": "pages/mine/multipleNumbers",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/bank/bank",
"style": {
"navigationBarTitleText": "银行卡"
}
},
{
"path": "pages/bank/addBankCard",
"style": {
"navigationBarTitleText": "添加银行卡"
}
},
{
"path": "pages/mine/signIn",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/find/add",
"style": {
"navigationBarTitleText": "发布"
}
},
{
"path": "pages/protocol/buy",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/protocol/trusteeship",
"style": {
"navigationBarTitleText": "发布"
}
}
],
"subPackages": [{
"root": "pageOrder",
"pages": [{
"path": "recharge/recharge",
"style": {
"navigationBarTitleText": "充电中",
"navigationBarBackgroundColor": "#000",
"navigationBarTextStyle": "white",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
}]
}, {
"root": "pageMake",
"pages": [{
"path": "invoice/invoice",
"style": {
"navigationBarTitleText": "开票记录"
}
},
{
"path": "invoice/applyFor",
"style": {
"navigationBarTitleText": "申请开票"
}
},
{
"path": "invoice/makeInvoice",
"style": {
"navigationBarTitleText": "申请开票"
}
},
{
"path": "invoice/applyForDay",
"style": {
"navigationBarTitleText": "申请开票"
}
},
{
"path": "refund/refund",
"style": {
"navigationBarTitleText": "退款申请"
}
}
]
}, {
"root": "pageInvest",
"pages": [{
"path": "shop/shop",
"style": {
"navigationBarTitleText": "商城"
}
},
{
"path": "facility/facility",
"style": {
"navigationBarTitleText": "我的充电桩"
}
},
{
"path": "login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
},
{
"path": "login/register",
"style": {
"navigationBarTitleText": "注册",
"navigationStyle": "custom"
}
},
{
"path": "login/getBack",
"style": {
"navigationBarTitleText": "找回密码",
"navigationStyle": "custom"
}
},
{
"path": "login/getBackAccout",
"style": {
"navigationBarTitleText": "找回账号",
"navigationStyle": "custom"
}
},
{
"path": "shop/details",
"style": {
"navigationBarTitleText": "商品详情"
}
},
{
"path": "shop/affirm",
"style": {
"navigationBarTitleText": "确认订单"
}
},
{
"path": "shop/pay",
"style": {
"navigationBarTitleText": "订单支付"
}
},
{
"path": "shop/order",
"style": {
"navigationBarTitleText": "订单列表"
}
},
{
"path": "money/wallet",
"style": {
"navigationBarTitleText": "余额"
}
},
{
"path": "money/withdraw",
"style": {
"navigationBarTitleText": "提现"
}
},
{
"path": "money/recharge",
"style": {
"navigationBarTitleText": "充值"
}
}
]
}],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#fff"
},
"uniIdRouter": {}
// "tabBar": {
// "color": "#999999",
// "selectedColor": "#999999",
// "borderStyle": "black",
// "backgroundColor": "#ffffff",
// "height": "60px",
// "list": [
// {
// "pagePath": "pages/home/home",
// "text": "首页"
// }, {
// "pagePath": "pages/index/index",
// "text": "地图"
// }, {
// "pagePath": "pages/sweep/sweep",
// "text": "扫码充电"
// }, {
// "pagePath": "pages/find/find",
// "text": "发现"
// }, {
// "pagePath": "pages/mine/mine",
// "text": "我的"
// }]
// }
}

View File

@@ -0,0 +1,21 @@
<template>
<view class="p30">
<mp-html :content="info.protocolContent" />
<view style="height: 100rpx;"></view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { selectProtocolInfo } from '@/api/api.js';
let info = ref({});
onLoad(async (options) => {
let _res = await selectProtocolInfo({ id: options.id });
info.value = _res;
});
</script>
<style></style>

137
pages/bank/addBankCard.vue Normal file
View File

@@ -0,0 +1,137 @@
<template>
<view class="addBankCard p30">
<view style="height: 30rpx"></view>
<view>
<view class="addBankCard_input_tit">请输入{{ enterprise.role == 1 ? '姓名' : '企业名称' }}</view>
<view class="addBankCard_input">
<up-input :border="false" placeholder="请输入" v-model="enterprise.realname"></up-input>
</view>
<!-- <view v-if="enterprise.type == 2">
<view class="addBankCard_input_tit">请输入纳税人识别号</view>
<view class="addBankCard_input">
<up-input :border="false" placeholder="请输入" v-model="enterprise.taxNo"></up-input>
</view>
</view> -->
<view v-if="enterprise.role == 1">
<view class="addBankCard_input_tit">请输入手机号</view>
<view class="addBankCard_input">
<up-input :border="false" placeholder="请输入" v-model="enterprise.mobile"></up-input>
</view>
</view>
<view v-if="enterprise.role == 1">
<view class="addBankCard_input_tit">请输入身份证号</view>
<view class="addBankCard_input">
<up-input :border="false" placeholder="请输入" v-model="enterprise.idcard"></up-input>
</view>
</view>
<!--
<view class="addBankCard_input_tit">请输入开户行名称</view>
<view class="addBankCard_input">
<up-input :border="false" placeholder="请输入" v-model="enterprise.bankName"></up-input>
</view> -->
<view class="addBankCard_input_tit" v-if="enterprise.role == 2">请输入开户行</view>
<view class="addBankCard_input" v-if="enterprise.role == 2">
<up-input :border="false" placeholder="请输入" v-model="enterprise.subname"></up-input>
</view>
<view class="addBankCard_input_tit">请输入银行卡卡号</view>
<view class="addBankCard_input">
<up-input :border="false" placeholder="请输入" v-model="enterprise.num"></up-input>
</view>
</view>
<view style="margin: 30rpx 0">
<view style="font-size: 28rpx; color: coral">请仔细核对信息填写错误会导致提现失败</view>
</view>
<view style="display: flex; justify-content: center">
<view class="addBankCard_btn" @click="addBank">确定</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { addUsersAccountInfo, smsCode } from '@/api/api.js';
let tips = ref('');
let uCode = ref(null);
let codeChange2 = (text) => {
tips.value = text;
};
let enterprise = reactive({
role: 1
});
onLoad((options) => {
enterprise.role = options.role;
});
let getCode2 = () => {
if (!enterprise.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' });
if (uCode.value.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: '正在获取验证码'
});
smsCode({
phone: enterprise.phone
}).then((res) => {
uni.hideLoading();
uni.$u.toast('验证码已发送');
uCode.value.start();
});
} else {
uni.$u.toast('倒计时结束后再发送');
}
};
let addBank = async () => {
// if (enterprise.type == 2) {
// enterprise.taxNo = '';
// enterprise.bankName = '';
// } else {
// enterprise.bankName = '';
// }
let _res = await addUsersAccountInfo(enterprise);
uni.showToast({ title: '添加成功', icon: 'none' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
};
</script>
<style scoped lang="scss">
.addBankCard {
// @include flex();
&_input {
width: 690rpx;
height: 70rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
@include flex;
margin-bottom: 30rpx;
padding: 0 30rpx;
&_tit {
width: 100%;
font-weight: bold;
font-size: 26rpx;
color: #232323;
margin-bottom: 20rpx;
}
}
&_btn {
width: 488rpx;
height: 86rpx;
background: #4874e5;
border-radius: 44rpx 44rpx 44rpx 44rpx;
@include flex($space: center);
font-weight: bold;
font-size: 28rpx;
color: #ffffff;
}
}
</style>

127
pages/bank/bank.vue Normal file
View File

@@ -0,0 +1,127 @@
<template>
<view class="bankCard">
<z-paging ref="paging" v-model="dataList" @query="queryList">
<view class="p30">
<view class="bankCard_add" @click="addBank">
<up-icon name="plus" color="#333" size="28"></up-icon>
<view style="font-size: 26rpx; color: #333; margin-top: 15rpx">添加银行卡</view>
</view>
</view>
<view style="height: 30rpx"></view>
<view v-for="(item, index) in dataList" :key="index" @click="bankSele(item)">
<view class="p30">
<view style="background-color: #ffffff; border-radius: 12rpx; padding: 20rpx; margin-bottom: 20rpx">
<view class="u-flex u-flex-y-center" style="font-size: 28rpx">
<view>
<u-tag :text="item.role == 1 ? '个人' : '企业'" size="mini" :type="item.role == 1 ? 'success' : 'error'" plain plainFill></u-tag>
</view>
<view style="width: 30rpx"></view>
<view style="font-size: 26rpx">{{ item.realname }}</view>
<view style="width: 30rpx"></view>
<view style="font-size: 26rpx">{{ item.mobile || '' }}</view>
</view>
<view style="height: 20rpx"></view>
<view style="color: #232323">
<!-- <view style="font-size: 28rpx">开户行{{ item.bankName }}</view>
<view style="height: 10rpx"></view> -->
<view style="font-size: 28rpx" v-if="item.role == 2">开户行{{ item.subname }}</view>
<view style="height: 10rpx"></view>
<view style="font-size: 28rpx">银行卡号{{ item.num }}</view>
<view style="height: 10rpx"></view>
<!-- <view style="font-size: 28rpx" v-if="item.type == 2 && item.taxNo">纳税人识别号{{ item.taxNo}}</view>
<view style="height: 10rpx"></view> -->
</view>
</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { getUsersAccountInfo } from '@/api/api.js';
import { onShow, onLoad } from '@dcloudio/uni-app';
const paging = ref(null);
let dataList = ref([]);
let numiNDE = ref(1);
let role = ref('');
const type = ref("");
onShow(() => {
if (numiNDE.value != 1) {
paging.value.reload();
}
numiNDE.value++;
});
onLoad((options) => {
type.value = options.type;
});
let addBank = () => {
uni.showActionSheet({
itemList: ['个人', '企业'],
success: (res) => {
if(res.tapIndex + 1 == 0){
console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
}else{
uni.navigateTo({
url: `/pages/bank/addBankCard?role=${res.tapIndex + 1}`
});
}
},
fail: function (res) {
console.log(res.errMsg);
}
});
};
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize
};
getUsersAccountInfo(params)
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
function maskCardNumber(cardNumber) {
if (!cardNumber || typeof cardNumber !== 'string') {
throw new Error('Invalid card number');
}
const sanitizedNumber = cardNumber.replace(/\D/g, '');
if (sanitizedNumber.length < 4) {
throw new Error('Card number is too short');
}
const lastFourDigits = sanitizedNumber.slice(-4);
const maskedNumber = '*'.repeat(sanitizedNumber.length - 4) + lastFourDigits;
return maskedNumber;
}
let bankSele = (e) => {
if (type.value) {
uni.$emit('bank', e);
uni.navigateBack();
}
};
</script>
<style scoped lang="scss">
.bankCard {
&_add {
width: 690rpx;
height: 174rpx;
background: #eeeeee;
border-radius: 16rpx 16rpx 16rpx 16rpx;
@include flex($direction: column, $space: center);
margin-top: 30rpx;
}
}
</style>

199
pages/find/add.vue Normal file
View File

@@ -0,0 +1,199 @@
<template>
<view class="findAdd">
<view class="findAdd_info">
<view style="display: flex; align-items: center; border-bottom: 1rpx solid #eee; padding-bottom: 25rpx">
<view style="margin-right: 25rpx; font-size: 30rpx">标题</view>
<view style="flex: 1">
<up-input height="200" border="none" v-model="formData.title" placeholder="请输入标题"></up-input>
</view>
</view>
<up-textarea height="200" border="none" :maxlength="-1" v-model="formData.content" placeholder="请输入您想要发布的图文"></up-textarea>
<up-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple :maxCount="9"></up-upload>
<view style="font-size: 24rpx; font-weight: bold; margin: 25rpx 0">#添加话题</view>
<view class="findAdd_info_list">
<view
v-for="(item, index) in formData.topic"
:key="index"
class="findAdd_info_list_view"
:style="{
backgroundColor: item.color
}"
>
{{ item.name }}
</view>
<view class="findAdd_info_list_view" style="background-color: rgba(111, 162, 86, 0.1)" @click="addTopic">
<up-icon name="plus" size="10"></up-icon>
</view>
</view>
</view>
<button class="confirm-button" @click="submit">发布</button>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { articleAdd, articleDetails, articleUpdate } from '@/api/api.js';
import { uploadFiles } from '@/utils/fun.js';
import { onLoad } from '@dcloudio/uni-app';
let formData = ref({
title: '',
content: '',
topic: [],
detailsImageUrl: '',
category: 'DISCOVERY',
isPublished: 1
});
const fileList1 = ref([]);
onLoad((options) => {
if(options.id){
getDetail(options.id);
}
});
const getDetail = async (id) => {
let _res = await articleDetails({ id });
formData.value = _res;
if(_res.detailsImageUrl){
const imagesUrlArr = _res.detailsImageUrl.split(",")
fileList1.value = imagesUrlArr.map(item => ({url:item}))
}
};
const submit = () => {
formData.value.detailsImageUrl = fileList1.value
.map((item, index) => {
return item.url;
})
.join(',');
formData.value.coverImageUrl = fileList1.value[0].url;
const apiFun = {
add: articleAdd,
edit: articleUpdate
}
apiFun[formData.value.id ? "edit" : "add"](formData.value).then((res) => {
uni.showModal({
title: '提示',
content: '发布成功',
showCancel: false,
success: (res) => {
if (res.confirm) {
uni.navigateBack();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
});
};
const addTopic = () => {
uni.showModal({
title: '添加话题',
editable: true,
placeholderText: '请输入话题',
success: function (res) {
if (res.confirm) {
formData.value.topic.push({
color: getRandomLightColor(),
name: res.content
});
console.log(res);
} else if (res.cancel) {
}
}
});
};
const lightColors = [
'rgba(210, 180, 222, 0.1)',
'rgba(173, 216, 230, 0.1)',
'rgba(255, 182, 193, 0.1)',
'rgba(152, 251, 152, 0.1)',
'rgba(240, 230, 140, 0.1)',
'rgba(216, 191, 216, 0.1)',
'rgba(175, 238, 238, 0.1)',
'rgba(255, 160, 122, 0.1)',
'rgba(221, 160, 221, 0.1)',
'rgba(144, 238, 144, 0.1)'
];
// 从数组中随机返回一个颜色的函数
function getRandomLightColor() {
const randomIndex = Math.floor(Math.random() * lightColors.length);
return lightColors[randomIndex];
}
// 删除图片
const deletePic = (event) => {
fileList1.value.splice(event.index, 1);
};
// 新增图片
const afterRead = async (event) => {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file);
let fileListLen = fileList1.value.length;
lists.map((item) => {
fileList1.value.push({
...item,
status: 'uploading',
message: '上传中'
});
});
for (let i = 0; i < lists.length; i++) {
const result = await uploadFiles(lists[i].url);
let item = fileList1.value[fileListLen];
fileList1.value.splice(fileListLen, 1, {
...item,
status: 'success',
message: '',
url: result
});
fileListLen++;
}
};
</script>
<style lang="scss">
.findAdd {
padding: 25rpx;
&_info {
width: 100%;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
padding: 36rpx;
&_list {
display: flex;
flex-wrap: wrap;
&_view {
margin-right: 20rpx;
margin-bottom: 20rpx;
padding: 8rpx 30rpx;
font-size: 24rpx;
border-radius: 28rpx 28rpx 28rpx 28rpx;
min-width: 132rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.confirm-button {
width: 488rpx;
height: 86rpx;
background: #6fa256;
border-radius: 44rpx 44rpx 44rpx 44rpx;
font-size: 26rpx;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
margin-top: 332rpx;
}
</style>

120
pages/find/detail.vue Normal file
View File

@@ -0,0 +1,120 @@
<template>
<view class="detail-container">
<view class="top-area">
<view class="picture">
<up-avatar size="60rpx" :src="detailData.authorUrl" />
</view>
<view class="info">
<view>
{{ detailData.authorName }}
</view>
<view class="time">
{{ detailData.publishTime }}
</view>
</view>
<view class="look">
<image src="/static/icon/icon-eye.png"></image>{{ detailData.pageView }}
</view>
</view>
<view class="title">
{{ detailData.title }}
</view>
<view class="content">
{{ detailData.content }}
</view>
<view class="img-area" v-for="(item, index) in detailData?.detailsImageUrl?.split(',')" :key="index">
<image mode="widthFix" :src="item"></image>
</view>
<view class="tags-area">
<view
class="tag-item"
v-for="(item, index) in detailData?.topic"
:key="index"
:style="{
backgroundColor: item.color
}"
>
{{ item.name }}
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { articleDetails } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
const detailData = ref()
onLoad((options) => {
getDetail(options.id);
});
const getDetail = async (id) => {
let _res = await articleDetails({ id });
detailData.value = _res;
};
</script>
<style scoped lang="scss">
.detail-container {
padding: 28rpx 30rpx;
.top-area {
display: flex;
font-weight: bold;
font-size: 24rpx;
color: #232323;
.info {
margin-left: 12rpx;
}
.look {
margin-left: 36rpx;
padding-top: 32rpx;
display: flex;
align-items: center;
image {
width: 28rpx;
height: 28rpx;
margin-right: 4rpx;
}
}
}
.title {
font-weight: bold;
font-size: 36rpx;
color: #232323;
margin-top: 40rpx;
}
.content {
margin-top: 24rpx;
font-weight: bold;
font-size: 20rpx;
color: #232323;
}
.img-area {
margin-top: 24rpx;
image {
width: 100%;
}
}
.tags-area {
display: flex;
flex-wrap: wrap;
margin-top: 36rpx;
.tag-item {
height: 48rpx;
line-height: 48rpx;
background: #6FA256;
border-radius: 24rpx;
font-weight: bold;
font-size: 20rpx;
color: #000;
padding: 0 28rpx;
margin-right: 24rpx;
margin-bottom: 24rpx;
}
}
}
</style>

122
pages/find/find.vue Normal file
View File

@@ -0,0 +1,122 @@
<template>
<view style="padding: 20rpx 30rpx">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view style="display: flex; flex-wrap: wrap; justify-content: space-between; width: 100%">
<view v-for="(item, index) in dataList" :key="index" style="width: 336rpx; background-color: #fff; border-radius: 8rpx 8rpx">
<image :src="item.coverImageUrl" style="width: 336rpx; height: 368rpx; border-radius: 8rpx 8rpx 0 0" mode="aspectFill"></image>
<view style="padding: 15rpx 15rpx 0; font-size: 24rpx">{{ item.title }}</view>
<view style="display: flex; align-items: center; padding: 15rpx; border-radius: 0 0 8rpx 8rpx; font-size: 24rpx">
<image :src="item.authorUrl" style="width: 48rpx; height: 48rpx; border-radius: 50%; margin-right: 20rpx"></image>
<view>{{ item.authorName }}</view>
</view>
</view>
</view>
</z-paging>
<view
style="
width: 108rpx;
height: 108rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
bottom: 300rpx;
right: 30rpx;
background: #ffffff;
border-radius: 50%;
font-size: 24rpx;
"
@click="navTo('/pages/find/add')"
>
<image src="/static/image/fawen.png" style="width: 48rpx; height: 48rpx"></image>
<view>发文</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue';
import { getMerchantSelect } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
const { navTo } = useNav();
onLoad(() => {});
const paging = ref(null);
const dataList = ref([]);
const queryList = async (pageNo, pageSize) => {
getMerchantSelect({
current: pageNo,
pageSize: pageSize,
category: 'DISCOVERY'
})
.then((res) => {
paging.value.complete(res.records);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
const column = ref(2);
function loaded() {
console.log('加载完成');
}
function wapperClick(item) {
console.log('单项点击事件', item);
}
function imageClick(item) {
console.log('图片点击事件', item);
}
const waterfallsFlowRef = ref(null);
</script>
<style>
page {
background-color: #f2f5f9;
}
</style>
<style lang="scss" scoped>
.handle {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 20rpx;
padding: 10rpx;
.btn {
margin: 20rpx 10rpx;
padding: 0 20rpx;
background: #2878ff;
font-size: 28rpx;
color: #fff;
&::after {
border: 0;
}
}
}
.item {
padding: 10rpx 10rpx 20rpx;
background: #fff;
.title {
line-height: 48rpx;
font-size: 28rpx;
color: #222;
}
.desc {
font-size: 24rpx;
color: #666;
}
}
</style>

186
pages/find/myArticle.vue Normal file
View File

@@ -0,0 +1,186 @@
<template>
<!-- 我的文章 -->
<view class="my-article">
<view class="top">
<view class="picture">
<up-avatar size="180rpx" :src="info.avatar" />
</view>
<view class="nickname">
{{ info.nickName }}
</view>
<view class="btn-area" @click="toPublish">
<image src="/static/icon/publish-article.png"></image>
<view class="btn-text">发文</view>
</view>
</view>
<z-paging ref="paging" v-model="listData" use-page-scroll @query="queryList">
<view class="list-area">
<view class="list-item" v-for="(item, index) in listData" :key="index" @click="goDetail(item)">
<view class="list-item-img">
<image :src="item.coverImageUrl"></image>
</view>
<view class="list-item-btm">
<view class="list-title">
{{ item.content }}
</view>
<view class="list-btn-area">
<view class="bottom-btn" @click.stop="goDelete(item)">
<image src="/static/icon/icon-delete.png"></image>
<text class="btn-text">删除</text>
</view>
<view class="bottom-btn ml16" @click.stop="goEdit(item)">
<image src="/static/icon/icon-eidt.png"></image>
<text class="btn-text">编辑</text>
</view>
</view>
</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { getUserArticleList, userInfo, articleDelete } from '@/api/api.js';
import { onShow } from '@dcloudio/uni-app';
const info = ref({});
const paging = ref(null);
const listData = ref()
onMounted(async () => {
const res = await userInfo();
info.value = res;
});
onShow(() => {
paging.value && paging.value.reload();
})
const queryList = async (pageNo, pageSize) => {
getUserArticleList()
.then((res) => {
paging.value.complete(res);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
const toPublish = () => {
uni.navigateTo({
url: `/pages/find/add`
});
}
const goDelete = item => {
articleDelete([Number(item.id)])
.then((res) => {
paging.value.reload();
});
}
const goEdit = item => {
uni.navigateTo({
url: `/pages/find/add?id=${item.id}`
});
}
const goDetail = item => {
uni.navigateTo({
url: `/pages/find/detail?id=${item.id}`
});
}
</script>
<style scoped lang="scss">
.my-article {
.top {
height: 342rpx;
background: #FFFFFF;
position: relative;
.picture {
padding-top: 40rpx;
display: flex;
justify-content: center;
}
.nickname {
font-weight: bold;
font-size: 40rpx;
color: #232323;
margin-top: 20rpx;
text-align: center;
}
.btn-area {
position: absolute;
top: 40rpx;
right: 40rpx;
padding: 0 12rpx;
image {
width: 40rpx;
height: 40rpx;
}
.btn-text {
font-weight: bold;
font-size: 20rpx;
color: #232323;
}
}
}
.list-area {
padding: 28rpx 30rpx;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.list-item {
background: #fff;
border-radius: 8rpx;
width: 336rpx;
margin-bottom: 24rpx;
&-img {
height: 370rpx;
background: #fff;
border-radius: 8rpx 8rpx 0 0;
image {
width: 336rpx;
height: 370rpx;
}
}
&-btm {
height: 120rpx;
padding: 12rpx;
.list-title {
font-weight: bold;
font-size: 24rpx;
color: #232323;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.list-btn-area {
margin-top: 36rpx;
font-weight: 400;
font-size: 20rpx;
color: #666666;
display: flex;
justify-content: flex-end;
.bottom-btn {
display: flex;
align-items: center;
image {
width: 28rpx;
height: 28rpx;
}
}
}
}
}
}
.ml16 {
margin-left: 16rpx;
}
}
</style>

View File

@@ -0,0 +1,184 @@
<template>
<view class="p30 piles" style="padding: 30rpx">
<view class="piles_card">
<view class="piles_card_title">充电桩汇总</view>
<view class="piles_card_view">
<view>
<text>{{ count.installDeviceNumber || 0 }}</text>
<text>已安装</text>
</view>
<view>
<text>{{ count.uninstallDeviceNumber || 0 }}</text>
<text>未安装数量</text>
</view>
<view>
<text>{{ count.deviceTotal || 0 }}</text>
<text>团队</text>
</view>
</view>
</view>
<up-subsection activeColor="rgba(111, 162, 86, 1)" :list="list" keyName="name" :current="current" @change="upChange"></up-subsection>
<view class="order_view" v-for="i in dataList" :key="i">
<view class="piles_list" v-if="current == 0">
<view class="piles_list_title">安装电站{{ i.stationName || '-' }}</view>
<view class="piles_list_view">
<view>设备ID</view>
<view>{{ i.id }}</view>
</view>
<view class="piles_list_view">
<view>设备功率</view>
<view>{{ i.deviceType }}KW</view>
</view>
<view class="piles_list_view" v-if="i.purposeType">
<view>设备类型</view>
<view>{{ i.purposeType == 1 ? '商用运维版' : i.purposeType == 2 ? '商用合作版' : i.purposeType == 3 ? '家用专业版' : '' }}</view>
</view>
<view class="piles_list_view">地址{{ i.stationAddress || '-' }}</view>
<!-- <view class="piles_list_view">
<view>电费费用</view>
<view>
<text>1.00</text>
/
</view>
</view>
<view class="piles_list_view">
<view>昨日收益</view>
<view>
<text>100.00 </text>
</view>
</view> -->
<view class="piles_list_view">
<view>下单时间</view>
<view>{{ timeFormat(new Date(i.createTime).getTime(), 'yyyy-mm-dd hh:MM') }}</view>
</view>
</view>
<view class="piles_list" v-if="current == 1">
<view class="piles_list_view">
<view>设备ID</view>
<view>{{ i.id }}</view>
</view>
<view class="piles_list_view">
<view>设备功率</view>
<view>{{ i.deviceType }}KW</view>
</view>
<view class="piles_list_view" v-if="i.purposeType">
<view>设备类型</view>
<view>{{ i.purposeType == 1 ? '商用运维版' : i.purposeType == 2 ? '商用合作版' : i.purposeType == 3 ? '家用专业版' : '' }}</view>
</view>
<view class="piles_list_view">
<view>下单时间</view>
<view>{{ timeFormat(new Date(i.createTime).getTime(), 'yyyy-mm-dd hh:MM') }}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { getDeviceInfo } from '@/api/api.js';
import { onMounted, reactive, ref } from 'vue';
import { onPullDownRefresh, onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app';
import { timeFormat } from '@/uni_modules/uview-plus';
const paging = ref(null);
let dataList = ref([]);
let dataFrom = reactive({
deviceStatus: 1
});
let count = ref({});
onMounted(() => {
console.log(123456);
getDeviceInfo().then((res) => {
count.value = res;
dataList.value = res.installDeviceList;
});
});
const list = ref([
{
name: '已安装',
id: 1
},
{
name: '待安装',
id: 0
}
]);
const current = ref(0);
const upChange = (e) => {
current.value = e;
if (e == 0) {
dataList.value = count.value.installDeviceList || [];
} else {
dataList.value = count.value.uninstallDeviceList || [];
}
};
</script>
<style scoped lang="scss">
.piles {
padding: 30rpx;
&_card {
width: 690rpx;
height: 192rpx;
background: linear-gradient( 179deg, #81BF63 0%, #6FA256 100%);
border-radius: 8rpx 8rpx 0rpx 0rpx;
padding: 30rpx;
&_title {
font-weight: bold;
font-size: 28rpx;
color: #ffffff;
margin-bottom: 20rpx;
}
&_view {
padding: 0 80rpx;
flex-direction: column;
@include flex($space: space-between);
view {
@include flex($direction: column, $space: space-between);
text:nth-child(1) {
font-weight: bold;
font-size: 32rpx;
color: #ffffff;
margin-bottom: 15rpx;
}
text:nth-child(2) {
font-size: 26rpx;
color: #ffffff;
}
}
}
}
&_list {
padding: 25rpx;
width: 690rpx;
background: #ffffff;
border-radius: 16rpx 16rpx 16rpx 16rpx;
margin-top: 30rpx;
&_title {
font-weight: bold;
font-size: 28rpx;
color: #232323;
}
&_view {
@include flex;
color: #555555;
font-size: 28rpx;
margin-top: 15rpx;
view:nth-child(2) {
font-weight: bold;
font-size: 28rpx;
color: #232323;
}
text {
color: #ff2727;
}
}
}
}
</style>

View File

@@ -0,0 +1,182 @@
<template>
<view class="order">
<z-paging ref="paging" v-model="dataList" @query="queryList">
<view style="height: 20rpx"></view>
<view style="display: flex; align-items: center; margin: 0 30rpx 30rpx">
<view
style="font-weight: bold; position: relative; margin-right: 50rpx"
:style="{
color: purposeType == item.id ? '#333' : '#bbb'
}"
v-for="(item, index) in tabbar"
:key="index"
@click="swichMenu(item.id)"
>
<view style="position: relative; z-index: 9">{{ item.name }}</view>
<view
v-if="purposeType == item.id"
style="width: 72rpx; height: 16rpx; background: #b6d0aa; border-radius: 48rpx 48rpx 48rpx 48rpx; position: absolute; bottom: -5rpx; left: 0"
></view>
</view>
</view>
<view class="p30">
<view class="order_view" v-for="i in dataList" :key="i" @click="navTo(`/pages/order/details?id=${i.id}`)">
<view class="order_view_dd">
<view>
<text style="font-weight: 500">订单号</text>
:{{ i.orderNo }}
</view>
<view>
<up-tag size="mini" v-if="i.status == 0" text="待支付" plain></up-tag>
<up-tag size="mini" v-if="i.status == -1" text="已取消" type="warning" plain></up-tag>
<up-tag size="mini" v-if="i.status == 1" text="支付成功" type="success" plain></up-tag>
<up-tag size="mini" v-if="i.status == -2" text="退款" type="error" plain></up-tag>
</view>
</view>
<view class="order_view_info">
<image class="order_view_info_img" :src="i.orderGoods.cover" mode="aspectFit"></image>
<view class="order_view_info_right">
<view class="order_view_info_right_tit">
<view style="display: flex; align-items: center">
<!-- <up-tag size="mini" :text="i.sourceType == 1 ? '商品' : '套餐'" bgColor="#4874e5" borderColor="#4874e5"></up-tag> -->
<view>
{{ i.orderGoods.name }}
</view>
</view>
</view>
<view class="order_view_info_right_num" style="display: flex; align-items: center; justify-content: space-between">数量:{{ i.num }}</view>
<view class="order_view_info_right_mon">
订单金额:
<text style="color: crimson">{{ i.payMoney }}</text>
</view>
</view>
</view>
<view
style="
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid rgba(153, 153, 153, 0.5);
margin-top: 15rpx;
padding-top: 15rpx;
"
>
<view style="font-size: 28rpx">{{ i.createdAt }}</view>
<view>
<up-tag size="mini" v-if="i.orderPlatform == 3" text="支付宝" plain></up-tag>
<up-tag size="mini" v-if="i.orderPlatform == 2" text="微信" type="success" plain></up-tag>
<up-tag size="mini" v-if="i.orderPlatform == 1" text="钱包" type="warning" plain></up-tag>
</view>
</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useNav } from '@/hooks/useNav.js';
import { onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { orderPage } from '@/api/api.js';
import { timeFormat } from '@/uni_modules/uview-plus';
const { navTo } = useNav();
const paging = ref(null);
let dataList = ref([]);
let dataFrom = reactive({
status: 1,
businessPayType: '',
sourceType: ''
});
let tabbar = [
{
name: '已支付',
id: 1
},
{
name: '待支付',
id: 0
},
{
name: '已取消',
id: -1
}
];
let purposeType = ref(1);
const swichMenu = (index) => {
dataFrom.status = index;
paging.value.reload();
};
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize,
...dataFrom
};
orderPage(params)
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
</script>
<style scoped lang="scss">
.order {
&_view {
background: #ffffff;
border-radius: 16rpx;
padding: 25rpx;
margin-bottom: 30rpx;
&_info {
@include flex;
&_img {
width: 208rpx;
height: 208rpx;
margin-right: 15rpx;
border-radius: 10rpx;
}
&_right {
flex: 1;
font-size: 28rpx;
color: #232323;
&_tit {
@include flex($space: space-between);
margin-bottom: 15rpx;
}
&_num {
margin-bottom: 15rpx;
}
&_mon {
margin-bottom: 15rpx;
text {
color: #ff2e24;
}
}
&_time {
}
}
}
&_dd {
@include flex($space: space-between);
font-weight: bold;
font-size: 28rpx;
color: #232323;
margin-bottom: 15rpx;
}
}
}
</style>

View File

@@ -0,0 +1,349 @@
<template>
<view class="u-wrap">
<view style="margin: 30rpx">
<up-swiper :list="['https://zhongshuai-test.oss-cn-beijing.aliyuncs.com/upload/20240919/c6f8c174-19b1-41a3-a0d9-082f0abb5f85.png']" height="320rpx" indicator></up-swiper>
</view>
<view class="u-search-box">
<u-input placeholder="请输入充电桩型号或关键字" border="surround" prefixIcon="search" shape="circle" clearable="true" v-model="keywords"></u-input>
</view>
<view style="display: flex; align-items: center; justify-content: space-between; margin: 0 30rpx 30rpx">
<view
style="font-weight: bold; position: relative"
:style="{
color: purposeType == item.id ? '#333' : '#bbb'
}"
v-for="(item, index) in tabbar"
:key="index"
@click="swichMenu(item.id)"
>
<view style="position: relative;z-index: 9;">{{ item.name }}</view>
<view v-if="purposeType == item.id" style="width: 72rpx; height: 16rpx; background: #b6d0aa; border-radius: 48rpx 48rpx 48rpx 48rpx; position: absolute; bottom: -5rpx; left: 0"></view>
</view>
</view>
<view class="shopList">
<!-- <image class="shopList_img" src="/static/jp.png" mode="widthFix"></image> -->
<view class="shopList_list">
<view class="shopList_list_view" v-for="i in filterGoods(goods)" :key="i" @click="navTo(`/pageInvest/shop/details?id=${i.id}`)">
<image class="shopList_list_view_img" :src="i.cover" mode="aspectFit"></image>
<view class="shopList_list_view_tit">{{ i.name }}</view>
<view class="shopList_list_view_mon">
<view class="shopList_list_view_mon_left">{{ i.currentPrice }} </view>
<!-- <up-tag @click="toShop(i)" text="下单" bgColor="#4874e5" borderColor="#4874e5"></up-tag> -->
<!-- <view class="shopList_list_view_mon_right">下单</view> -->
</view>
</view>
</view>
</view>
<!-- <view class="u-menu-wrap">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop">
<view
v-for="(item, index) in tabbar"
:key="index"
class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']"
:data-current="index"
@tap.stop="swichMenu(index)"
>
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<block v-for="(item, index) in tabbar" :key="index">
<scroll-view scroll-y class="right-box" v-if="current == index">
<view class="page-view">
<view class="class-item">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container">
<view class="thumb-box" v-for="(item1, index1) in filterGoods(item.foods)" @click="navTo(`/pageInvest/shop/details?id=${item1.id}`)" :key="item1.id">
<image class="item-menu-image" :src="item1.cover" mode="aspectFill"></image>
<view class="item-menu-name">{{ item1.name }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</block>
</view> -->
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { goodsList, categoryList } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
const { navTo } = useNav();
const keywords = ref('');
let tabbar = ref([]);
let goods = ref([]);
let scrollTop = ref(0);
let current = ref(0);
let menuHeight = ref(0);
let menuItemHeight = ref(0);
let purposeType = ref(null);
// [
// {
// name: '女装',
// foods: [
// {
// name: 'A字裙',
// key: 'A字裙',
// icon: 'https://cdn.uviewui.com/uview/common/classify/1/1.jpg',
// cat: 10
// }
// ]
// }
// ]
onMounted(() => {
categoryList().then((res) => {
tabbar.value = res.map((item, index) => {
return {
...item,
foods: []
};
});
purposeType.value = res[0].id;
goodsList({ categoryId: res[0].id }).then((res) => {
// tabbar.value[0].foods = res;
goods.value = res;
});
});
});
async function swichMenu(index) {
// if (index == current.value) return;
// current.value = index;
purposeType.value = index;
goodsList({ categoryId: index }).then((res) => {
goods.value = res;
});
return;
// 如果为0意味着尚未初始化
if (menuHeight.value == 0 || menuItemHeight.value == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('u-tab-item', 'menuItemHeight');
}
// 将菜单菜单活动item垂直居中
this.scrollTop = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2;
}
function getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query
.select('.' + elClass)
.fields({ size: true }, (res) => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
this[dataVal] = res.height;
})
.exec();
});
}
const filterGoods = (value) => {
if (!value?.length) {
return [];
}
return value.filter((item) => item.name.includes(keywords.value));
};
</script>
<style lang="scss" scoped>
.u-wrap {
height: calc(100vh);
/* #ifdef H5 */
height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
}
.u-search-box {
padding: 18rpx 30rpx;
}
.u-menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: $u-tips-color;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
}
.u-tab-item {
height: 80rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: '';
position: absolute;
border-left: 4px solid rgba(111, 162, 86, 1);
height: 45rpx;
left: 0;
top: calc(50% - 22.5rpx);
}
.u-tab-view {
height: 100%;
}
.right-box {
background-color: rgb(250, 250, 250);
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
}
.item-title {
font-size: 26rpx;
color: $u-main-color;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 24rpx;
color: $u-main-color;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 33.333333%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 20rpx;
}
.item-menu-image {
width: 144rpx;
height: 144rpx;
border-radius: 4rpx 4rpx 4rpx 4rpx;
}
.shopList {
@include flex($direction: column, $space: content);
&_img {
width: 308rpx;
height: 44rpx;
margin-bottom: 50rpx;
}
&_list {
width: 690rpx;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
&_view {
border-radius: 8rpx 8rpx 8rpx 8rpx;
width: 334rpx;
background-color: #fff;
margin-bottom: 30rpx;
padding-bottom: 20rpx;
&_img {
width: 334rpx;
height: 334rpx;
border-radius: 8rpx 8rpx 0rpx 0rpx;
}
&_tit {
padding: 10rpx 20rpx 0;
display: -webkit-box;
-webkit-line-clamp: 2; /* 限制显示的行数 */
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
font-weight: bold;
font-size: 30rpx;
color: #232323;
}
&_mon {
padding: 0rpx 20rpx;
@include flex($space: space-between);
&_left {
font-weight: bold;
font-size: 30rpx;
color: rgba(239, 38, 38, 1);
}
&_right {
width: 80rpx;
height: 40rpx;
@include flex($space: center);
font-size: 26rpx;
background-color: #4874e5;
color: #fff;
font-weight: bold;
border-radius: 20rpx;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<view style="padding: 20rpx 30rpx">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view style="display: flex; flex-wrap: wrap; justify-content: space-between; width: 100%">
<view v-for="(item, index) in dataList" :key="index" style="width: 336rpx; background-color: #fff; border-radius: 8rpx 8rpx;margin-bottom: 30rpx;">
<image :src="item.coverImageUrl" style="width: 336rpx; height: 368rpx; border-radius: 8rpx 8rpx 0 0" mode="aspectFill"></image>
<view style="padding: 15rpx 15rpx 0; font-size: 24rpx">{{ item.title }}</view>
<view style="display: flex; align-items: center; padding: 15rpx; border-radius: 0 0 8rpx 8rpx; font-size: 24rpx">
<image :src="item.authorUrl" style="width: 48rpx; height: 48rpx; border-radius: 50%; margin-right: 20rpx"></image>
<view>{{ item.authorName }}</view>
</view>
</view>
</view>
<!-- <custom-waterfalls-flow
ref="waterfallsFlowRef"
:value="dataList"
:column="column"
:columnSpace="1.5"
:seat="2"
@wapperClick="wapperClick"
@imageClick="imageClick"
@loaded="loaded"
>
<view class="item" v-for="(item, index) in dataList" :key="index" :slot="`slot${index}`">
<view class="title">{{ item.title }}</view>
<view class="desc">{{ item.content }}</view>
</view>
</custom-waterfalls-flow> -->
</z-paging>
<view
style="
width: 108rpx;
height: 108rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
bottom: 300rpx;
right: 30rpx;
background: #ffffff;
border-radius: 50%;
font-size: 24rpx;
"
@click="navTo('/pages/find/add')"
>
<image src="/static/image/fawen.png" style="width: 48rpx; height: 48rpx"></image>
<view>发文</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue';
import { getMerchantSelect } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
const { navTo } = useNav();
onLoad(() => {});
const paging = ref(null);
const dataList = ref([]);
const queryList = async (pageNo, pageSize) => {
getMerchantSelect({
current: pageNo,
pageSize: pageSize,
category: 'DISCOVERY'
})
.then((res) => {
paging.value.complete(res.records);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
const column = ref(2);
function loaded() {
console.log('加载完成');
}
function wapperClick(item) {
console.log('单项点击事件', item);
}
function imageClick(item) {
console.log('图片点击事件', item);
}
const waterfallsFlowRef = ref(null);
</script>
<style>
page {
background-color: #f2f5f9;
}
</style>
<style lang="scss" scoped>
.handle {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 20rpx;
padding: 10rpx;
.btn {
margin: 20rpx 10rpx;
padding: 0 20rpx;
background: #2878ff;
font-size: 28rpx;
color: #fff;
&::after {
border: 0;
}
}
}
.item {
padding: 10rpx 10rpx 20rpx;
background: #fff;
.title {
line-height: 48rpx;
font-size: 28rpx;
color: #222;
}
.desc {
font-size: 24rpx;
color: #666;
}
}
</style>

View File

@@ -0,0 +1,389 @@
<template>
<view>
<z-paging ref="paging" v-model="dataList" @query="queryList">
<view class="search_header p30">
<view style="margin: 30rpx 0 0">
<up-swiper :list="list1" height="320rpx" keyName="imageUrl" indicator></up-swiper>
</view>
</view>
<view style="height: 35rpx"></view>
<view class="p30" style="width: 100%">
<search :top="false" @search="searchChange" />
</view>
<view style="height: 25rpx"></view>
<view style="padding: 0 30rpx">
<view class="order_list" style="position: sticky; top: 0; left: 0">
<view class="order_list_header">
<view class="order_list_header_view" @click="tabChange(1)">
<view>距我最近</view>
<view v-if="query.orderByType == 1" class="order_list_header_view_dian"></view>
</view>
<view class="order_list_header_view" @click="tabChange(2)">
<view>空闲最多</view>
<view v-if="query.orderByType == 2" class="order_list_header_view_dian"></view>
</view>
</view>
<image class="filter-btn" src="/static/icon/icon-filter.png" @click="filterBtn"></image>
</view>
</view>
<view style="margin-bottom: 30rpx; padding: 0 30rpx" v-for="(item, index) in dataList" :key="index">
<orderList toNav :info="item"></orderList>
</view>
</z-paging>
<view style="height: 180rpx"></view>
<u-popup
:show="popupShow"
mode="top"
:safeAreaInsetBottom="false"
@close="popupClose"
@open="popupOpen"
>
<view class="filter-area">
<view class="filter-label">充电方式</view>
<view class="filter-value">
<view
class="filter-value-item"
v-for="(item, index) in filterData.chargeWay"
:key="index"
:class="{'filter-value-item-active': item.value === query.chargeWay}"
@click="clickChargeWay(item)"
>
{{ item.label }}
</view>
</view>
<view class="filter-label">停车费</view>
<view class="filter-value">
<view
class="filter-value-item"
v-for="(item, index) in filterData.serviceInfo"
:key="index"
:class="{'filter-value-item-active': item.value === query.serviceInfo}"
@click="clickServiceInfo(item)"
>
{{ item.label }}
</view>
</view>
<view class="filter-label">终端功率kw</view>
<view class="filter-value">
<SlideFilter
style="width: 100%;padding: 0 40rpx;"
v-model="query.maxPower"
:option="[0, 20, 40, 80, 120, 240, 360, 480, 720, 960]"
@change="slideFilterChange"
/>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad, onShow, onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { aroundAreaApi, bannerList } from '@/api/api.js';
import SlideFilter from '@/components/slide-filter/index.vue';
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
const dataList = ref([]);
const paging = ref(null);
const query = reactive({
lon: '',
lat: '',
orderByType: 1, //1-最近;2-空闲较多
chargeWay: "",
serviceInfo: "",
maxPower: "",
keyWord: ''
});
const list1 = ref([]);
onLoad(async () => {
let _res = await bannerList();
list1.value = _res;
});
onShow(() => {
uni.hideTabBar();
});
let toKft = (e) => {
uni.makePhoneCall({
phoneNumber: '4008005326' //仅为示例
});
};
const queryList = async () => {
uni.showLoading({
title: '加载中...'
});
try {
if (!query.lon && !query.lat) {
const { longitude: lon, latitude: lat } = await uni.getLocation();
query.lon = lon;
query.lat = lat;
}
} catch (err) {
console.log(err);
}
console.log(query);
aroundAreaApi(query)
.then((res) => {
console.log(res, 'list');
paging.value.complete(res);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
let tabChange = (e) => {
query.orderByType = e;
paging.value.reload();
};
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const toOrder = () => {
uni.switchTab({
url: '/pages/order/order'
});
};
let searchChange = (e) => {
query.keyWord = e;
paging.value.reload();
};
let showMode = () => {
uni.showModal({
title: '提示',
content: '暂未开放',
showCancel: false,
confirmText: '确认',
success: () => {}
});
};
const popupShow = ref(false);
const filterData = reactive({
chargeWay: [
{ label: "慢充<20kw", value: "1" },
{ label: "快充20~360kw", value: "2" },
{ label: "超充≥360kw", value: "3" },
],
serviceInfo: [
{ label: "停车免费", value: "1" },
{ label: "限时免费", value: "2" },
{ label: "停车收费", value: "3" },
]
})
// 筛选电站
const filterBtn = () => {
popupShow.value = true;
}
const popupClose = () => {
console.log("popupClose");
popupShow.value = false;
}
const popupOpen = () => {
console.log("popupOpen");
}
const clickChargeWay = (item) => {
if(query.chargeWay == item.value){
query.chargeWay = ""
}else{
query.chargeWay = item.value;
}
paging.value.reload();
}
const clickServiceInfo = (item) => {
if(query.serviceInfo == item.value){
query.serviceInfo = ""
}else{
query.serviceInfo = item.value;
}
paging.value.reload();
}
const slideFilterChange = () => {
console.log("query.maxPower", query.maxPower)
paging.value.reload();
}
</script>
<style>
page {
/* background: linear-gradient(180deg, #ffffff 0%, #f7f7f7 100%); */
background-color: #f7f7f7;
}
</style>
<style lang="scss" scoped>
.search_header {
position: relative;
&_blur {
width: 100%;
height: 185rpx;
position: absolute;
top: 0;
left: 0;
background: #dbe6ff;
opacity: 0.8;
filter: blur(50px);
/* #ifdef MP-ALIPAY */
z-index: 0;
/* #endif */
/* #ifdef MP-WEIXIN */
z-index: -1;
/* #endif */
}
&_grid {
// margin: 35rpx 0;
margin-top: 25rpx;
border-radius: 15rpx;
@include flex($space: space-between);
&_view {
display: flex;
flex-direction: column;
align-items: center;
width: 126rpx;
font-size: 26rpx;
// background: #ffffff;
// border-radius: 24rpx 24rpx 24rpx 24rpx;
image {
width: 99rpx;
height: 99rpx;
margin-bottom: 10rpx;
}
}
}
}
.order_list {
box-sizing: border-box;
view {
box-sizing: border-box;
}
display: flex;
align-items: center;
padding: 15rpx;
margin-bottom: 30rpx;
font-size: 30rpx;
// background-color: #fff;
width: 690rpx;
border-radius: 15rpx;
// width: 690rpx;
// background: linear-gradient(180deg, #ffffff 0%, #f6f6f6 100%);
// box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(88, 140, 255, 0.1);
// border-radius: 44rpx 44rpx 0rpx 0rpx;
&_view {
padding: 15rpx 30rpx;
background-color: #fff;
border-radius: 15rpx;
margin-right: 30rpx;
}
&_active {
background-color: #6FA256;
color: #fff;
}
&_header {
width: 100%;
height: 100rpx;
@include flex;
font-weight: bold;
font-size: 36rpx;
color: #232323;
// background-color: #ffffff;
position: sticky;
top: 360rpx;
left: 0;
&_view {
position: relative;
margin-right: 50rpx;
view {
position: relative;
z-index: 99;
}
&_dian {
position: absolute !important;
bottom: 0rpx;
right: 20rpx;
width: 66rpx;
height: 20rpx;
background-color: #6FA256;
border-radius: 10rpx;
z-index: 1 !important;
}
}
}
.filter-btn {
width: 72rpx;
height: 72rpx;
}
}
button::after {
all: unset;
}
.filter-area {
padding: 30rpx 30rpx 56rpx;
.filter-label {
font-weight: bold;
font-size: 36rpx;
color: #232323;
margin-bottom: 24rpx;
}
.filter-value {
display: flex;
justify-content: space-between;
margin-bottom: 36rpx;
&-item {
font-weight: bold;
font-size: 24rpx;
color: #232323;
padding: 8rpx 0;
border-radius: 8rpx;
border: 2rpx solid #666666;
width: 220rpx;
text-align: center;
}
&-item-active {
background: #6FA256;
color: #FFFFFF;;
border: 2rpx solid #428A1F;
}
}
}
</style>

View File

@@ -0,0 +1,264 @@
<template>
<view class="content">
<!-- <search :Fixed="true" /> -->
<map
id="map"
:longitude="longitude"
@markertap="markerClick"
@callouttap="markerClick"
@regionchange="regionchange"
height="90"
width="90"
:markers="markList"
:latitude="latitude"
class="map_content"
>
<!-- #ifdef MP-WEIXIN -->
<cover-view slot="callout">
<template v-for="(item, index) in markList">
<cover-view class="callout" :marker-id="item.id">
<cover-view class="callout_item">
<cover-image class="callout_item_img" src="/static/icon/mc.png"></cover-image>
<cover-view class="callout_item_view"> {{ item.gunUseCount || 0 }}/{{ item.gunCount || 0 }}</cover-view>
</cover-view>
</cover-view>
</template>
</cover-view>
<!-- #endif -->
</map>
<uni-transition ref="mapLocationRef" :show="true">
<view class="map-location" @click="mapLocation">
<image src="/static/icon/location-marker-icon.png" mode="widthFix"></image>
</view>
</uni-transition>
<uni-transition modeClass="fade" :show="mapBox">
<view class="map_box">
<orderList toNav :Image="true" :info="infoDz" :list="infoDz.pictures" />
</view>
</uni-transition>
<!-- <tabbar path="/pages/index/index"></tabbar> -->
</view>
</template>
<script setup>
import { ref,onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { aroundAreaMap, infoAroundApi } from '@/api/api.js';
let longitude = ref(113.675688);
let latitude = ref(34.75527700365562);
let mapContext = ref(null);
let mapBox = ref(false);
let mapLocationRef = ref();
let infoDz = ref([]);
let markList = ref([]);
onMounted(async () => {
mapContext.value = uni.createMapContext('map');
const { longitude: lon, latitude: lat } = await uni.getLocation({
type: 'gcj02' // 根据实际需要选择坐标系
});
latitude.value = lat;
longitude.value = lon;
getInfo();
setTimeout(() => {
mapLocation();
}, 300);
});
let getInfo = async () => {
let _res = await aroundAreaMap({
orderByType: 1,
lat: latitude.value,
lon: longitude.value
});
let list = _res.map((item, index) => {
return {
id: item.id,
longitude: item.location.lng,
latitude: item.location.lat,
iconPath: '/static/icon/marker-pointer.png',
width: 20,
height: 23,
content: '2',
gunUseCount: item.gunUseCount,
gunCount: item.gunCount,
distance: item.distance,
customCallout: {
display: 'ALWAYS', // 显示方式
anchorX: 0, // 锚点X轴
anchorY: -10 // 锚点Y轴
}
};
});
list.unshift({
longitude: longitude.value,
latitude: latitude.value,
iconPath: '/static/icon/my-location-default.png',
width: 45,
height: 45,
id: -1
});
markList.value = list;
};
const mapLocation = () => {
const log = longitude.value;
const lat = latitude.value;
mapContext.value.moveToLocation({
longitude: log,
latitude: lat
});
};
// 地图缩放移动触发
const regionchange = (e) => {
// 地图移动手松开结束触发type:end
if (e.type == 'end') {
console.log(e);
console.log(e.detail.scale);
mapBox.value = false;
mapLocationRefStep(false);
}
};
// marker点击事件
const markerClick = async (e) => {
console.log(e, 'eeeeeee');
if (e.markerId == -1) {
return;
}
uni.showLoading();
let _res = await infoAroundApi({
id: e.markerId
});
let markerInfo = markList.value.find((val) => val.id == e.markerId);
let data = _res?.priceList?.find((val) => val.isCurrent == 1);
infoDz.value = {
..._res,
distance: markerInfo.distance,
priceAmount: data.totalAmount
};
console.log(infoDz, 'infoDzinfoDz');
// infoDz.value.priceAmount = data.totalAmount;
// infoDz.value.distance = data.distance;
uni.hideLoading();
mapBox.value = true;
mapLocationRefStep(true);
};
const mapLocationRefStep = (type) => {
if (type) {
mapLocationRef.value.step(
{
translateY: '-200rpx'
},
{
timingFunction: 'ease-in',
duration: 100
}
);
} else {
mapLocationRef.value.step(
{
translateY: '0rpx'
},
{
timingFunction: 'ease',
duration: 500
}
);
}
mapLocationRef.value.run();
};
</script>
<style lang="scss">
.map_content {
width: 750rpx;
height: 100vh;
/* #ifdef MP-ALIPAY */
height: calc(100vh - 100upx);
/* #endif */
}
.map-location {
width: 90rpx;
height: 90rpx;
background-color: #fff;
position: fixed;
left: 30rpx;
bottom: 570rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 5px 11px rgba(0, 0, 0, 0.2);
image {
width: 45rpx;
height: 45rpx;
}
}
.callout {
box-sizing: border-box;
background: rgba(15, 75, 203, 0.26);
border-radius: 15rpx 15rpx 15rpx 0;
padding: 10rpx 15rpx;
@include flex($direction: column);
&_item {
@include flex;
font-weight: bold;
font-size: 28rpx;
color: #ffffff;
box-sizing: border-box;
&_img {
width: 40rpx;
height: 40rpx;
margin-right: 15rpx;
}
}
&_item:nth-child(1) {
margin-bottom: 15rpx;
}
}
.recharge {
width: 690rpx;
background-color: #fff;
min-height: 300rpx;
position: fixed;
left: 30rpx;
bottom: 250rpx;
border-radius: 20rpx;
padding: 20rpx;
box-shadow: 0 5px 11px rgba(0, 0, 0, 0.2);
&_title {
font-size: 36rpx;
margin-bottom: 20rpx;
}
&_con {
font-size: 26rpx;
}
}
.map_box {
width: 690rpx;
position: fixed;
left: 30rpx;
bottom: 230rpx;
z-index: 999;
}
</style>

View File

@@ -0,0 +1,373 @@
<template>
<view class="mine">
<!-- 头部个人信息 -->
<view class="header">
<view class="user-info" @click="navTo('/pages/mine/sett')">
<up-avatar size="120rpx" :src="user.avatarUrl || user.avatar" />
<view class="user-detail" v-if="user.nickName || user.username">
<text class="nickname">{{ user.nickName || user.username }}</text>
<text class="phone">{{ user.phone || user.mobile }}</text>
</view>
<view class="user-detail" v-else @click="!isInvest ? navTo('/pages/login/login') : navTo('/pageInvest/login/login')">
<text class="nickname">您还未登录</text>
</view>
</view>
<view class="qr-code" v-if="isInvest">
<image @click="lookImg([user.qrcode])" :src="user.qrcode" mode="aspectFit" />
<text>邀请码</text>
</view>
</view>
<!-- 余额积分 -->
<view class="balance-wrap">
<view class="balance-item" @click="toIsInvest">
<text class="amount">{{ user.money2 || '0' }}</text>
<text class="label">余额</text>
</view>
<view v-if="!isInvest" class="balance-item" @click="navTo('/pages/mine/signIn')">
<text class="amount">{{ user.points || '0' }}</text>
<text class="label">积分</text>
</view>
<view v-else class="balance-item" @click="emit('tabChange', { index: 2 })">
<text class="amount">{{ user.deviceNum || '0' }}</text>
<text class="label">充电桩</text>
</view>
</view>
<!-- 我的爱车 -->
<view class="vehicle-section" v-if="!isInvest">
<view class="section-header">
<text style="font-weight: bold">我的爱车</text>
<text class="more" @click="navTo('/pages/mine/car/car')">全部车辆 ></text>
</view>
<view class="car-plate" v-if="user.licensePlate" @click="navTo('/pages/mine/car/car')">
<image style="width: 198rpx; height: 56rpx; position: absolute; top: 0; left: 0" src="/static/image/carNum.png"></image>
<text>{{ user.licensePlate }}</text>
</view>
<view v-else class="add-vehicle" @click="navTo('/pages/mine/car/add')">
<view class="add-btn">
<image src="/static/icon/add.png" mode="aspectFit" />
</view>
<text>添加我的爱车</text>
</view>
<view class="vehicle-status">
<view class="status-item">
<image src="/static/icon/mine/parking.png" mode="aspectFit" />
<text>停车定位</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/charging.png" mode="aspectFit" />
<text>充电状态</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/location.png" mode="aspectFit" />
<text>精确定位</text>
</view>
</view>
</view>
<!-- 投资者功能菜单 -->
<view class="menu-grid" v-if="isInvest">
<view class="menu-item" v-for="(item, index) in menuItemsIsInvest1" :key="index" @click="item.type == 'relTo' ? emit('tabChange', item) : handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
<!-- 投资者功能菜单 -->
<view class="menu-grid" v-if="isInvest">
<view class="menu-item" v-for="(item, index) in menuItemsIsInvest2" :key="index" @click="handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
<!-- 功能菜单 -->
<view class="menu-grid" v-if="!isInvest">
<view class="menu-item" v-for="(item, index) in menuItems" :key="index" @click="handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { userInfo } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
import { lookImg } from '@/utils/fun.js';
const props = defineProps({
user: {
type: Object,
default: {}
},
isInvest: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['tabChange']);
const { navTo, relTo } = useNav();
const menuItemsIsInvest1 = ref([
{ name: '我的订单', icon: '/static/icon/mine/order.png', index: 1, type: 'relTo' },
{ name: '商城', icon: '/static/icon/mine/shop.png', index: 0, type: 'relTo' },
{ name: '我的银行卡', icon: '/static/icon/mine/travel.png', path: '/pages/bank/bank' },
{ name: '切换账号', icon: '/static/icon/mine/switch.png', path: '/pageInvest/login/login' }
]);
const menuItemsIsInvest2 = ref([
{ name: '提现', icon: '/static/icon/tixian.png', path: '/pageInvest/money/withdraw' },
{ name: '客服中心', icon: '/static/icon/mine/service.png', path: '/pages/service/index' },
{ name: '退出登录', icon: '/static/icon/mine/logout.png', path: '/pages/account/logout' },
{ name: '充电模式', icon: '/static/icon/qiehuan.png', path: '/pages/login/login' }
]);
const menuItems = ref([
{ name: '我的订单', icon: '/static/icon/mine/order.png', path: '/pages/order/order' },
{ name: '收藏电站', icon: '/static/icon/mine/station.png', path: '/pages/station/favorite' },
{ name: '客服中心', icon: '/static/icon/mine/service.png', path: '/pages/service/index' },
{ name: '一号多充', icon: '/static/icon/mine/multi.png', path: '/pages/mine/multipleNumbers' },
{ name: '隐私', icon: '/static/icon/mine/privacy.png', path: '/pages/privacy/index' },
{ name: '我的银行卡', icon: '/static/icon/mine/travel.png', path: '/pages/bank/bank' },
{ name: '投资者平台', icon: '/static/icon/mine/switch.png', path: '/pageInvest/login/login' },
{ name: '退出登录', icon: '/static/icon/mine/logout.png', path: '/pages/account/logout' }
]);
const handleMenuClick = (item) => {
if (item.path) {
if (item.path === "/pages/account/logout") {
outLogin()
return
}
navTo(item.path);
return;
}
};
const toIsInvest = () => {
if (props.isInvest) {
navTo('/pageInvest/money/wallet', true);
} else {
}
};
onMounted(async () => {});
onShow(async () => {
isInvest.value = uni.getStorageSync('isInvest') || false;
if (isInvest.value) {
menuItems.value[6].name = '充电模式';
} else {
menuItems.value[6].name = '投资者平台';
}
});
const outLogin = () => {
uni.showModal({
title: '提示',
content: '是否确认退出登录?',
success: (res) => {
if (res.confirm) {
uni.clearStorageSync();
uni.reLaunch({
url: '/pages/home/home'
});
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
</script>
<style lang="scss" scoped>
.mine {
min-height: 100vh;
background-color: #f7f7f7;
.header {
padding: 30rpx;
background: #fff;
display: flex;
justify-content: space-between;
align-items: center;
.user-info {
display: flex;
align-items: center;
gap: 20rpx;
.user-detail {
.nickname {
font-size: 32rpx;
font-weight: 500;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.phone {
font-size: 28rpx;
color: #666;
}
}
}
.qr-code {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
image {
width: 88rpx;
height: 88rpx;
margin-bottom: 6rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
.balance-wrap {
display: flex;
justify-content: space-around;
background: #fff;
padding: 0rpx 0 30rpx;
.balance-item {
text-align: center;
.amount {
font-size: 40rpx;
font-weight: 600;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.label {
font-size: 26rpx;
color: #666;
}
}
}
.vehicle-section {
margin: 20rpx;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
.section-header {
display: flex;
justify-content: space-between;
margin-bottom: 30rpx;
text {
font-size: 30rpx;
color: #333;
}
.more {
color: #666;
font-size: 26rpx;
}
}
.add-vehicle {
display: flex;
align-items: center;
gap: 20rpx;
margin-bottom: 30rpx;
.add-btn {
width: 80rpx;
height: 80rpx;
background: #f5f5f5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
image {
width: 40rpx;
height: 40rpx;
}
}
text {
font-size: 28rpx;
color: #666;
}
}
.vehicle-status {
display: flex;
justify-content: space-around;
border-top: 1rpx solid #f7f7f7;
padding-top: 20rpx;
.status-item {
display: flex;
align-items: center;
text-align: center;
image {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
}
.menu-grid {
margin: 20rpx;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 30rpx;
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10rpx;
image {
width: 48rpx;
height: 48rpx;
}
text {
font-size: 24rpx;
color: #333;
}
}
}
}
.car-plate {
color: #333;
font-weight: bold;
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 198rpx;
height: 56rpx;
margin: 20rpx;
text {
position: relative;
z-index: 99;
}
}
</style>

View File

@@ -0,0 +1,127 @@
<template>
<view class="sweep">
<statusBar />
<view class="sweep_note">
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/djk.png" mode="widthFix"></image>
</view>
<view>插上</view>
<view>充电枪</view>
</view>
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/djs.png" mode="widthFix"></image>
</view>
<view>点击</view>
<view>扫码充电</view>
</view>
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/cs.png" mode="widthFix"></image>
</view>
<view>点击</view>
<view>开始充电</view>
</view>
</view>
<view class="sweep_scan" style="margin-top: 300rpx">
<up-input placeholder="请输入充电枪编号" type="number" border="surround" v-model="value"></up-input>
<view style="width: 100rpx">
<up-button type="primary" text="确定" @click="toCd"></up-button>
</view>
</view>
<view class="sweep_scan" style="margin-top: 150rpx">
<up-button @click="scan" type="primary" shape="circle" text="扫码充电"></up-button>
</view>
<!-- <tabbar path="/pages/sweep/sweep" /> -->
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
import { urlQuery } from '@/utils/fun.js';
const { nav, navTo } = useNav();
let value = ref('');
onLoad(() => {
});
const scan = async () => {
uni.scanCode({
success: function (res) {
let query = urlQuery(res.result);
if (!query.num) {
uni.showToast({
title: '请扫描正确的设备码',
icon: 'none'
});
} else {
navTo(`/pages/home/star?id=${query.num}`);
}
// navTo(`/pages/home/star?id=${res.result}`);
}
});
};
const toCd = async () => {
if (!value.value) {
uni.showToast({
title: '请输入枪号',
icon: 'none'
});
return;
}
navTo(`/pages/home/star?id=${value.value}`);
};
</script>
<style scoped lang="scss">
.sweep {
&_note {
padding: 0 60rpx;
@include flex($space: space-between);
&_view {
@include flex($direction: column, $space: center);
font-weight: 800;
font-size: 32rpx;
color: #4879e6;
&_img {
display: flex;
align-items: flex-end;
height: 115rpx;
margin-bottom: 30rpx;
}
}
&_view:nth-child(1) {
image {
width: 151rpx;
height: 99rpx;
}
}
&_view:nth-child(2) {
image {
width: 120rpx;
height: 99rpx;
}
}
&_view:nth-child(3) {
image {
width: 106rpx;
height: 113rpx;
}
}
}
&_scan {
@include flex;
padding: 0 120rpx;
}
}
</style>

445
pages/home/detail.vue Normal file
View File

@@ -0,0 +1,445 @@
<template>
<view class="orderdetail">
<!-- <statusBar /> -->
<view class="orderdetail_header p30" :style="{ backgroundColor: headerBg ? '#FFF' : '' }">
<view :style="{ height: statusBarHeight }"></view>
<view style="height: 44px; display: flex; align-items: center" @click="">
<up-icon name="arrow-left" bold color="#000" @click="back"></up-icon>
<view @click="back" style="margin-left: 25rpx; transition: all 0.5s" :style="{ opacity: headerBg ? 1 : 0 }">电站详情</view>
</view>
</view>
<up-swiper :list="info.pictures" height="530rpx"></up-swiper>
<view class="p30" style="margin-top: -80rpx">
<orderList
:info="{
...info,
priceAmount: fullCost.totalAmount
}"
type="info"
></orderList>
<view style="height: 30rpx"></view>
<view class="orderdetail_info" style="margin-bottom: 30rpx">
<view class="orderdetail_info_title">
<view>费用信息</view>
<view style="display: flex; align-items: center" @click="showJf = true">
价格详情
<view style="margin-left: 30rpx">
<up-icon color="#333" size="28rpx" name="arrow-right"></up-icon>
</view>
</view>
</view>
<view style="max-width: 420rpx">
<up-tag size="mini" :text="`当前计费时间段:${fullCost.startTime}-${fullCost.endTime}`" plain plainFill></up-tag>
</view>
<view class="orderdetail_info_fy">
<view class="orderdetail_info_fy_left">电站价格</view>
<view class="orderdetail_info_fy_right">
{{ fullCost.totalAmount }}
<text style="font-weight: 500; font-size: 24rpx; color: #333; margin-left: 15rpx">/</text>
</view>
</view>
</view>
<view class="orderdetail_info" style="margin-bottom: 30rpx">
<view>
<view class="orderdetail_info_title">终端明细</view>
</view>
<view class="orderdetail_info_zd" style="position: relative" @click="showZd">
<view class="orderdetail_info_zd_zdbg"></view>
<image
src="/static/icon/eleclist-terminal.png"
style="transform: rotateY(180deg); position: absolute; left: 0; bottom: 0; width: 100rpx; height: 100rpx"
mode="widthFix"
></image>
<view>交流</view>
<view style="display: flex; align-items: center">
{{ info.gunCount - info.gunUseCount }}
<text style="font-size: 28rpx; opacity: 0.9; margin-left: 10rpx">空闲</text>
<text style="font-size: 24rpx; opacity: 0.8">/{{ info.gunCount }}</text>
<view style="margin-left: 30rpx">
<up-icon color="#fff" size="28rpx" name="arrow-right"></up-icon>
</view>
</view>
</view>
</view>
<view class="orderdetail_info">
<view class="orderdetail_info_title">基本信息</view>
<view class="orderdetail_info_view">
<view class="orderdetail_info_view_left">服务提供方</view>
<view class="orderdetail_info_view_right" @click="lookImg([info.licenseImage])">
{{ info.merchantName }}
<image src="/static/icon/9you.png" mode="widthFix"></image>
</view>
</view>
<!-- <view class="orderdetail_info_view">
<view class="orderdetail_info_view_left" style="color: #232323">{{ info.merchantName }}</view>
</view> -->
<view class="orderdetail_info_view">
<view class="orderdetail_info_view_left">营业时间</view>
<view class="orderdetail_info_view_right" @click="lookImg([info.licenseImage])">
{{ info.busineHours }}
</view>
</view>
<!-- <view class="orderdetail_info_view">
<view class="orderdetail_info_view_left" style="margin-right: 30rpx">
{{ info.busineHours }}
</view>
</view> -->
<view class="orderdetail_info_xian"></view>
<view class="orderdetail_info_view">
<view class="orderdetail_info_view_left">发票服务</view>
<view class="orderdetail_info_view_right">{{ info.invoice }}</view>
</view>
<view class="orderdetail_info_view">
<view class="orderdetail_info_view_left">备注信息</view>
<view class="orderdetail_info_view_right">{{ info.remarks || '' }}</view>
</view>
<view class="orderdetail_info_view">
<view class="orderdetail_info_view_left">服务提供方</view>
<view class="orderdetail_info_view_right" @click="call(info.stationTel)" style="color: #6FA256; font-weight: bold">{{ info.stationTel }}</view>
</view>
</view>
</view>
<view class="orderdetail_btn p30">
<view class="orderdetail_btn_left">
{{ fullCost.totalAmount }}
<text>/</text>
</view>
<view class="orderdetail_btn_right" @click="toRecharge">扫码充电</view>
</view>
<view style="height: 150rpx"></view>
<up-popup :show="show" @close="show = false" closeable round="10">
<view class="orderdetail_info" style="padding-top: 50rpx">
<view class="orderdetail_info_zd" style="position: relative" @click="show = true">
<view class="orderdetail_info_zd_zdbg"></view>
<image
src="/static/icon/eleclist-terminal.png"
style="transform: rotateY(180deg); position: absolute; left: 0; bottom: 0; width: 100rpx; height: 100rpx"
mode="widthFix"
></image>
<view>交流</view>
<view style="display: flex; align-items: center">
{{ info.gunCount - info.gunUseCount }}
<text style="font-size: 28rpx; opacity: 0.9; margin-left: 10rpx">空闲</text>
<text style="font-size: 24rpx; opacity: 0.8">/{{ info.gunCount }}</text>
</view>
</view>
</view>
<view class="gun">
<z-paging ref="paging" :fixed="false" :loading-more-enabled="false" v-model="dataList" @query="queryList" height="600rpx;" :auto="false" show-refresher-when-reload>
<view class="gun_list" v-for="(item, index) in dataList" :key="index">
<view class="gun_list_left">
<view class="gun_list_left_view1">
<up-tag v-if="item.realtimeStatus == 1" size="mini" type="error" text="故障" plain plainFill></up-tag>
<up-tag v-else-if="item.realtimeStatus == 2" size="mini" type="success" text="空闲" plain plainFill></up-tag>
<up-tag v-else-if="item.realtimeStatus == 3" size="mini" type="warning" text="充电中" plain plainFill></up-tag>
<up-tag v-else size="mini" type="error" text="离线" plain plainFill></up-tag>
<view style="margin-left: 15rpx"><up-tag v-if="item.insertStatus == 1" size="mini" text="已插枪" plain plainFill></up-tag></view>
<view style="margin-left: 15rpx">{{ item.gunName }}</view>
</view>
<view class="gun_list_left_view">{{ item.deviceNo }}</view>
<view class="gun_list_left_view">
<view>最高功率{{ item.maxPower }}KW</view>
<view style="margin-left: 30rpx">电压{{ item.maxVoltage }}V</view>
</view>
</view>
<view>
<up-button @click="startCd(item)" v-if="item.realtimeStatus == 2" shape="circle" type="success" :plain="true" text="启动充电"></up-button>
<up-button
v-if="item.realtimeStatus == 1 || item.realtimeStatus == 0"
shape="circle"
type="error"
:plain="true"
text="报故障"
openType="contact"
></up-button>
</view>
</view>
</z-paging>
</view>
</up-popup>
<up-popup :show="showJf" @close="showJf = false" closeable round="10">
<view style="font-size: 36rpx; font-weight: bold; padding: 30rpx">价格详情</view>
<view style="padding: 30rpx; padding-top: 0">
<scroll-view scroll-y="true" style="height: 800rpx">
<view v-for="(item, index) in info.priceList" :key="index" style="margin-bottom: 30rpx; position: relative; position: relative">
<view
style="
height: 80rpx;
background: linear-gradient(to right, rgba(72, 121, 230, 1), rgba(72, 121, 230, 0.4));
border-radius: 15rpx;
color: #fff;
font-size: 28rpx;
padding-top: 10rpx;
padding-left: 30rpx;
"
>
<text v-if="item.isCurrent == 1" style="margin-right: 30rpx">当前计费时间段</text>
{{ item.startTime }}-{{ item.endTime }}
</view>
<view style="border: 1rpx solid #6FA256; border-radius: 15rpx; padding: 30rpx; margin-top: -30rpx; background-color: #fff; font-size: 28rpx">
<view style="display: flex; justify-content: space-between; margin-bottom: 15rpx">
<view>电费</view>
<view>{{ item.electricityRate }}/</view>
</view>
<view style="display: flex; justify-content: space-between; margin-bottom: 15rpx">
<view>服务费</view>
<view>{{ item.serviceFeeRate }}/</view>
</view>
<view style="border-top: 1rpx solid #eee; margin-bottom: 15rpx"></view>
<view style="display: flex; justify-content: space-between">
<view>总计</view>
<view>{{ item.totalAmount }}/</view>
</view>
</view>
</view>
</scroll-view>
</view>
</up-popup>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { infoAroundApi, listByStationId, startCharging } from '@/api/api.js';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import { lookImg, call, urlQuery } from '@/utils/fun.js';
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
const headerBg = ref(false);
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
let info = reactive({});
let show = ref(false);
const dataList = ref([]);
const paging = ref(null);
let showJf = ref(false);
const fullCost = computed(() => {
let data = info?.priceList?.find((val) => val.isCurrent == 1);
return data || {};
});
onLoad((options) => {
getInfo(options.id, options.distance);
});
onPageScroll((e) => {
if (e.scrollTop > uni.getSystemInfoSync().statusBarHeight + 44) {
headerBg.value = true;
} else {
headerBg.value = false;
}
});
const getInfo = async (e, distance) => {
let _res = await infoAroundApi({ id: e });
_res.distance = distance;
Object.assign(info, _res);
};
// 使用 ref 创建响应式引用
const list3 = ref(['https://cdn.uviewui.com/uview/swiper/swiper3.png', 'https://cdn.uviewui.com/uview/swiper/swiper2.png', 'https://cdn.uviewui.com/uview/swiper/swiper1.png']);
let toRecharge = () => {
uni.scanCode({
success: function (res) {
let query = urlQuery(res.result);
if (!query.num) {
uni.showToast({
title: '请扫描正确的设备码',
icon: 'none'
});
} else {
navTo(`/pages/home/star?id=${query.num}`);
}
// navTo(`/pages/home/star?id=${res.result}`);
}
});
};
const back = () => {
uni.navigateBack();
};
const queryList = async () => {
listByStationId({ stationId: info.id })
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
const showZd = () => {
show.value = true;
paging.value.reload();
};
const startCd = async (e) => {
uni.navigateTo({
url: './star?id=' + e.deviceGunNo
});
// let _res = startCharging({
// deviceNo: e.deviceNo,
// gunNo: e.gunNo
// });
};
</script>
<style scoped lang="scss">
.orderdetail {
padding-bottom: 150rpx;
&_header {
width: 750rpx;
position: fixed;
left: 0;
top: 0;
z-index: 99;
transition: all 0.5s;
}
&_info {
background: #ffffff;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 25rpx;
box-shadow: 0rpx -6rpx 8rpx 2rpx rgba(66, 115, 229, 0.05);
&_title {
font-size: 32rpx;
color: #232323;
margin-bottom: 30rpx;
@include flex($space: space-between);
}
&_fy {
background: linear-gradient(to right, rgba(111, 162, 86, 0.4), rgba(72, 121, 230, 0));
border-radius: 15rpx;
padding: 40rpx 20rpx 40rpx 40rpx;
color: #fff;
margin-top: 30rpx;
@include flex;
&_left {
font-size: 32rpx;
font-weight: 800;
font-style: italic;
color: #6FA256;
}
&_right {
font-size: 36rpx;
font-weight: 800;
color: #6FA256;
margin-left: 30rpx;
@include flex;
}
}
&_zd {
border-radius: 15rpx;
padding: 40rpx 20rpx 40rpx 130rpx;
background-color: #6FA256;
color: #fff;
@include flex($space: space-between);
&_zdbg {
position: absolute;
left: 0;
top: 0;
width: 40%;
height: 100%;
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.3) 100%);
}
}
&_view {
@include flex($space: space-between);
margin-bottom: 30rpx;
&_left {
font-weight: 400;
font-size: 28rpx;
color: #232323;
}
&_right {
@include flex;
font-weight: bold;
font-size: 28rpx;
color: #232323;
image {
width: 28rpx;
height: 28rpx;
margin-left: 10rpx;
}
}
}
&_xian {
width: 100%;
border: 2rpx solid #707070;
margin-bottom: 30rpx;
opacity: 0.06;
}
}
&_btn {
width: 100%;
position: fixed;
left: 0;
bottom: 40rpx;
@include flex($space: space-between);
view {
@include flex($space: center);
width: 330rpx;
height: 92rpx;
border-radius: 46rpx 46rpx 46rpx 46rpx;
}
&_left {
background-color: #e5eaf4;
color: #6FA256;
font-size: 34rpx;
font-weight: bold;
text {
font-size: 26rpx;
}
}
&_right {
background: #6FA256;
color: #fff;
font-weight: bold;
font-size: 32rpx;
}
}
.gun {
height: 600rpx;
&_list {
@include flex($space: space-between);
padding: 30rpx;
&_left {
flex: 1;
&_view {
font-size: 24rpx;
color: #b0b2b6;
margin-bottom: 10rpx;
@include flex;
}
&_view1 {
@include flex;
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
}
}
}
}
::v-deep .u-popup__content__close--top-right {
top: 10rpx;
}
}
</style>

View File

@@ -0,0 +1,261 @@
<template>
<view>
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view class="search_header p30">
<view style="margin: 30rpx 0 0">
<up-swiper :list="list1" height="320rpx" keyName="imageUrl" indicator></up-swiper>
</view>
</view>
<view style="height: 35rpx"></view>
<view class="p30" style="width: 100%">
<search :top="false" @search="searchChange" />
</view>
<view style="height: 25rpx"></view>
<view style="padding: 0 30rpx">
<view class="order_list" style="position: sticky; top: 0; left: 0">
<view class="order_list_header">
<view class="order_list_header_view" @click="tabChange(1)">
<view>距我最近</view>
<view v-if="query.orderByType == 1" class="order_list_header_view_dian"></view>
</view>
<view class="order_list_header_view" @click="tabChange(2)">
<view>空闲最多</view>
<view v-if="query.orderByType == 2" class="order_list_header_view_dian"></view>
</view>
</view>
</view>
</view>
<view style="margin-bottom: 30rpx; padding: 0 30rpx" v-for="(item, index) in dataList" :key="index">
<orderList toNav :info="item"></orderList>
</view>
</z-paging>
<view style="height: 180rpx"></view>
<cc-myTabbar :tabBarShow="0"></cc-myTabbar>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad, onShow, onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { aroundAreaApi, bannerList } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
const dataList = ref([]);
const paging = ref(null);
const query = reactive({
lon: '',
lat: '',
orderByType: 1, //1-最近;2-空闲较多
keyWord: ''
});
const list1 = ref([]);
onLoad(async () => {
let _res = await bannerList();
list1.value = _res;
});
onShow(() => {
});
let toKft = (e) => {
uni.makePhoneCall({
phoneNumber: '4008005326' //仅为示例
});
};
const queryList = async () => {
uni.showLoading({
title: '加载中...'
});
try {
if (!query.lon && !query.lat) {
const { longitude: lon, latitude: lat } = await uni.getLocation();
query.lon = lon;
query.lat = lat;
}
} catch (err) {
console.log(err);
}
console.log(query);
aroundAreaApi(query)
.then((res) => {
console.log(res, 'list');
paging.value.complete(res);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
let tabChange = (e) => {
query.orderByType = e;
paging.value.reload();
};
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const toOrder = () => {
uni.switchTab({
url: '/pages/order/order'
});
};
let searchChange = (e) => {
query.keyWord = e;
paging.value.reload();
};
let showMode = () => {
uni.showModal({
title: '提示',
content: '暂未开放',
showCancel: false,
confirmText: '确认',
success: () => {}
});
};
</script>
<style>
page {
/* background: linear-gradient(180deg, #ffffff 0%, #f7f7f7 100%); */
background-color: #f7f7f7;
}
</style>
<style lang="scss" scoped>
.search_header {
position: relative;
&_blur {
width: 100%;
height: 185rpx;
position: absolute;
top: 0;
left: 0;
background: #dbe6ff;
opacity: 0.8;
filter: blur(50px);
/* #ifdef MP-ALIPAY */
z-index: 0;
/* #endif */
/* #ifdef MP-WEIXIN */
z-index: -1;
/* #endif */
}
&_grid {
// margin: 35rpx 0;
margin-top: 25rpx;
border-radius: 15rpx;
@include flex($space: space-between);
&_view {
display: flex;
flex-direction: column;
align-items: center;
width: 126rpx;
font-size: 26rpx;
// background: #ffffff;
// border-radius: 24rpx 24rpx 24rpx 24rpx;
image {
width: 99rpx;
height: 99rpx;
margin-bottom: 10rpx;
}
}
}
}
.order_list {
box-sizing: border-box;
view {
box-sizing: border-box;
}
display: flex;
align-items: center;
padding: 15rpx;
margin-bottom: 30rpx;
font-size: 30rpx;
// background-color: #fff;
width: 690rpx;
border-radius: 15rpx;
// width: 690rpx;
// background: linear-gradient(180deg, #ffffff 0%, #f6f6f6 100%);
// box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(88, 140, 255, 0.1);
// border-radius: 44rpx 44rpx 0rpx 0rpx;
&_view {
padding: 15rpx 30rpx;
background-color: #fff;
border-radius: 15rpx;
margin-right: 30rpx;
}
&_active {
background-color: #6FA256;
color: #fff;
}
&_header {
width: 100%;
height: 100rpx;
@include flex;
font-weight: bold;
font-size: 36rpx;
color: #232323;
// background-color: #ffffff;
position: sticky;
top: 360rpx;
left: 0;
&_view {
position: relative;
margin-right: 50rpx;
view {
position: relative;
z-index: 99;
}
&_dian {
position: absolute !important;
bottom: 0rpx;
right: 20rpx;
width: 66rpx;
height: 20rpx;
background-color: #6FA256;
border-radius: 10rpx;
z-index: 1 !important;
}
}
}
}
button::after {
all: unset;
}
</style>

75
pages/home/home.vue Normal file
View File

@@ -0,0 +1,75 @@
<template>
<view>
<view v-if="isInvest">
<view>
<pageG v-if="tabBarShow == 0" :user="user" ref="pageG" />
</view>
<view>
<pageH v-if="tabBarShow == 1" :user="user" ref="pageH" />
</view>
<view>
<pageI v-if="tabBarShow == 2" :user="user" ref="pageI" />
</view>
<view>
<pageF v-if="tabBarShow == 3" :user="user" :isInvest="isInvest" @tabChange="tabChange" ref="pageF" />
</view>
</view>
<view v-else>
<view>
<pageA v-if="tabBarShow == 0" :user="user" ref="pageA" />
</view>
<view>
<pageB v-if="tabBarShow == 1" :user="user" ref="pageB" />
</view>
<view>
<pageC v-if="tabBarShow == 2" :user="user" ref="pageC" />
</view>
<view>
<pageE v-if="tabBarShow == 3" :user="user" ref="pageE" />
</view>
<view>
<pageF v-if="tabBarShow == 4" :user="user" :isInvest="isInvest" @tabChange="tabChange" ref="pageF" />
</view>
</view>
<cc-myTabbar ref="myTabbar" :tabbar="tabbar" :tabBarShow="tabBarShow" @tabChange="tabChange"></cc-myTabbar>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { userHook } from '@/hooks/userInfo.js';
import { getUrlParam } from '@/utils/fun.js';
import pageA from '@/pages/home/components/user/home.vue';
import pageB from '@/pages/home/components/user/index.vue';
import pageC from '@/pages/home/components/user/sweep.vue';
import pageE from '@/pages/home/components/user/find.vue';
import pageF from '@/pages/home/components/user/mine.vue';
import pageG from '@/pages/home/components/Invest/shop.vue';
import pageH from '@/pages/home/components/Invest/order.vue';
import pageI from '@/pages/home/components/Invest/facility.vue';
const { isInvest, user, tabbar } = userHook();
let tabBarShow = ref(0);
onLoad((options) => {
if (options.q) {
const q = decodeURIComponent(options.q);
const query = getUrlParam(q);
if (query.code) {
uni.setStorageSync('invite_code', query.code);
}
}
if (options.tabBarShow) {
tabBarShow.value = options.tabBarShow;
}
});
const tabChange = (e) => {
tabBarShow.value = e.index;
};
</script>
<style lang="scss"></style>

561
pages/home/star.vue Normal file
View File

@@ -0,0 +1,561 @@
<template>
<view class="p30">
<!-- <view class="star_pile" style="margin-bottom: 30rpx"></view> -->
<view class="orderdetail_info" style="margin-bottom: 30rpx">
<view class="orderdetail_info_title">
<view>{{ info.stationName }}</view>
</view>
<view style="font-size: 26rpx; margin-bottom: 15rpx; display: flex; align-items: center">
<view style="opacity: 0.7">枪号{{ info.gunName }}</view>
<image style="width: 40rpx; height: 40rpx; margin-left: 15rpx" src="/static/icon/copy.png" @click="copy(info.gunName)" mode="widthFix"></image>
</view>
<view style="font-size: 26rpx; margin-bottom: 15rpx; opacity: 0.7">停车收费说明{{ info.occupyCostInfo }}</view>
<view style="font-size: 26rpx; opacity: 0.7">占用收费说明{{ info.parkCostInfo }}</view>
</view>
<view class="orderdetail_info" style="margin-bottom: 30rpx">
<view class="orderdetail_info_title">
<view>费用信息</view>
</view>
<view style="max-width: 420rpx">
<up-tag size="mini" :text="`当前计费时间段:${currentPrice.startTime}-${currentPrice.endTime}`" plain plainFill></up-tag>
</view>
<view class="orderdetail_info_fy">
<view class="orderdetail_info_fy_left">电站价格</view>
<view class="orderdetail_info_fy_right">
{{ currentPrice.totalAmount }}
<text style="font-weight: 500; font-size: 24rpx; color: #333; margin-left: 15rpx">/</text>
</view>
</view>
</view>
<view class="orderdetail_info" style="margin-bottom: 30rpx">
<view class="orderdetail_info_title">
<view style="display: flex; align-items: center">
<view>支付方式</view>
<!-- -->
<view style="margin-left: 15rpx">
<up-tag v-if="store.state.insertStatus == 1" size="mini" text="已插枪" plain plainFill></up-tag>
</view>
</view>
<view style="display: flex; align-items: center">
<up-button type="primary" size="small" :plain="true" text="余额充值" @click="navTo('/pages/money/recharge')"></up-button>
</view>
</view>
<view style="font-size: 30rpx; margin-bottom: 30rpx">
<!-- @click="payTo" -->
<!-- <view>支付方式</view> -->
<!-- <view>{{ payType == 1 ? '余额付款' : payType == 2 ? '电卡支付' : payType == 3 ? '预付款' : '请选择' }}</view> -->
<view>
<view
class="flex-acsb"
style="padding: 15rpx 30rpx; border-radius: 10rpx"
v-for="(item, index) in payList"
:key="index"
:style="{
border: item.id == payType ? '1rpx solid #4879e6' : ''
}"
@click="payType = item.id"
>
<view style="display: flex; align-items: center">
<image :src="`/static/icon/lie${item.id}.png`" style="width: 50rpx; height: 50rpx; margin-right: 25rpx"></image>
{{ item.name }}
</view>
<view v-if="item.id == 1" style="font-size: 28rpx; opacity: 0.7">可用余额{{ infoUser.balance || 0 }}</view>
</view>
</view>
</view>
</view>
<view class="orderdetail_info" style="margin-bottom: 30rpx">
<view class="orderdetail_info_yf">
<view class="orderdetail_info_yf_left">
<view class="orderdetail_info_yf_left_tit">
<view style="margin-right: 30rpx">预付费</view>
<up-tag size="mini" :text="`余额原路退款`" plain plainFill></up-tag>
</view>
<!-- <view>{{ dataForm.money }} </view> -->
<view class="orderdetail_info_yf_left_mon">
<!-- 预付金额 -->
<view
@click="
dataForm.money = 30;
inputBorder = false;
"
:style="{ border: `1rpx solid ${dataForm.money == 30 && !inputBorder ? '#4879e6' : '#c5c5c5'}` }"
>
30
</view>
<view
@click="
dataForm.money = 50;
inputBorder = false;
"
:style="{ border: `1rpx solid ${dataForm.money == 50 && !inputBorder ? '#4879e6' : '#c5c5c5'}` }"
>
50
</view>
<view
@click="
dataForm.money = 100;
inputBorder = false;
"
:style="{ border: `1rpx solid ${dataForm.money == 100 && !inputBorder ? '#4879e6' : '#c5c5c5'}` }"
>
100
</view>
<view @click="inputClik" :style="{ border: `1rpx solid ${inputBorder ? '#4879e6' : '#c5c5c5'}` }">
<input adjust-position v-if="inputBorder" focus type="number" v-model="dataForm.money" placeholder="自定义" />
<text v-else>自定义</text>
</view>
</view>
</view>
<!-- <view class="orderdetail_info_yf_right" @click="openDialog">预付金额</view> -->
</view>
</view>
<view class="orderdetail_info" style="margin-bottom: 30rpx" v-if="payType == 2">
<view>
<view class="flex-acsb" style="font-size: 30rpx; margin-bottom: 20rpx">
<view>当前可用电卡</view>
</view>
<view @click="userCardId = item.id" style="margin-bottom: 30rpx; position: relative" class="mt30 wallet_list" v-for="(item, index) in userCard" :key="index">
<view v-if="userCardId == item.id" style="position: absolute; top: 0; left: 0; background-color: #e45656; border-radius: 0 0 20rpx 0">
<up-icon name="checkbox-mark" color="#fff"></up-icon>
</view>
<view style="color: #fff">
<view style="font-weight: bold; font-size: 30rpx; margin-bottom: 18rpx">
{{ item.name }}
</view>
<view style="font-size: 28rpx; color: #eee">卡号{{ item.cardNo }}</view>
</view>
<view style="display: flex; flex-direction: column; align-items: center; color: #fff; font-weight: bold; font-size: 26rpx">
<view style="font-size: 36rpx; margin-bottom: 10rpx">{{ item.balance }}</view>
<view style="font-weight: 500">余额</view>
</view>
</view>
</view>
</view>
<view style="height: 500rpx"></view>
<view class="orderdetail_btn p30" style="background-color: #fff">
<view class="orderdetail_btn_left">
{{ currentPrice.totalAmount }}
<text>/ 免费停车</text>
</view>
<view>
<up-button v-if="!payType" :customStyle="{ height: '80rpx', width: '230rpx' }" disabled color="#4879e6" text="请选择支付方式" shape="circle"></up-button>
<up-button v-if="payType == 1" :customStyle="{ height: '80rpx', width: '280rpx' }" @click="toRecharge" color="#4879e6" shape="circle" text="启动充电"></up-button>
<up-button
v-if="payType == 3"
:customStyle="{ height: '80rpx', width: '280rpx' }"
@click="toRechargeYuFu"
color="#4879e6"
shape="circle"
:text="`预付${dataForm.money}元,启动充电`"
></up-button>
<!-- :text="`预付${dataForm.money}元,启动充电`" -->
<up-button
v-if="payType == 2"
:customStyle="{ height: '80rpx', width: '280rpx' }"
:disabled="!userCardId"
color="#4879e6"
:text="userCardId ? '启动充电' : '请选择电卡'"
shape="circle"
@click="toRechargeCard"
></up-button>
</view>
<!-- <view v-if="!payType" class="orderdetail_btn_right" style="opacity: 0.5;">请选择支付方式</view> -->
<!-- <view v-if="payType == 1" class="orderdetail_btn_right" @click="toRecharge">预付{{ dataForm.money }}启动充电</view> -->
<!-- <view v-if="payType == 2" class="orderdetail_btn_right" @click="toRecharge">电卡支付启动充电</view> -->
</view>
<uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog
ref="inputClose"
mode="input"
title="请输入预付金额"
:value="dataForm.money"
placeholder="请输入内容"
@confirm="dialogInputConfirm"
></uni-popup-dialog>
</uni-popup>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { gunInfo, infoAroundApi, startChargingByWallet, userCardUsableList, startChargingByCard, ordersInfo, startChargingByAdaPay, userInfo } from '@/api/api.js';
import { onLoad, onShow } from '@dcloudio/uni-app';
import store from '@/store/index.js';
import { copy } from '@/utils/fun.js';
import { useNav } from '@/hooks/useNav.js';
const { navTo } = useNav();
const inputDialog = ref(null);
let info = reactive({});
let infoUser = reactive({});
let inputBorder = ref(false);
let currentPrice = ref({});
let id = ref('');
let userCard = ref([]);
let userCardId = ref(null);
let payType = ref(1);
let dataForm = reactive({
money: 30
});
let payList = reactive([
{
id: 1,
name: '余额支付'
}
]);
onLoad((options) => {
if (options.q) {
let search = decodeURIComponent(options.q);
search = search.split('?')[1];
const pairs = search ? search.split('&') : [];
const query = {};
for (let i = 0; i < pairs.length; ++i) {
const [key, value] = pairs[i].split('=');
query[key] = query[key] || decodeURIComponent(value);
}
if (query.num) {
id.value = query.num;
infoDate(query.num);
}
}
if (options.id) {
id.value = options.id;
infoDate(options.id);
}
});
onShow(async () => {
if (uni.getStorageSync('token') && id.value) {
infoDate(id.value);
let _res = await userInfo();
infoUser.value = _res;
}
});
let getUserCard = async (e) => {
let _res = await userCardUsableList({ stationId: e });
userCard.value = _res;
if (_res.length == 0) {
payType.value = 1;
} else {
payType.value = 2;
userCardId.value = _res[0].id;
if (!payList.find((val) => val.name == '电卡支付')) {
payList.push({
id: 2,
name: '电卡支付'
});
}
}
};
let inputClik = () => {
inputBorder.value = true;
dataForm.money = dataForm.money == 30 || dataForm.money == 50 || dataForm.money == 100 ? '' : dataForm.money;
};
let infoDate = async (e) => {
let _res = await gunInfo({ deviceNo: e });
info = _res;
getUserCard(_res.stationId);
currentPrice.value = _res.currentPrice;
console.log(_res.deviceNo, '_res.deviceNo');
console.log(_res.gunNo, '_res.gunNo');
store.commit('setInsertStatus', _res.insertStatus);
uni.sendSocketMessage({
data: JSON.stringify({
command: 'sub',
deviceNo: _res.deviceNo,
gunNo: _res.gunNo
}),
success: (res) => {
console.log('发送成功');
},
fail: (err) => {
console.log(err);
console.log('发送失败');
}
});
};
let dialogInputConfirm = (e) => {
dataForm.money = e;
};
let openDialog = () => {
console.log(12345);
inputDialog.value.open();
};
let toRechargeCard = async () => {
uni.showLoading({
title: '启动充电中...',
mask: true
});
let _res = await startChargingByCard({
deviceNo: info.deviceNo,
gunNo: info.gunNo,
amount: dataForm.money,
userCardId: userCardId.value
});
};
let toRechargeYuFu = async () => {
uni.showLoading({
title: '启动充电中...',
mask: true
});
let _res = await startChargingByAdaPay({
deviceNo: info.deviceNo,
gunNo: info.gunNo,
amount: dataForm.money
});
let data = _res.payInfo;
uni.requestPayment({
provider: 'wxpay',
timeStamp: data.timeStamp,
nonceStr: data.nonceStr,
package: data.package,
signType: data.signType,
paySign: data.paySign,
success: function (r) {
store.commit('setTransactionNo', _res.transactionNo);
store.commit('setSokStatus', 0);
timeMap(_res);
},
fail: function (err) {
uni.showToast({
title: '已取消支付',
icon: 'none'
});
console.log('fail:' + JSON.stringify(err));
}
});
// store.commit('setTransactionNo', _res.transactionNo);
// store.commit('setSokStatus', 0);
// timeMap(_res);
// uni.navigateTo({
// url: `/pageOrder/recharge/recharge?transactionNo=${_res.transactionNo}&type=order`
// });
};
let toRecharge = async () => {
uni.showLoading({
title: '启动充电中...',
mask: true
});
let _res = await startChargingByWallet({
deviceNo: info.deviceNo,
gunNo: info.gunNo,
amount: dataForm.money
});
store.commit('setTransactionNo', _res.transactionNo);
store.commit('setSokStatus', 0);
timeMap(_res);
// uni.navigateTo({
// url: `/pageOrder/recharge/recharge?transactionNo=${_res.transactionNo}&type=order`
// });
// uni.navigateTo({
// url: `/pageOrder/recharge/recharge?transactionNo=${_res.transactionNo}`
// });
// console.log(_res);
};
const timeMap = (_res) => {
var time = setInterval(async () => {
if (store.state.sokStatus != 1) {
let _data = await ordersInfo({
transactionNo: _res.transactionNo
});
store.commit('setDataObj', _data);
if (_data.status == 3) {
uni.hideLoading();
uni.navigateTo({
url: `/pageOrder/recharge/recharge?transactionNo=${_res.transactionNo}&type=order`
});
clearTimeout(time);
store.commit('setSokStatus', 0);
}
if (_data.status == -1) {
uni.hideLoading();
uni.showModal({
title: '提示',
content: '启动失败,请重试',
showCancel: false,
confirmText: '确认',
success: () => {}
});
clearTimeout(time);
store.commit('setSokStatus', 0);
}
if (_data.status == -2) {
uni.hideLoading();
uni.showModal({
title: '提示',
content: '启动超时,请重试',
showCancel: false,
confirmText: '确认',
success: () => {}
});
clearTimeout(time);
store.commit('setSokStatus', 0);
}
}
}, 5000);
};
const payTo = () => {
let itemList = ['余额付款'];
if (userCard.value.length != 0) {
itemList.push('电卡支付');
}
// itemList.push('预付款');
uni.showActionSheet({
itemList: itemList,
success: function (res) {
// if (itemList[1] == '预付款' && res.tapIndex == 1) {
// payType.value = 3;
// } else {
// payType.value = res.tapIndex + 1;
// }
payType.value = res.tapIndex + 1;
},
fail: function (res) {
console.log(res.errMsg);
}
});
};
</script>
<style lang="scss">
.star_pile {
width: 100%;
box-shadow: 0rpx -6rpx 8rpx 2rpx rgba(66, 115, 229, 0.05);
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 20rpx;
background-color: #fff;
}
.orderdetail_info {
background: #ffffff;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 25rpx;
box-shadow: 0rpx -6rpx 8rpx 2rpx rgba(66, 115, 229, 0.05);
&_title {
font-size: 32rpx;
color: #232323;
margin-bottom: 30rpx;
@include flex($space: space-between);
}
&_fy {
background: linear-gradient(to right, rgba(72, 121, 230, 0.4), rgba(72, 121, 230, 0));
border-radius: 15rpx;
padding: 40rpx 20rpx 40rpx 40rpx;
color: #fff;
margin-top: 30rpx;
@include flex;
&_left {
font-size: 32rpx;
font-weight: 800;
font-style: italic;
color: #4879e6;
}
&_right {
font-size: 36rpx;
font-weight: 800;
color: #4879e6;
margin-left: 30rpx;
@include flex;
}
}
&_yf {
@include flex($space: space-between);
&_left {
flex: 1;
// view {
// @include flex;
// }
&_tit {
font-size: 28rpx;
color: rgba(51, 51, 51, 0.8);
margin-bottom: 20rpx;
@include flex;
}
&_mon {
font-size: 30rpx;
@include flex($space: space-between);
view {
// width: 22%;
padding: 15rpx 35rpx;
border: 1rpx solid #c5c5c5;
margin-right: 15rpx;
border-radius: 10rpx;
}
input {
width: 100rpx;
}
}
}
&_right {
padding: 15rpx 30rpx;
color: #1779ff;
border: 1rpx solid #1779ff;
border-radius: 50rpx;
}
}
}
.orderdetail_btn {
width: 100%;
position: fixed;
left: 0;
bottom: 0rpx;
padding: 30rpx;
@include flex($space: space-between);
&_left {
// background-color: #e5eaf4;
color: #333;
font-size: 38rpx;
font-weight: bold;
text {
font-size: 26rpx;
font-weight: 500;
}
}
&_right {
background: #1779ff;
color: #fff;
font-weight: bold;
font-size: 32rpx;
padding: 0 40rpx;
}
}
.wallet_list {
border-radius: 15rpx;
background-color: #4879e6;
padding: 20rpx 50rpx 20rpx 30rpx;
display: flex;
align-items: flex-end;
justify-content: space-between;
}
</style>

View File

@@ -0,0 +1,234 @@
<template>
<view class="u-wrap">
<view class="u-search-box">
<view class="u-search-inner">
<up-icon name="search" color="#909399" :size="28"></up-icon>
<text class="u-search-text">请输入您需要的商品名称</text>
</view>
</view>
<view class="u-menu-wrap">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop">
<view
v-for="(item, index) in tabbar"
:key="index"
class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']"
:data-current="index"
@tap.stop="swichMenu(index)"
>
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<block v-for="(item, index) in tabbar" :key="index">
<scroll-view scroll-y class="right-box" v-if="current == index">
<view class="page-view">
<view class="class-item">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container">
<view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1">
<image class="item-menu-image" :src="item1.cover" mode=""></image>
<view class="item-menu-name">{{ item1.name }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</block>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { goodsList, categoryList } from '@/api/api.js';
let tabbar = ref([]);
let scrollTop = ref(0);
let current = ref(0);
let menuHeight = ref(0);
let menuItemHeight = ref(0);
// [
// {
// name: '女装',
// foods: [
// {
// name: 'A字裙',
// key: 'A字裙',
// icon: 'https://cdn.uviewui.com/uview/common/classify/1/1.jpg',
// cat: 10
// }
// ]
// }
// ]
onLoad(() => {
categoryList().then((res) => {
tabbar.value = res.map((item, index) => {
return {
...item,
foods: []
};
});
goodsList({ categoryId: res[0].id }).then((res) => {
tabbar.value[0].foods = res;
});
});
});
async function swichMenu(index) {
if (index == current.value) return;
current.value = index;
goodsList({ categoryId: tabbar.value[index].id }).then((res) => {
tabbar.value[index].foods = res;
});
// 如果为0意味着尚未初始化
if (menuHeight.value == 0 || menuItemHeight.value == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('u-tab-item', 'menuItemHeight');
}
// 将菜单菜单活动item垂直居中
this.scrollTop = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2;
}
function getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query
.select('.' + elClass)
.fields({ size: true }, (res) => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
this[dataVal] = res.height;
})
.exec();
});
}
</script>
<style lang="scss" scoped>
.u-wrap {
height: calc(100vh);
/* #ifdef H5 */
height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
}
.u-search-box {
padding: 18rpx 30rpx;
}
.u-menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: $u-tips-color;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
}
.u-tab-item {
height: 80rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: '';
position: absolute;
border-left: 4px solid rgba(111, 162, 86, 1);
height: 45rpx;
left: 0;
top: calc(50% - 22.5rpx);
}
.u-tab-view {
height: 100%;
}
.right-box {
background-color: rgb(250, 250, 250);
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
}
.item-title {
font-size: 26rpx;
color: $u-main-color;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 24rpx;
color: $u-main-color;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 33.333333%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 20rpx;
}
.item-menu-image {
width: 120rpx;
height: 120rpx;
}
</style>

View File

@@ -0,0 +1,140 @@
<template>
<view style="padding: 20rpx 30rpx">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view style="display: flex; flex-wrap: wrap; justify-content: space-between; width: 100%">
<view v-for="(item, index) in dataList" :key="index" style="width: 336rpx; background-color: #fff; border-radius: 8rpx 8rpx">
<image :src="item.coverImageUrl" style="width: 336rpx; height: 368rpx; border-radius: 8rpx 8rpx 0 0" mode="aspectFill"></image>
<view style="padding: 15rpx 15rpx 0; font-size: 24rpx">{{ item.title }}</view>
<view style="display: flex; align-items: center; padding: 15rpx; border-radius: 0 0 8rpx 8rpx; font-size: 24rpx">
<image :src="item.authorUrl" style="width: 48rpx; height: 48rpx; border-radius: 50%; margin-right: 20rpx"></image>
<view>{{ item.authorName }}</view>
</view>
</view>
</view>
<!-- <custom-waterfalls-flow
ref="waterfallsFlowRef"
:value="dataList"
:column="column"
:columnSpace="1.5"
:seat="2"
@wapperClick="wapperClick"
@imageClick="imageClick"
@loaded="loaded"
>
<view class="item" v-for="(item, index) in dataList" :key="index" :slot="`slot${index}`">
<view class="title">{{ item.title }}</view>
<view class="desc">{{ item.content }}</view>
</view>
</custom-waterfalls-flow> -->
</z-paging>
<cc-myTabbar :tabBarShow="3"></cc-myTabbar>
<view
style="
width: 108rpx;
height: 108rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
bottom: 300rpx;
right: 30rpx;
background: #ffffff;
border-radius: 50%;
font-size: 24rpx;
"
@click="navTo('/pages/find/add')"
>
<image src="/static/image/fawen.png" style="width: 48rpx; height: 48rpx"></image>
<view>发文</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue';
import { getMerchantSelect } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
const { navTo } = useNav();
onLoad(() => {});
const paging = ref(null);
const dataList = ref([]);
const queryList = async (pageNo, pageSize) => {
getMerchantSelect({
current: pageNo,
pageSize: pageSize,
category: 'DISCOVERY'
})
.then((res) => {
paging.value.complete(res.records);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
const column = ref(2);
function loaded() {
console.log('加载完成');
}
function wapperClick(item) {
console.log('单项点击事件', item);
}
function imageClick(item) {
console.log('图片点击事件', item);
}
const waterfallsFlowRef = ref(null);
</script>
<style>
page {
background-color: #f2f5f9;
}
</style>
<style lang="scss" scoped>
.handle {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 20rpx;
padding: 10rpx;
.btn {
margin: 20rpx 10rpx;
padding: 0 20rpx;
background: #2878ff;
font-size: 28rpx;
color: #fff;
&::after {
border: 0;
}
}
}
.item {
padding: 10rpx 10rpx 20rpx;
background: #fff;
.title {
line-height: 48rpx;
font-size: 28rpx;
color: #222;
}
.desc {
font-size: 24rpx;
color: #666;
}
}
</style>

View File

@@ -0,0 +1,261 @@
<template>
<view>
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view class="search_header p30">
<view style="margin: 30rpx 0 0">
<up-swiper :list="list1" height="320rpx" keyName="imageUrl" indicator></up-swiper>
</view>
</view>
<view style="height: 35rpx"></view>
<view class="p30" style="width: 100%">
<search :top="false" @search="searchChange" />
</view>
<view style="height: 25rpx"></view>
<view style="padding: 0 30rpx">
<view class="order_list" style="position: sticky; top: 0; left: 0">
<view class="order_list_header">
<view class="order_list_header_view" @click="tabChange(1)">
<view>距我最近</view>
<view v-if="query.orderByType == 1" class="order_list_header_view_dian"></view>
</view>
<view class="order_list_header_view" @click="tabChange(2)">
<view>空闲最多</view>
<view v-if="query.orderByType == 2" class="order_list_header_view_dian"></view>
</view>
</view>
</view>
</view>
<view style="margin-bottom: 30rpx; padding: 0 30rpx" v-for="(item, index) in dataList" :key="index">
<orderList toNav :info="item"></orderList>
</view>
</z-paging>
<view style="height: 180rpx"></view>
<cc-myTabbar :tabBarShow="0"></cc-myTabbar>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad, onShow, onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { aroundAreaApi, bannerList } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
const { nav, navTo } = useNav();
const dataList = ref([]);
const paging = ref(null);
const query = reactive({
lon: '',
lat: '',
orderByType: 1, //1-最近;2-空闲较多
keyWord: ''
});
const list1 = ref([]);
onLoad(async () => {
let _res = await bannerList();
list1.value = _res;
});
onShow(() => {
});
let toKft = (e) => {
uni.makePhoneCall({
phoneNumber: '4008005326' //仅为示例
});
};
const queryList = async () => {
uni.showLoading({
title: '加载中...'
});
try {
if (!query.lon && !query.lat) {
const { longitude: lon, latitude: lat } = await uni.getLocation();
query.lon = lon;
query.lat = lat;
}
} catch (err) {
console.log(err);
}
console.log(query);
aroundAreaApi(query)
.then((res) => {
console.log(res, 'list');
paging.value.complete(res);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
let tabChange = (e) => {
query.orderByType = e;
paging.value.reload();
};
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const toOrder = () => {
uni.switchTab({
url: '/pages/order/order'
});
};
let searchChange = (e) => {
query.keyWord = e;
paging.value.reload();
};
let showMode = () => {
uni.showModal({
title: '提示',
content: '暂未开放',
showCancel: false,
confirmText: '确认',
success: () => {}
});
};
</script>
<style>
page {
/* background: linear-gradient(180deg, #ffffff 0%, #f7f7f7 100%); */
background-color: #f7f7f7;
}
</style>
<style lang="scss" scoped>
.search_header {
position: relative;
&_blur {
width: 100%;
height: 185rpx;
position: absolute;
top: 0;
left: 0;
background: #dbe6ff;
opacity: 0.8;
filter: blur(50px);
/* #ifdef MP-ALIPAY */
z-index: 0;
/* #endif */
/* #ifdef MP-WEIXIN */
z-index: -1;
/* #endif */
}
&_grid {
// margin: 35rpx 0;
margin-top: 25rpx;
border-radius: 15rpx;
@include flex($space: space-between);
&_view {
display: flex;
flex-direction: column;
align-items: center;
width: 126rpx;
font-size: 26rpx;
// background: #ffffff;
// border-radius: 24rpx 24rpx 24rpx 24rpx;
image {
width: 99rpx;
height: 99rpx;
margin-bottom: 10rpx;
}
}
}
}
.order_list {
box-sizing: border-box;
view {
box-sizing: border-box;
}
display: flex;
align-items: center;
padding: 15rpx;
margin-bottom: 30rpx;
font-size: 30rpx;
// background-color: #fff;
width: 690rpx;
border-radius: 15rpx;
// width: 690rpx;
// background: linear-gradient(180deg, #ffffff 0%, #f6f6f6 100%);
// box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(88, 140, 255, 0.1);
// border-radius: 44rpx 44rpx 0rpx 0rpx;
&_view {
padding: 15rpx 30rpx;
background-color: #fff;
border-radius: 15rpx;
margin-right: 30rpx;
}
&_active {
background-color: #6FA256;
color: #fff;
}
&_header {
width: 100%;
height: 100rpx;
@include flex;
font-weight: bold;
font-size: 36rpx;
color: #232323;
// background-color: #ffffff;
position: sticky;
top: 360rpx;
left: 0;
&_view {
position: relative;
margin-right: 50rpx;
view {
position: relative;
z-index: 99;
}
&_dian {
position: absolute !important;
bottom: 0rpx;
right: 20rpx;
width: 66rpx;
height: 20rpx;
background-color: #6FA256;
border-radius: 10rpx;
z-index: 1 !important;
}
}
}
}
button::after {
all: unset;
}
</style>

View File

@@ -0,0 +1,265 @@
<template>
<view class="content">
<!-- <search :Fixed="true" /> -->
<map
id="map"
:longitude="longitude"
@markertap="markerClick"
@callouttap="markerClick"
@regionchange="regionchange"
height="90"
width="90"
:markers="markList"
:latitude="latitude"
class="map_content"
>
<!-- #ifdef MP-WEIXIN -->
<cover-view slot="callout">
<template v-for="(item, index) in markList">
<cover-view class="callout" :marker-id="item.id">
<cover-view class="callout_item">
<cover-image class="callout_item_img" src="/static/icon/mc.png"></cover-image>
<cover-view class="callout_item_view"> {{ item.gunUseCount || 0 }}/{{ item.gunCount || 0 }}</cover-view>
</cover-view>
</cover-view>
</template>
</cover-view>
<!-- #endif -->
</map>
<uni-transition ref="mapLocationRef" :show="true">
<view class="map-location" @click="mapLocation">
<image src="/static/icon/location-marker-icon.png" mode="widthFix"></image>
</view>
</uni-transition>
<uni-transition modeClass="fade" :show="mapBox">
<view class="map_box">
<orderList toNav :Image="true" :info="infoDz" :list="infoDz.pictures" />
</view>
</uni-transition>
<cc-myTabbar :tabBarShow="1"></cc-myTabbar>
<!-- <tabbar path="/pages/index/index"></tabbar> -->
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { aroundAreaMap, infoAroundApi } from '@/api/api.js';
let longitude = ref(113.675688);
let latitude = ref(34.75527700365562);
let mapContext = ref(null);
let mapBox = ref(false);
let mapLocationRef = ref();
let infoDz = ref([]);
let markList = ref([]);
onLoad(async () => {
mapContext.value = uni.createMapContext('map');
const { longitude: lon, latitude: lat } = await uni.getLocation({
type: 'gcj02' // 根据实际需要选择坐标系
});
latitude.value = lat;
longitude.value = lon;
getInfo();
setTimeout(() => {
mapLocation();
}, 300);
});
let getInfo = async () => {
let _res = await aroundAreaMap({
orderByType: 1,
lat: latitude.value,
lon: longitude.value
});
let list = _res.map((item, index) => {
return {
id: item.id,
longitude: item.location.lng,
latitude: item.location.lat,
iconPath: '/static/icon/marker-pointer.png',
width: 20,
height: 23,
content: '2',
gunUseCount: item.gunUseCount,
gunCount: item.gunCount,
distance: item.distance,
customCallout: {
display: 'ALWAYS', // 显示方式
anchorX: 0, // 锚点X轴
anchorY: -10 // 锚点Y轴
}
};
});
list.unshift({
longitude: longitude.value,
latitude: latitude.value,
iconPath: '/static/icon/my-location-default.png',
width: 45,
height: 45,
id: -1
});
markList.value = list;
};
const mapLocation = () => {
const log = longitude.value;
const lat = latitude.value;
mapContext.value.moveToLocation({
longitude: log,
latitude: lat
});
};
// 地图缩放移动触发
const regionchange = (e) => {
// 地图移动手松开结束触发type:end
if (e.type == 'end') {
console.log(e);
console.log(e.detail.scale);
mapBox.value = false;
mapLocationRefStep(false);
}
};
// marker点击事件
const markerClick = async (e) => {
console.log(e, 'eeeeeee');
if (e.markerId == -1) {
return;
}
uni.showLoading();
let _res = await infoAroundApi({
id: e.markerId
});
let markerInfo = markList.value.find((val) => val.id == e.markerId);
let data = _res?.priceList?.find((val) => val.isCurrent == 1);
infoDz.value = {
..._res,
distance: markerInfo.distance,
priceAmount: data.totalAmount
};
console.log(infoDz, 'infoDzinfoDz');
// infoDz.value.priceAmount = data.totalAmount;
// infoDz.value.distance = data.distance;
uni.hideLoading();
mapBox.value = true;
mapLocationRefStep(true);
};
const mapLocationRefStep = (type) => {
if (type) {
mapLocationRef.value.step(
{
translateY: '-200rpx'
},
{
timingFunction: 'ease-in',
duration: 100
}
);
} else {
mapLocationRef.value.step(
{
translateY: '0rpx'
},
{
timingFunction: 'ease',
duration: 500
}
);
}
mapLocationRef.value.run();
};
</script>
<style lang="scss">
.map_content {
width: 750rpx;
height: 100vh;
/* #ifdef MP-ALIPAY */
height: calc(100vh - 100upx);
/* #endif */
}
.map-location {
width: 90rpx;
height: 90rpx;
background-color: #fff;
position: fixed;
left: 30rpx;
bottom: 570rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 5px 11px rgba(0, 0, 0, 0.2);
image {
width: 45rpx;
height: 45rpx;
}
}
.callout {
box-sizing: border-box;
background: rgba(15, 75, 203, 0.26);
border-radius: 15rpx 15rpx 15rpx 0;
padding: 10rpx 15rpx;
@include flex($direction: column);
&_item {
@include flex;
font-weight: bold;
font-size: 28rpx;
color: #ffffff;
box-sizing: border-box;
&_img {
width: 40rpx;
height: 40rpx;
margin-right: 15rpx;
}
}
&_item:nth-child(1) {
margin-bottom: 15rpx;
}
}
.recharge {
width: 690rpx;
background-color: #fff;
min-height: 300rpx;
position: fixed;
left: 30rpx;
bottom: 250rpx;
border-radius: 20rpx;
padding: 20rpx;
box-shadow: 0 5px 11px rgba(0, 0, 0, 0.2);
&_title {
font-size: 36rpx;
margin-bottom: 20rpx;
}
&_con {
font-size: 26rpx;
}
}
.map_box {
width: 690rpx;
position: fixed;
left: 30rpx;
bottom: 230rpx;
z-index: 999;
}
</style>

View File

@@ -0,0 +1,321 @@
<template>
<view class="mine">
<!-- 头部个人信息 -->
<view class="header">
<view class="user-info" @click="navTo('/pages/mine/sett')">
<up-avatar size="120rpx" :src="user.avatar" />
<view class="user-detail">
<text class="nickname">{{ user.nickName || user.username }}</text>
<text class="phone">{{ user.phone || user.mobile }}</text>
</view>
</view>
<view class="qr-code" v-if="isInvest">
<image @click="lookImg([user.qrcode])" :src="user.qrcode" mode="aspectFit" />
<text>邀请码</text>
</view>
</view>
<!-- 余额积分 -->
<view class="balance-wrap">
<view class="balance-item" @click="">
<text class="amount">{{ user.balance || '0' }}</text>
<text class="label">余额</text>
</view>
<view v-if="!isInvest" class="balance-item" @click="navTo('/pages/mine/signIn')">
<text class="amount">{{ user.points || '0' }}</text>
<text class="label">积分</text>
</view>
<view v-else class="balance-item" @click="navTo('/pageInvest/facility/facility')">
<text class="amount">{{ user.deviceNum || '0' }}</text>
<text class="label">充电桩</text>
</view>
</view>
<!-- 我的爱车 -->
<view class="vehicle-section" v-if="!isInvest">
<view class="section-header">
<text style="font-weight: bold">我的爱车</text>
<text class="more" @click="navTo('/pages/mine/car/car')">全部车辆 ></text>
</view>
<view class="car-plate" v-if="user.licensePlate" @click="navTo('/pages/mine/car/car')">
<image style="width: 198rpx; height: 56rpx; position: absolute; top: 0; left: 0" src="/static/image/carNum.png"></image>
<text>{{ user.licensePlate }}</text>
</view>
<view v-else class="add-vehicle" @click="navTo('/pages/mine/car/add')">
<view class="add-btn">
<image src="/static/icon/add.png" mode="aspectFit" />
</view>
<text>添加我的爱车</text>
</view>
<view class="vehicle-status">
<view class="status-item">
<image src="/static/icon/mine/parking.png" mode="aspectFit" />
<text>停车定位</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/charging.png" mode="aspectFit" />
<text>充电状态</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/location.png" mode="aspectFit" />
<text>精确定位</text>
</view>
</view>
</view>
<!-- 投资者功能菜单 -->
<view class="menu-grid" v-if="isInvest">
<view class="menu-item" v-for="(item, index) in menuItemsIsInvest" :key="index" @click="handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
<!-- 功能菜单 -->
<view class="menu-grid">
<view class="menu-item" v-for="(item, index) in menuItems" :key="index" @click="handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
<cc-myTabbar :tabBarShow="4" />
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { userInfo } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
import { userHook } from '@/hooks/userInfo.js';
import { lookImg} from '@/utils/fun.js';
const { navTo } = useNav();
const { user, isInvest } = userHook();
const menuItemsIsInvest = ref([
{ name: '我的订单', icon: '/static/icon/mine/order.png', path: '/pages/order/order' },
{ name: '商城', icon: '/static/icon/mine/shop.png', path: '/pageInvest/shop/shop' },
{ name: '我的银行卡', icon: '/static/icon/mine/travel.png', path: '/pages/bank/bank' },
{ name: '切换账号', icon: '/static/icon/mine/switch.png', path: '/pageInvest/login/login' }
]);
const menuItems = ref([
{ name: '我的订单', icon: '/static/icon/mine/order.png', path: '/pages/order/order' },
{ name: '收藏电站', icon: '/static/icon/mine/station.png', path: '/pages/station/favorite' },
{ name: '客服中心', icon: '/static/icon/mine/service.png', path: '/pages/service/index' },
{ name: '一号多充', icon: '/static/icon/mine/multi.png', path: '/pages/mine/multipleNumbers' },
{ name: '隐私', icon: '/static/icon/mine/privacy.png', path: '/pages/privacy/index' },
{ name: '我的银行卡', icon: '/static/icon/mine/travel.png', path: '/pages/bank/bank' },
{ name: '投资者平台', icon: '/static/icon/mine/switch.png', path: '/pageInvest/login/login' },
{ name: '退出登录', icon: '/static/icon/mine/logout.png', path: '/pages/account/logout' }
]);
const handleMenuClick = (item) => {
if (item.path) {
navTo(item.path);
return;
}
};
onMounted(async () => {
});
onShow(async () => {
isInvest.value = uni.getStorageSync('isInvest') || false;
if (isInvest.value) {
menuItems.value[6].name = '充电模式';
} else {
menuItems.value[6].name = '投资者平台';
}
});
</script>
<style lang="scss" scoped>
.mine {
min-height: 100vh;
background-color: #f7f7f7;
.header {
padding: 30rpx;
background: #fff;
display: flex;
justify-content: space-between;
align-items: center;
.user-info {
display: flex;
align-items: center;
gap: 20rpx;
.user-detail {
.nickname {
font-size: 32rpx;
font-weight: 500;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.phone {
font-size: 28rpx;
color: #666;
}
}
}
.qr-code {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
image {
width: 88rpx;
height: 88rpx;
margin-bottom: 6rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
.balance-wrap {
display: flex;
justify-content: space-around;
background: #fff;
padding: 0rpx 0 30rpx;
.balance-item {
text-align: center;
.amount {
font-size: 40rpx;
font-weight: 600;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.label {
font-size: 26rpx;
color: #666;
}
}
}
.vehicle-section {
margin: 20rpx;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
.section-header {
display: flex;
justify-content: space-between;
margin-bottom: 30rpx;
text {
font-size: 30rpx;
color: #333;
}
.more {
color: #666;
font-size: 26rpx;
}
}
.add-vehicle {
display: flex;
align-items: center;
gap: 20rpx;
margin-bottom: 30rpx;
.add-btn {
width: 80rpx;
height: 80rpx;
background: #f5f5f5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
image {
width: 40rpx;
height: 40rpx;
}
}
text {
font-size: 28rpx;
color: #666;
}
}
.vehicle-status {
display: flex;
justify-content: space-around;
border-top: 1rpx solid #f7f7f7;
padding-top: 20rpx;
.status-item {
display: flex;
align-items: center;
text-align: center;
image {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
}
.menu-grid {
margin: 20rpx;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 30rpx;
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10rpx;
image {
width: 48rpx;
height: 48rpx;
}
text {
font-size: 24rpx;
color: #333;
}
}
}
}
.car-plate {
color: #333;
font-weight: bold;
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 198rpx;
height: 56rpx;
margin: 20rpx;
text {
position: relative;
z-index: 99;
}
}
</style>

View File

@@ -0,0 +1,130 @@
<template>
<view class="sweep">
<statusBar />
<view class="sweep_note">
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/djk.png" mode="widthFix"></image>
</view>
<view>插上</view>
<view>充电枪</view>
</view>
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/djs.png" mode="widthFix"></image>
</view>
<view>点击</view>
<view>扫码充电</view>
</view>
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/cs.png" mode="widthFix"></image>
</view>
<view>点击</view>
<view>开始充电</view>
</view>
</view>
<view class="sweep_scan" style="margin-top: 300rpx">
<up-input placeholder="请输入充电枪编号" type="number" border="surround" v-model="value"></up-input>
<view style="width: 100rpx">
<up-button type="primary" text="确定" @click="toCd"></up-button>
</view>
</view>
<view class="sweep_scan" style="margin-top: 150rpx">
<up-button @click="scan" type="primary" shape="circle" text="扫码充电"></up-button>
</view>
<cc-myTabbar :tabBarShow="2"></cc-myTabbar>
<!-- <tabbar path="/pages/sweep/sweep" /> -->
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
import { urlQuery } from '@/utils/fun.js';
const { nav, navTo } = useNav();
let value = ref('');
onLoad(() => {
});
const scan = async () => {
uni.scanCode({
success: function (res) {
let query = urlQuery(res.result);
if (!query.num) {
uni.showToast({
title: '请扫描正确的设备码',
icon: 'none'
});
} else {
navTo(`/pages/home/star?id=${query.num}`);
}
// navTo(`/pages/home/star?id=${res.result}`);
}
});
};
const toCd = async () => {
if (!value.value) {
uni.showToast({
title: '请输入枪号',
icon: 'none'
});
return;
}
navTo(`/pages/home/star?id=${value.value}`);
};
</script>
<style scoped lang="scss">
.sweep {
&_note {
padding: 0 60rpx;
@include flex($space: space-between);
&_view {
@include flex($direction: column, $space: center);
font-weight: 800;
font-size: 32rpx;
color: #4879e6;
&_img {
display: flex;
align-items: flex-end;
height: 115rpx;
margin-bottom: 30rpx;
}
}
&_view:nth-child(1) {
image {
width: 151rpx;
height: 99rpx;
}
}
&_view:nth-child(2) {
image {
width: 120rpx;
height: 99rpx;
}
}
&_view:nth-child(3) {
image {
width: 106rpx;
height: 113rpx;
}
}
}
&_scan {
@include flex;
padding: 0 120rpx;
}
}
</style>

View File

@@ -0,0 +1,268 @@
<template>
<view class="content">
<!-- <search :Fixed="true" /> -->
<map
id="map"
:longitude="longitude"
@markertap="markerClick"
@callouttap="markerClick"
@regionchange="regionchange"
height="90"
width="90"
:markers="markList"
:latitude="latitude"
class="map_content"
>
<!-- #ifdef MP-WEIXIN -->
<cover-view slot="callout">
<template v-for="(item, index) in markList">
<cover-view class="callout" :marker-id="item.id">
<cover-view class="callout_item">
<cover-image class="callout_item_img" src="/static/icon/mc.png"></cover-image>
<cover-view class="callout_item_view"> {{ item.gunUseCount || 0 }}/{{ item.gunCount || 0 }}</cover-view>
</cover-view>
</cover-view>
</template>
</cover-view>
<!-- #endif -->
</map>
<uni-transition ref="mapLocationRef" :show="true">
<view class="map-location" @click="mapLocation">
<image src="/static/icon/location-marker-icon.png" mode="widthFix"></image>
</view>
</uni-transition>
<uni-transition modeClass="fade" :show="mapBox">
<view class="map_box">
<orderList toNav :Image="true" :info="infoDz" :list="infoDz.pictures" />
</view>
</uni-transition>
<cc-myTabbar :tabBarShow="1"></cc-myTabbar>
<!-- <tabbar path="/pages/index/index"></tabbar> -->
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { aroundAreaMap, infoAroundApi } from '@/api/api.js';
let longitude = ref(113.675688);
let latitude = ref(34.75527700365562);
let mapContext = ref(null);
let mapBox = ref(false);
let mapLocationRef = ref();
let infoDz = ref([]);
let markList = ref([]);
onLoad(async () => {
// #ifndef MP-WEIXIN
uni.hideTabBar();
// #endif
mapContext.value = uni.createMapContext('map');
const { longitude: lon, latitude: lat } = await uni.getLocation({
type: 'gcj02' // 根据实际需要选择坐标系
});
latitude.value = lat;
longitude.value = lon;
getInfo();
setTimeout(() => {
mapLocation();
}, 300);
});
let getInfo = async () => {
let _res = await aroundAreaMap({
orderByType: 1,
lat: latitude.value,
lon: longitude.value
});
let list = _res.map((item, index) => {
return {
id: item.id,
longitude: item.location.lng,
latitude: item.location.lat,
iconPath: '/static/icon/marker-pointer.png',
width: 20,
height: 23,
content: '2',
gunUseCount: item.gunUseCount,
gunCount: item.gunCount,
distance: item.distance,
customCallout: {
display: 'ALWAYS', // 显示方式
anchorX: 0, // 锚点X轴
anchorY: -10 // 锚点Y轴
}
};
});
list.unshift({
longitude: longitude.value,
latitude: latitude.value,
iconPath: '/static/icon/my-location-default.png',
width: 45,
height: 45,
id: -1
});
markList.value = list;
};
const mapLocation = () => {
const log = longitude.value;
const lat = latitude.value;
mapContext.value.moveToLocation({
longitude: log,
latitude: lat
});
};
// 地图缩放移动触发
const regionchange = (e) => {
// 地图移动手松开结束触发type:end
if (e.type == 'end') {
console.log(e);
console.log(e.detail.scale);
mapBox.value = false;
mapLocationRefStep(false);
}
};
// marker点击事件
const markerClick = async (e) => {
console.log(e, 'eeeeeee');
if (e.markerId == -1) {
return;
}
uni.showLoading();
let _res = await infoAroundApi({
id: e.markerId
});
let markerInfo = markList.value.find((val) => val.id == e.markerId);
let data = _res?.priceList?.find((val) => val.isCurrent == 1);
infoDz.value = {
..._res,
distance: markerInfo.distance,
priceAmount: data.totalAmount
};
console.log(infoDz, 'infoDzinfoDz');
// infoDz.value.priceAmount = data.totalAmount;
// infoDz.value.distance = data.distance;
uni.hideLoading();
mapBox.value = true;
mapLocationRefStep(true);
};
const mapLocationRefStep = (type) => {
if (type) {
mapLocationRef.value.step(
{
translateY: '-200rpx'
},
{
timingFunction: 'ease-in',
duration: 100
}
);
} else {
mapLocationRef.value.step(
{
translateY: '0rpx'
},
{
timingFunction: 'ease',
duration: 500
}
);
}
mapLocationRef.value.run();
};
</script>
<style lang="scss">
.map_content {
width: 750rpx;
height: 100vh;
/* #ifdef MP-ALIPAY */
height: calc(100vh - 100upx);
/* #endif */
}
.map-location {
width: 90rpx;
height: 90rpx;
background-color: #fff;
position: fixed;
left: 30rpx;
bottom: 570rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 5px 11px rgba(0, 0, 0, 0.2);
image {
width: 45rpx;
height: 45rpx;
}
}
.callout {
box-sizing: border-box;
background: rgba(15, 75, 203, 0.26);
border-radius: 15rpx 15rpx 15rpx 0;
padding: 10rpx 15rpx;
@include flex($direction: column);
&_item {
@include flex;
font-weight: bold;
font-size: 28rpx;
color: #ffffff;
box-sizing: border-box;
&_img {
width: 40rpx;
height: 40rpx;
margin-right: 15rpx;
}
}
&_item:nth-child(1) {
margin-bottom: 15rpx;
}
}
.recharge {
width: 690rpx;
background-color: #fff;
min-height: 300rpx;
position: fixed;
left: 30rpx;
bottom: 250rpx;
border-radius: 20rpx;
padding: 20rpx;
box-shadow: 0 5px 11px rgba(0, 0, 0, 0.2);
&_title {
font-size: 36rpx;
margin-bottom: 20rpx;
}
&_con {
font-size: 26rpx;
}
}
.map_box {
width: 690rpx;
position: fixed;
left: 30rpx;
bottom: 230rpx;
z-index: 999;
}
</style>

49
pages/index/index.vue Normal file
View File

@@ -0,0 +1,49 @@
<template>
<view>
<view v-if="!isInvest"></view>
<view v-else>
<view>
<pageA ref="pageA" />
</view>
<view>
<pageB ref="pageB" />
</view>
<view>
<pageC ref="pageC" />
</view>
<view>
<pageE ref="pageE" />
</view>
<view>
<pageF ref="pageF" />
</view>
</view>
<cc-myTabbar ref="myTabbar" :tabBarShow="1" @tabChange="tabChange"></cc-myTabbar>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { userHook } from '@/hooks/userInfo.js';
import pageA from '@/pages/index/components/user/home.vue';
import pageB from '@/pages/index/components/user/index.vue';
import pageC from '@/pages/index/components/user/sweep.vue';
import pageE from '@/pages/index/components/user/find.vue';
import pageF from '@/pages/index/components/user/mine.vue';
const { isInvest } = userHook();
let tabBarShow = ref(1);
onLoad(() => {
console.log(12354);
tabChange();
});
const tabChange = (e) => {
console.log('-----------');
};
</script>
<style lang="scss"></style>

166
pages/login/login.vue Normal file
View File

@@ -0,0 +1,166 @@
<template>
<view class="content">
<view class="head">
<image src="/static/image/login26_bg.png" mode="widthFix"></image>
</view>
<view class="title">
<text class="name">Hello!</text>
<text class="sub-name">欢迎登录电小芮</text>
</view>
<view class="form-box">
<button class="login-btn" :disabled="!aloneChecked" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">一键注册登录</button>
<view class="tip-link" style="display: flex; align-items: center">
<up-checkbox shape="circle" name="agree" usedAlone @change="change"></up-checkbox>
我已阅读并同意
<text @click="toNav('/pages/agreement/agreement?id=9')">用户协议</text>
<text @click="toNav('/pages/agreement/agreement?id=10')">隐私政策</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { login } from '@/common/js/user.js';
let aloneChecked = ref(false);
let getPhoneNumber = async (e) => {
if (!aloneChecked.value) {
return uni.showToast({
title: '请先阅读并同意用户协议和隐私政策',
icon: 'none'
});
}
try {
login(e, 2);
// let token = uni.getStorageSync('token');
// if (!token) {
// login(e, 2);
// } else {
// login();
// uni.navigateBack();
// }
} catch (err) {
uni.showToast({
title: err,
icon: 'none'
});
}
};
const toNav = (e) => {
uni.navigateTo({
url: e
});
};
const change = (e) => {
aloneChecked.value = e;
};
</script>
<style lang="scss">
page {
background-color: #e9edf6;
}
.head {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 30vh;
z-index: -1;
image {
width: 100%;
height: 100%;
}
}
.title {
padding-left: 80rpx;
padding-top: 100rpx;
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
height: 30vh;
.name {
font-size: 70rpx;
line-height: 100rpx;
font-weight: bold;
}
.sub-name {
line-height: 80rpx;
font-size: 45rpx;
letter-spacing: 8rpx;
font-weight: bold;
}
}
.form-box {
padding: 0rpx 80rpx;
.row-input {
display: flex;
justify-content: flex-start;
align-items: center;
height: 100rpx;
background-color: #ffffff;
border-radius: 12rpx;
margin: 50rpx 0rpx;
image {
margin: 0 25rpx;
flex-shrink: 0;
width: 31rpx;
height: 35rpx;
}
input {
font-size: 30rpx;
flex: 1;
}
}
.menu-link {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 26rpx;
}
.login-btn {
margin-top: 250rpx;
display: flex;
justify-content: center;
align-items: center;
height: 90rpx;
border-radius: 12rpx;
background-color: #819682;
color: #f4f4f4;
font-size: 30rpx;
letter-spacing: 5rpx;
box-shadow: 0rpx 5rpx 20rpx #94ac95;
}
.tip-link {
display: flex;
justify-content: center;
letter-spacing: 3rpx;
line-height: 150rpx;
font-size: 26rpx;
text {
color: #57a2ee;
}
}
}
</style>

100
pages/mine/car/add.vue Normal file
View File

@@ -0,0 +1,100 @@
<template>
<view class="container">
<view class="container_block">
<view class="vehicle-status">
<view class="status-item">
<image src="/static/icon/mine/parking.png" mode="aspectFit" />
<text>停车定位</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/charging.png" mode="aspectFit" />
<text>充电状态</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/location.png" mode="aspectFit" />
<text>精确定位</text>
</view>
</view>
<car-number-input @numberInputResult="numberInputResult"></car-number-input>
<view style="color: #6fa256; font-size: 24rpx; margin-top: 40rpx">绑定车牌后在指定充电站可享减免停车费或免费停车</view>
</view>
<button class="confirm-button" @click="submit">确定</button>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { carAdd } from '@/api/api.js';
let formData = ref({
licensePlate: '',
isDefault: 0
});
const numberInputResult = (e) => {
formData.value.licensePlate = e;
};
const submit = () => {
carAdd(formData.value).then((res) => {
uni.showModal({
title: '提示',
content: '添加成功',
showCancel: false,
success: (res) => {
if (res.confirm) {
uni.navigateBack();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
});
};
</script>
<style lang="scss">
.container {
padding: 30rpx;
&_block {
width: 100%;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
padding: 28rpx 8rpx;
}
}
.confirm-button {
width: 488rpx;
height: 86rpx;
background: #6fa256;
border-radius: 44rpx 44rpx 44rpx 44rpx;
font-size: 26rpx;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
margin-top: 332rpx;
}
.vehicle-status {
display: flex;
justify-content: space-around;
margin-bottom: 25rpx;
.status-item {
display: flex;
align-items: center;
text-align: center;
image {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
</style>

144
pages/mine/car/car.vue Normal file
View File

@@ -0,0 +1,144 @@
<template>
<view class="car-list">
<view class="car-item" v-for="(car, index) in cars" :key="index">
<view class="car-number">
<view>NO{{ index + 1 }}.</view>
<image @click="delCar(car)" src="/static/image/cardel.png" style="width: 40rpx; height: 40rpx"></image>
</view>
<view class="car-info">
<view>
<view class="car-default">
<view>默认车辆</view>
</view>
<view class="car-plate">
<image style="width: 198rpx; height: 56rpx; position: absolute; top: 0; left: 0" src="/static/image/carNum.png"></image>
<text>{{ car.licensePlate }}</text>
</view>
</view>
<image :src="car.image" class="car-image" mode="widthFix" />
</view>
</view>
<view class="add-car">
<view class="add-car-jia">+</view>
<view @click="navTo('/pages/mine/car/add')">添加我的爱车</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useNav } from '@/hooks/useNav.js';
import { carList, carDel } from '@/api/api.js';
import { onLoad } from '@dcloudio/uni-app';
const { navTo } = useNav();
const cars = ref([]);
onLoad(() => {
getList();
});
const getList = () => {
carList().then((res) => {
cars.value = res.map((item, index) => {
return {
...item,
image: '/static/image/car-image.png'
};
});
});
};
const delCar = (item) => {
uni.showModal({
title: '提示',
content: '是否删除该车辆信息?',
success: (res) => {
if (res.confirm) {
carDel(item.id).then((res) => {
getList();
});
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
</script>
<style lang="scss">
.car-list {
padding: 30rpx;
}
.car-item {
width: 100%;
padding: 24rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
margin-bottom: 20rpx;
// display: flex;
// align-items: center;
// justify-content: space-between;
}
.car-number {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: bold;
}
.car-info {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.car-default {
font-size: 26rpx;
margin-bottom: 45rpx;
}
.car-plate {
color: #333;
font-weight: bold;
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 198rpx;
height: 56rpx;
text {
position: relative;
z-index: 99;
}
}
.car-image {
width: 336rpx;
margin-left: 10px;
}
.add-car {
width: 690rpx;
height: 176rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
margin-top: 20px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 36rpx;
color: #232323;
}
.add-car-jia {
width: 92rpx;
height: 92rpx;
background: rgba(111, 162, 86, 0.1);
border-radius: 50%;
font-weight: 500;
color: rgba(111, 162, 86, 1);
font-size: 70rpx;
line-height: 80rpx;
text-align: center;
margin-right: 25rpx;
}
</style>

96
pages/mine/card.vue Normal file
View File

@@ -0,0 +1,96 @@
<template>
<view class="earnings p30">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view style="margin-bottom: 30rpx" @click="toCrud(item)" class="mt30 wallet_list" v-for="(item, index) in dataList" :key="index">
<view style="color: #fff">
<view style="font-weight: bold; font-size: 32rpx; margin-bottom: 18rpx">
{{ item.name }}
</view>
<view style="margin-bottom: 12rpx; font-size: 28rpx; color: #eee">
卡号{{ item.cardNo }}
</view>
<view style="margin-bottom: 12rpx; font-size: 28rpx; color: #eee">
电站{{ item.stationName }}
</view>
<view style="font-size: 28rpx; color: #eee">
商户{{ item.merchantName }}
</view>
</view>
<view style="display: flex; flex-direction: column; align-items: center; color: #fff; font-weight: bold; font-size: 26rpx">
<view style="font-size: 55rpx; margin-bottom: 30rpx">{{ item.balance }}</view>
<view style="font-weight: 500">余额</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { reactive, ref, computed } from 'vue';
import { onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { timeFormat } from '@/uni_modules/uview-plus';
import { userCardList } from '@/api/api.js';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
const changeSele = (e) => {
paging.value.reload();
};
const { nav, navTo } = useNav();
let getInfo = ref({});
const paging = ref(null);
let dataList = ref([]);
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize
};
userCardList(params)
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
let toCrud = ()=>{
uni.navigateTo({
url:'./cardList?id=' + e.id
})
}
</script>
<style scoped lang="scss">
.wallet_list {
border-radius: 15rpx;
background-color: #4879e6;
padding: 35rpx 50rpx 35rpx 30rpx;
display: flex;
align-items: flex-end;
justify-content: space-between;
}
</style>

151
pages/mine/cardList.vue Normal file
View File

@@ -0,0 +1,151 @@
<template>
<view class="earnings p30">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view style="margin-bottom: 30rpx" class="mt30 wallet_list" v-for="(item, index) in dataList" :key="index">
<view class="wallet_list_left">
<view>{{ item.recordName || '-' }}</view>
<view>{{ item.createTime }}</view>
</view>
<view class="wallet_list_right" style="display: flex; flex-direction: column; align-items: flex-end">
<!-- <view style="margin-bottom: 10rpx; width: 75rpx">
<view></view>
<up-tag v-if="item.pointType == 2" size="mini" text="余额" type="warning" plain plainFill></up-tag>
<up-tag v-if="item.pointType == 1" size="mini" text="收益" plain plainFill></up-tag>
</view> -->
<view>{{ item.amount }}</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { reactive, ref, computed } from 'vue';
import { onPullDownRefresh, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
import { timeFormat } from '@/uni_modules/uview-plus';
import { userCardRecord } from '@/api/api.js';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
let id = ref('');
const changeSele = (e) => {
paging.value.reload();
};
const { nav, navTo } = useNav();
let getInfo = ref({});
const paging = ref(null);
let dataList = ref([]);
let isPagingRefNotFound = () => {
return !paging.value;
};
onLoad((options) => {
id.value = options.id;
});
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize,
id: id.value
};
userCardRecord(params)
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
</script>
<style scoped lang="scss">
.wallet_pall {
width: 690rpx;
height: 272rpx;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 40rpx;
background: #ffffff;
&_header {
font-weight: bold;
font-size: 26rpx;
color: #002ea4;
}
&_ye {
display: flex;
align-items: center;
justify-content: space-between;
height: 70%;
view:nth-child(1) {
font-weight: bold;
font-size: 68rpx;
color: #002ea4;
}
view:nth-child(2) {
width: 128rpx;
height: 58rpx;
background: rgba(0, 46, 164, 0.07);
border-radius: 32rpx 32rpx 32rpx 32rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #002ea4;
}
}
}
.wallet_list {
width: 690rpx;
// height: 120rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
padding: 15rpx 30rpx;
@include flex($space: space-between);
&_left {
view:nth-child(1) {
font-weight: bold;
font-size: 28rpx;
color: #232323;
margin-bottom: 10rpx;
}
view:nth-child(2) {
font-size: 24rpx;
color: #232323;
}
view:nth-child(3) {
font-size: 24rpx;
color: #232323;
}
view:nth-child(4) {
font-size: 24rpx;
color: #232323;
}
}
&_right {
font-weight: bold;
font-size: 28rpx;
color: #ff2727;
}
}
</style>

18
pages/mine/earnings.vue Normal file
View File

@@ -0,0 +1,18 @@
<template>
<view class="earnings">
<up-cell-group>
<up-cell icon="integral-fill" title="会员等级" value="新版本"></up-cell>
</up-cell-group>
</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {}
};
</script>
<style></style>

225
pages/mine/incomeList.vue Normal file
View File

@@ -0,0 +1,225 @@
<template>
<view class="container">
<view class="balance-section text-center">
<view class="grey-text mb12">总余额</view>
<view class="amount">{{ info.balance || 0 }}</view>
<view class="details">
<view class="detail-item right-border">
<view class="grey-text mb12">可提取金额</view>
<view class="text-40-bold">{{ userInfo.balance || 0 }}</view>
</view>
<view class="detail-item">
<view class="grey-text mb12">冻结金额</view>
<view class="text-40-bold">0</view>
</view>
</view>
</view>
<view class="transaction-section">
<view class="transaction-date">
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text>{{ date }}</text>
<image src="/static/icon/xai.png"></image>
</picker>
</view>
<view class="text-24-bold mx-24">充值{{ statistics.inMoney }} 提现/支出人民币{{ statistics.outMoney }}</view>
<z-paging ref="paging" v-model="recordData" use-page-scroll @query="queryList">
<view class="transaction-list">
<view class="transaction-item" v-for="(item, index) in recordData" :key="index">
<text class="text-24-bold" :class="[getItemColor(item.sourceType)]">
{{item.recordName}}{{item.amount}}
</text>
<view class="line"></view>
<text class="text-24-bold">{{item.createTime}}</text>
</view>
</view>
</z-paging>
</view>
<view class="button-section">
<!-- <button class="withdraw-button">提现</button> -->
<button class="recharge-button" @click="navTo('/pages/money/recharge')">充值</button>
</view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { userInfo, walletRecord } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
const { navTo } = useNav();
const info = ref({});
const date = ref()
const statistics = reactive({
outMoney: 0,
inMoney: 0,
})
const paging = ref()
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = currentDate.getMonth() + 1;
date.value = year + "-" + (month < 10 ? "0" + month : month);
onMounted(async () => {
const res = await userInfo();
info.value = res;
});
const recordData = ref()
const getItemColor = v => {
if (v == 11) {
return "text-green-dark"
} else if(v == 21) {
return "text-red"
} else {
return ""
}
}
const queryList = async (pageNo, pageSize) => {
walletRecord({
current: pageNo,
pageSize,
time: date.value
})
.then((res) => {
statistics.inMoney = res.inMoney;
statistics.outMoney = res.outMoney;
paging.value.complete(res.record);
uni.hideLoading();
})
.catch((res) => {
paging.value.complete(false);
uni.hideLoading();
});
};
const bindDateChange = e => {
date.value = e.detail.value;
paging.value.reload();
}
</script>
<style scoped lang="scss">
.container {
// padding: 36rpx 30rpx;
.balance-section {
background: #FFFFFF;
border-radius: 8rpx;
margin: 36rpx 30rpx;
padding: 36rpx 48rpx;
.grey-text {
font-weight: 400;
font-size: 24rpx;
color: #232323;
}
.amount {
font-weight: bold;
font-size: 54rpx;
color: #232323;
margin-bottom: 28rpx;
}
.details {
border-top: 2rpx solid #EEEEEE;
padding-top: 20rpx;
display: flex;
.detail-item {
width: 50%;
}
.right-border {
border-right: 2rpx solid #EEEEEE;
}
}
}
.text-40-bold {
font-weight: bold;
font-size: 40rpx;
color: #232323;
}
.text-24-bold {
font-weight: bold;
font-size: 24rpx;
color: #232323;
}
.mb12 {
margin-bottom: 12rpx;
}
.text-center {
text-align: center;
}
.transaction-section {
background: #FFFFFF;
border-radius: 8rpx;
margin: 36rpx 30rpx;
.transaction-date {
font-family: DIN, DIN;
font-weight: bold;
font-size: 40rpx;
color: #232323;
padding: 24rpx 24rpx 14rpx;
image {
width: 24rpx;
height: 24rpx;
margin-left: 18rpx;
}
}
.mx-24 {
margin-left: 24rpx;
margin-right: 24rpx;
}
.transaction-list {
padding: 36rpx 24rpx;
.transaction-item {
display: flex;
align-items: center;
margin-bottom: 24rpx;
.line {
flex: 1;
height: 0;
border-top: 2rpx dashed #999999;
margin: 0 32rpx;
}
}
}
}
.text-green-dark {
color: #6FA256;
}
.text-green-bright {
color: #3BCF73;
}
.text-red {
color: #FF2C2C;
}
.button-section {
position: fixed;
width: 100%;
display: flex;
justify-content: space-evenly;
left: 0;
bottom: 76rpx;
.withdraw-button, .recharge-button {
width: 330rpx;
height: 92rpx;
line-height: 92rpx;
border-radius: 46rpx;
font-weight: bold;
font-size: 32rpx;
margin: 0;
border-width: 0;
}
.withdraw-button::after, .recharge-button::after {
border-width: 0;
}
.withdraw-button {
background: #eaf1e7;
color: #77B658;
}
.recharge-button {
background: #77B658;
color: #FFFFFF;
}
}
}
</style>

322
pages/mine/mine.vue Normal file
View File

@@ -0,0 +1,322 @@
<template>
<view class="mine">
<!-- 头部个人信息 -->
<view class="header">
<view class="user-info" @click="navTo('/pages/mine/sett')">
<up-avatar size="120rpx" :src="user.avatar" />
<view class="user-detail" v-if="user.nickName || user.username">
<text class="nickname">{{ user.nickName || user.username }}</text>
<text class="phone">{{ user.phone || user.mobile }}</text>
</view>
<view class="user-detail" v-else>
<text class="nickname">您还未登录</text>
</view>
</view>
<view class="qr-code" v-if="isInvest">
<image @click="lookImg([user.qrcode])" :src="user.qrcode" mode="aspectFit" />
<text>邀请码</text>
</view>
</view>
<!-- 余额积分 -->
<view class="balance-wrap">
<view class="balance-item" @click="">
<text class="amount">{{ user.balance || '0' }}</text>
<text class="label">余额</text>
</view>
<view v-if="!isInvest" class="balance-item" @click="navTo('/pages/mine/signIn')">
<text class="amount">{{ user.points || '0' }}</text>
<text class="label">积分</text>
</view>
<view v-else class="balance-item" @click="navTo('/pageInvest/facility/facility')">
<text class="amount">{{ user.deviceNum || '0' }}</text>
<text class="label">充电桩</text>
</view>
</view>
<!-- 我的爱车 -->
<view class="vehicle-section" v-if="!isInvest">
<view class="section-header">
<text style="font-weight: bold">我的爱车</text>
<text class="more" @click="navTo('/pages/mine/car/car')">全部车辆 ></text>
</view>
<view class="car-plate" v-if="user.licensePlate" @click="navTo('/pages/mine/car/car')">
<image style="width: 198rpx; height: 56rpx; position: absolute; top: 0; left: 0" src="/static/image/carNum.png"></image>
<text>{{ user.licensePlate }}</text>
</view>
<view v-else class="add-vehicle" @click="navTo('/pages/mine/car/add')">
<view class="add-btn">
<image src="/static/icon/add.png" mode="aspectFit" />
</view>
<text>添加我的爱车</text>
</view>
<view class="vehicle-status">
<view class="status-item">
<image src="/static/icon/mine/parking.png" mode="aspectFit" />
<text>停车定位</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/charging.png" mode="aspectFit" />
<text>充电状态</text>
</view>
<view class="status-item">
<image src="/static/icon/mine/location.png" mode="aspectFit" />
<text>精确定位</text>
</view>
</view>
</view>
<!-- 投资者功能菜单 -->
<view class="menu-grid" v-if="isInvest">
<view class="menu-item" v-for="(item, index) in menuItemsIsInvest" :key="index" @click="handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
<!-- 功能菜单 -->
<view class="menu-grid">
<view class="menu-item" v-for="(item, index) in menuItems" :key="index" @click="handleMenuClick(item)">
<image :src="item.icon" mode="aspectFit" />
<text>{{ item.name }}</text>
</view>
</view>
<cc-myTabbar :tabBarShow="4" />
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { userInfo } from '@/api/api.js';
import { useNav } from '@/hooks/useNav.js';
import { userHook } from '@/hooks/userInfo.js';
import { lookImg } from '@/utils/fun.js';
const { navTo } = useNav();
const { user, isInvest } = userHook();
const menuItemsIsInvest = ref([
{ name: '我的订单', icon: '/static/icon/mine/order.png', path: '/pages/order/order' },
{ name: '商城', icon: '/static/icon/mine/shop.png', path: '/pageInvest/shop/shop' },
{ name: '我的银行卡', icon: '/static/icon/mine/travel.png', path: '/pages/bank/bank' },
{ name: '切换账号', icon: '/static/icon/mine/switch.png', path: '/pageInvest/login/login' }
]);
const menuItems = ref([
{ name: '我的订单', icon: '/static/icon/mine/order.png', path: '/pages/order/order' },
{ name: '收藏电站', icon: '/static/icon/mine/station.png', path: '/pages/station/favorite' },
{ name: '客服中心', icon: '/static/icon/mine/service.png', path: '/pages/service/index' },
{ name: '一号多充', icon: '/static/icon/mine/multi.png', path: '/pages/mine/multipleNumbers' },
{ name: '隐私', icon: '/static/icon/mine/privacy.png', path: '/pages/privacy/index' },
{ name: '我的银行卡', icon: '/static/icon/mine/travel.png', path: '/pages/bank/bank' },
{ name: '投资者平台', icon: '/static/icon/mine/switch.png', path: '/pageInvest/login/login' },
{ name: '退出登录', icon: '/static/icon/mine/logout.png', path: '/pages/account/logout' }
]);
const handleMenuClick = (item) => {
if (item.path) {
navTo(item.path);
return;
}
};
onMounted(async () => {});
onShow(async () => {
isInvest.value = uni.getStorageSync('isInvest') || false;
if (isInvest.value) {
menuItems.value[6].name = '充电模式';
} else {
menuItems.value[6].name = '投资者平台';
}
});
</script>
<style lang="scss" scoped>
.mine {
min-height: 100vh;
background-color: #f7f7f7;
.header {
padding: 30rpx;
background: #fff;
display: flex;
justify-content: space-between;
align-items: center;
.user-info {
display: flex;
align-items: center;
gap: 20rpx;
.user-detail {
.nickname {
font-size: 32rpx;
font-weight: 500;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.phone {
font-size: 28rpx;
color: #666;
}
}
}
.qr-code {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
image {
width: 88rpx;
height: 88rpx;
margin-bottom: 6rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
.balance-wrap {
display: flex;
justify-content: space-around;
background: #fff;
padding: 0rpx 0 30rpx;
.balance-item {
text-align: center;
.amount {
font-size: 40rpx;
font-weight: 600;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.label {
font-size: 26rpx;
color: #666;
}
}
}
.vehicle-section {
margin: 20rpx;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
.section-header {
display: flex;
justify-content: space-between;
margin-bottom: 30rpx;
text {
font-size: 30rpx;
color: #333;
}
.more {
color: #666;
font-size: 26rpx;
}
}
.add-vehicle {
display: flex;
align-items: center;
gap: 20rpx;
margin-bottom: 30rpx;
.add-btn {
width: 80rpx;
height: 80rpx;
background: #f5f5f5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
image {
width: 40rpx;
height: 40rpx;
}
}
text {
font-size: 28rpx;
color: #666;
}
}
.vehicle-status {
display: flex;
justify-content: space-around;
border-top: 1rpx solid #f7f7f7;
padding-top: 20rpx;
.status-item {
display: flex;
align-items: center;
text-align: center;
image {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
}
text {
font-size: 24rpx;
color: #666;
}
}
}
}
.menu-grid {
margin: 20rpx;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 30rpx;
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10rpx;
image {
width: 48rpx;
height: 48rpx;
}
text {
font-size: 24rpx;
color: #333;
}
}
}
}
.car-plate {
color: #333;
font-weight: bold;
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 198rpx;
height: 56rpx;
margin: 20rpx;
text {
position: relative;
z-index: 99;
}
}
</style>

View File

@@ -0,0 +1,41 @@
<template>
<view class="p30" style="padding: 30rpx">
<view class="multipleNumbers_1">
<view class="multipleNumbers_1_info" style="width: 330rpx">
<view style="font-weight: bold; font-size: 40rpx; color: #232323; margin-bottom: 36rpx">开通一号多充</view>
<view style="font-weight: 400; font-size: 24rpx; color: #333333; text-align: left">
开通后可以让您使用同一个 账号同时给多辆车进行充电 你可以按需调整同时充电的数量
</view>
</view>
<image style="width: 330rpx" mode="widthFix" src="/static/image/Multiple_numbers.png"></image>
</view>
<view style="height: 30rpx"></view>
<view class="multipleNumbers_1">
<view style="font-weight: bold; font-size: 32rpx; color: #232323">开通一号多充</view>
<view style="display: flex; align-items: center">
<view>1</view>
<image src="/static/icon/youjin.png" style="width: 28rpx; margin-left: 15rpx" mode="widthFix"></image>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {}
};
</script>
<style scoped lang="scss">
.multipleNumbers_1 {
background: #ffffff;
border-radius: 10rpx 10rpx 10rpx 10rpx;
padding: 25rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
</style>

84
pages/mine/sett.vue Normal file
View File

@@ -0,0 +1,84 @@
<template>
<view class="p30">
<view style="background-color: #fff; border-radius: 15rpx">
<up-cell-group :border="false">
<button style="all: unset" open-type="chooseAvatar" @chooseavatar="chooseAvatar">
<up-cell title="头像" :isLink="true" size="min">
<template #value>
<up-avatar :src="user.avatarUrl || user.avatar"></up-avatar>
</template>
</up-cell>
</button>
<up-cell title="昵称" :isLink="true" size="min" @click="upNickName">
<template #value>
<text class="u-slot-value">{{ user.nickname || user.nickName }}</text>
</template>
</up-cell>
<up-cell title="手机号" size="min" :border="false">
<template #value>
<text class="u-slot-value">{{ user.mobile || user.phone || '-' }}</text>
</template>
</up-cell>
</up-cell-group>
</view>
<view style="height: 100rpx"></view>
<up-button type="error" text="退出登录" @click="outLogin"></up-button>
</view>
</template>
<script setup>
import { onShow } from '@dcloudio/uni-app';
import { investUserModify, updateNickName, updateAvatar } from '@/api/api.js';
import { ref } from 'vue';
import { uploadFiles } from '@/utils/fun.js';
import { userHook } from '@/hooks/userInfo.js';
const { user, isInvest, fetchUserData } = userHook();
const chooseAvatar = async (e) => {
let img = await uploadFiles(e.detail.avatarUrl);
console.log(img);
isInvest.value ? await investUserModify({ ...user, avatarUrl: img }) : await updateAvatar({ avatar: img });
fetchUserData();
};
const upNickName = () => {
uni.showModal({
title: '修改昵称',
content: user.nickname || user.nickName || "",
editable: true,
success: async function (res) {
if (res.confirm) {
isInvest.value ? await investUserModify({ ...user, nickname: res.content }) : await updateNickName({ nickName: res.content });
fetchUserData()
console.log(res);
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
const outLogin = () => {
uni.showModal({
title: '提示',
content: '是否确认退出登录?',
success: (res) => {
if (res.confirm) {
uni.clearStorageSync();
uni.reLaunch({
url: '/pages/home/home'
});
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
</script>
<style>
button::after {
all: unset;
}
</style>

109
pages/mine/signIn.vue Normal file
View File

@@ -0,0 +1,109 @@
<template>
<view>
<gb-qiandao
:days="dayInfo.day"
:taskList="dayInfo.taskStatusParams"
:completeDay="dayInfo.day"
:dayList="dayList"
:taskStatus="dayInfo.isSignInToday"
@receiveMoney="receiveMoney"
@listTab="listTab"
></gb-qiandao>
</view>
</template>
<script>
import { findSignInRecord, signIn, shareMiniProgram } from '@/api/api.js';
export default {
data() {
return {
// 签到天数
days: 0,
// 签到任务第一个
play_number: 0,
// 签到任务第二个
search_number: 0,
// 签到任务第三个
full_ad: 0,
// 已完成天数
completeDay: 0,
// 签到状态 0.代表未签到 1.代表已签到
taskStatus: 0,
// 签到规则
rule: '这里是签到规则,你可以任意编辑',
// 签到任务奖励数组
dayList: [1, 1, 2, 3, 5, 6, 7],
// 签到任务
taskList: [
{
title: '试玩游戏',
img: '../../static/yx.png',
number: 1,
dec: '完成游戏赚相关游戏'
},
{
title: '试玩应用',
img: '../../static/zl.png',
number: 1,
dec: '完成应用赚相关任务'
},
{
title: '观看广告',
img: '../../static/kgg.png',
number: 10,
dec: '观看广告赚相关广告'
}
],
dayInfo: {}
};
},
onLoad() {
this.getData();
},
methods: {
// 获取用户签到得相关信息,自己写接口获取即可
getData() {
findSignInRecord().then((res) => {
this.dayInfo = res;
});
},
// 签到并领取奖励
receiveMoney() {
signIn().then((res) => {
uni.showToast({
title: '签到成功',
icon: 'none',
position: 'bottom'
});
this.getData();
});
},
// 签到任务完成
listTab(i) {
if (i == 0) {
uni.showToast({
title: '跳转第一个任务',
icon: 'none',
position: 'bottom'
});
}
if (i == 1) {
uni.showToast({
title: '跳转第二个任务',
icon: 'none',
position: 'bottom'
});
}
if (i == 2) {
shareMiniProgram().then((res) => {
this.getData();
});
}
}
}
};
</script>
<style></style>

341
pages/money/recharge.vue Normal file
View File

@@ -0,0 +1,341 @@
<template>
<view class="buy">
<view class="title">
<!-- <image src="../../static/image/travel/matching/buy.png"></image> -->
<text class="text">当前余额</text>
<text class="num">{{info.balance}}</text>
</view>
<view class="number">
<view class="list">
<view :class="num == index ? 'item real' : 'item'" v-for="(item, index) in list" :key="index" @click="pick(item, index)">
<view class="card">
<view class="top">
<text>{{ item.number }}</text>
</view>
<!-- <text class="money">{{ item.money }}</text> -->
</view>
</view>
<view :class="num == 'input' ? 'item real' : 'item'" @click="pick('input', 'input')">
<view class="card">
<view class="top" style="padding: 0 15rpx; text-align: center">
<input @change="inputChange" placeholder="其他面额" style="font-weight: bold; color: #666666" v-model="moneyNum" type="number" />
</view>
<!-- <text class="money">{{ item.money }}</text> -->
</view>
</view>
</view>
<view class="tip">
<text class="titl">温馨提示</text>
<view>
<text>1本次充值金额尽可用于充电消费</text>
</view>
<view>
<text>2若充值时若使用了第三方优惠抵扣时,该笔金额不支持直接退款</text>
</view>
</view>
</view>
<view style="position: fixed; bottom: 0; left: 0; width: 750rpx">
<view style="display: flex; align-items: center; justify-content: center; font-size: 26rpx; background-color: rgba(72, 121, 230, 0.3); padding: 15rpx 0">
<up-checkbox shape="circle" name="agree" usedAlone @change="change"></up-checkbox>
我已阅读并同意
<text style="color: #4879e6">云充电用户充值协议</text>
</view>
<view style="display: flex; align-items: center; justify-content: space-between; padding: 20rpx 30rpx">
<view style="font-size: 40rpx; font-weight: bold">
{{ money }}
<text style="font-size: 26rpx; font-weight: 500"></text>
</view>
<view style="width: 220rpx">
<up-button @click="toUp" color="#4879e6" text="充值" shape="circle" :disabled="!aloneChecked"></up-button>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { jqbPay,userInfo,adaPay } from '@/api/api.js';
import { onShow, onLoad } from '@dcloudio/uni-app';
let info = ref({});
let money = ref(30);
let moneyNum = ref('');
let num = ref(0);
let aloneChecked = ref(false);
let list = ref([
{
number: '¥30',
money: '30'
},
{
number: '¥50',
money: '50'
},
{
number: '¥80',
money: '80'
},
{
number: '¥100',
money: '100'
},
{
number: '¥200',
money: '200'
},
{
number: '¥300',
money: '300'
},
{
number: '¥400',
money: '400'
},
{
number: '¥500',
money: '500'
}
]);
const pick = (item, index) => {
if (item != 'input') {
money.value = item.money;
moneyNum.value = '';
}
num.value = index;
};
const change = (e) => {
aloneChecked.value = e;
console.log(e);
};
const toUp = () => {
adaPay({
amount: money.value
}).then((res) => {
let data = res;
uni.requestPayment({
provider: 'wxpay',
timeStamp: data.timeStamp,
nonceStr: data.nonceStr,
package: data.package,
signType: data.signType,
paySign: data.paySign,
success: function (r) {
uni.showModal({
title: '提示',
content: '充值成功',
showCancel: false,
success: function (res) {
if (res.confirm) {
uni.navigateBack();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
});
// jqbPay({
// amount: money.value
// }).then((res) => {
// let data = JSON.parse(res.payData);
// uni.requestPayment({
// provider: 'wxpay',
// timeStamp: data.timeStamp,
// nonceStr: data.nonceStr,
// package: data.package,
// signType: data.signType,
// paySign: data.paySign,
// success: function (r) {
// uni.showModal({
// title: '提示',
// content: '充值成功',
// showCancel: false,
// success: function (res) {
// if (res.confirm) {
// uni.navigateBack();
// } else if (res.cancel) {
// console.log('用户点击取消');
// }
// }
// });
// },
// fail: function (err) {
// console.log('fail:' + JSON.stringify(err));
// }
// });
// });
};
onShow(async () => {
let _res = await userInfo();
info.value = _res;
});
const inputChange = (e) => {
money.value = e.detail.value;
};
</script>
<style lang="scss" scoped>
.buy {
width: 100%;
height: 100%;
.title {
display: flex;
align-items: center;
padding: 20rpx 0 20rpx 50rpx;
background-color: #ffffff;
> image {
width: 32rpx;
height: 32rpx;
margin-right: 6rpx;
}
> text {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 40rpx;
}
.num {
color: #ff4141;
}
}
.number {
width: 100%;
background-color: #ffffff;
margin-top: 18rpx;
display: flex;
flex-direction: column;
align-items: center;
.list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 38rpx 40rpx 0rpx 40rpx;
.item {
width: 194rpx;
height: 194rpx;
background: #ffffff;
box-shadow: 0rpx 0rpx 6rpx 0rpx rgba(0, 0, 0, 0.1);
border-radius: 20rpx;
margin-bottom: 44rpx;
display: flex;
.card {
width: 194rpx;
height: 194rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.top {
display: flex;
align-items: center;
> text {
font-size: 32rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #666666;
line-height: 44rpx;
margin-right: 12rpx;
}
> image {
width: 30rpx;
height: 30rpx;
}
}
.money {
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 34rpx;
margin-top: 12rpx;
}
}
.recommend {
width: 112rpx;
height: 36rpx;
background: #f3f2ea;
border-radius: 8rpx 0rpx 8rpx 0rpx;
position: absolute;
text-align: center;
margin-top: -18rpx;
> text {
font-size: 20rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #666666;
line-height: 36rpx;
}
}
}
.real {
border: 2rpx solid #f88700;
background-color: rgba(248, 135, 0, 0.1);
}
&:after {
content: '';
width: 194rpx;
}
}
.sure {
width: 582rpx;
height: 80rpx;
background: #ff6a5f;
border-radius: 40rpx;
text-align: center;
> text {
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #ffffff;
line-height: 80rpx;
}
}
}
.tip {
background: #ffffff;
padding: 40rpx;
padding-top: 0;
.titl {
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #666666;
line-height: 40rpx;
margin-bottom: 6rpx;
}
> view {
> text {
font-size: 22rpx;
font-family: PingFangSC-Regular, PingFang SC;
color: #999999;
line-height: 32rpx;
}
&:nth-child(2) {
> text:nth-child(2) {
color: #333333;
}
}
&:nth-child(5) {
> text:nth-child(2) {
color: #ff6a5f;
font-weight: 600;
border-bottom: 2rpx solid #ff6a5f;
}
}
}
}
}
</style>

362
pages/order/detail.vue Normal file
View File

@@ -0,0 +1,362 @@
<template>
<view class="order-detail-container">
<!-- <statusBar /> -->
<view class="top-area">
<view class="order-state">
<view class="state-left">
{{ detailData.status < 2 ? "待支付" : detailData.status < 5 ? "进行中" : detailData.status == 5 ? "已完成" : "" }}
<text class="pay-type">{{ getPayName(detailData.orderPlatform) }}</text>
</view>
<!-- view>
<button class="pay-btn" @click="goPay(detailData)">去支付</button>
</view> -->
</view>
<view class="number-area">
<view class="number-area-item">
<view>
订单编号
</view>
<view class="number-value">
{{ detailData.orderNo }}
<image class="copy-img" src="/static/icon/icon-copy.png" @click="copy(detailData.orderNo)"></image>
</view>
</view>
<view class="number-area-item">
<view>
充电桩编号
</view>
<view class="number-value">
{{ detailData.gunNo }}
<image class="copy-img" src="/static/icon/icon-copy.png" @click="copy(detailData.gunNo)"></image>
</view>
</view>
</view>
</view>
<view class="info-item">
<view class="info-item-title">
充电信息
</view>
<view class="flex-space-between">
<view class="text-one">
{{ detailData.startTime?.substring(5, 10)?.replace("-", "月") }}
</view>
<view class="text-one">
{{ detailData.endTime?.substring(5, 10)?.replace("-", "月") }}
</view>
</view>
<view class="flex-space-between mb16 item-flex-end">
<view class="text-one">
{{ detailData.startTime?.substring(11, 19) }}
</view>
<view class="time-area">
<view class="use-time">
{{ detailData.useTime }}分钟
</view>
<view class="arrow-line"></view>
</view>
<view class="text-one">
{{ detailData.endTime?.substring(11, 19) }}
</view>
</view>
<view class="flex-space-between">
<view class="text-two">
开始充电
</view>
<view class="text-two">
结束充电
</view>
</view>
<view class="line"></view>
<view class="flex-space-between item-center">
<view class="text-one">
合计充电量
</view>
<view>
<text class="text-three">{{ detailData.useDegree }}</text>
<text class="text-one"> </text>
</view>
</view>
</view>
<view class="info-item">
<view class="info-item-title">
费用信息
</view>
<view class="flex-space-between">
<view class="text-one">
订单总额
</view>
<view class="text-one">
{{ detailData.actuallyAmount }}
</view>
</view>
<view class="money-detail">
<view class="money-detail-box">
<view>
电费
<text class="text-one mx16">{{ detailData.electricityAmount }}</text>
</view>
<view>
服务费
<text class="text-one mx16">{{ detailData.serviceAmount }}</text>
</view>
</view>
</view>
<view class="flex-space-between mb16">
<view class="text-two">
支付金额
</view>
<view class="text-one">
{{ detailData.actuallyAmount }}
</view>
</view>
<view class="flex-space-between">
<view class="text-two">
{{ detailData.payTime }}
</view>
<view class="text-two">
{{ getPayName(detailData.orderPlatform) }}
</view>
</view>
<view class="line"></view>
<view class="flex-space-between item-center">
<view class="text-one">
实付金额
</view>
<view>
<text class="text-three">{{ detailData.actuallyAmount }}</text>
<text class="text-one"> </text>
</view>
</view>
</view>
<view class="info-item">
<view class="info-item-title">
终端信息
</view>
<!-- <view class="flex-space-between mb16">
<view class="text-two">
辅助电源
</view>
<view class="text-two text-bold">
12/24v
</view>
</view> -->
<view class="flex-space-between mb16">
<view class="text-two">
充电站
</view>
<view class="text-two text-bold">
{{ detailData.stationName }}
</view>
</view>
<view class="flex-space-between">
<view class="text-two">
终端名称
</view>
<view class="text-two text-bold">
{{ detailData.deviceNo }}
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { copy } from '@/utils/fun.js';
import { ordersInfo } from '@/api/api.js';
const detailData = ref();
onLoad((options) => {
getDetail(options.transactionNo);
});
const getDetail = async (transactionNo) => {
console.log("------transactionNo-----", transactionNo)
let _res = await ordersInfo({ transactionNo });
detailData.value = _res;
};
const getPayName = v => {
if(v == 1){
return "微信支付"
}else if(v == 2){
return "支付宝支付"
}else{
return ""
}
}
const goPay = () => {
console.log("去支付")
}
</script>
<style scoped lang="scss">
.order-detail-container {
.top-area {
background: linear-gradient( 180deg, #FFFFFF 0%, #F7F7F7 100%);
padding: 24rpx 30rpx 36rpx;
.order-state {
display: flex;
justify-content: space-between;
align-items: center;
.state-left {
font-weight: bold;
font-size: 44rpx;
color: #232323;
.pay-type {
width: 120rpx;
height: 38rpx;
background: rgba(111,162,86, 0.1);
border-radius: 8rpx;
font-weight: bold;
font-size: 24rpx;
color: #6FA256;
padding: 6rpx 12rpx;
margin-left: 8rpx;
}
}
.pay-btn {
width: 156rpx;
height: 50rpx;
line-height: 50rpx;
background: #6FA256;
border-radius: 26rpx;
font-weight: bold;
font-size: 30rpx;
color: #FFFFFF;
}
}
.number-area {
display: flex;
justify-content: space-between;
margin-top: 36rpx;
&-item {
width: 50%;
font-family: DIN, DIN;
font-weight: 400;
font-size: 24rpx;
color: #232323;
.number-value {
margin-top: 16rpx;
.copy-img {
width: 24rpx;
height: 24rpx;
margin-left: 6rpx;
}
}
}
}
}
.info-item {
background: #FFFFFF;
border-radius: 16rpx;
padding: 24rpx;
margin: 0 30rpx 36rpx;
.info-item-title {
font-weight: bold;
font-size: 32rpx;
color: #232323;
margin-bottom: 28rpx;
}
.time-area {
flex: 1;
margin: 0 18rpx;
.use-time {
font-weight: bold;
font-size: 28rpx;
color: #3BCF73;
text-align: center;
margin-bottom: 8rpx;
}
.arrow-line {
border-top: 2rpx dashed #999999;
padding-top: 6rpx;
position: relative;
}
.arrow-line::after {
content: '';
position: absolute;
width: 14rpx;
height: 14rpx;
right: 4rpx;
top: 0;
transform: translateY(-60%) rotate(-50deg);
border-right: 2rpx dashed #999999;
}
}
.money-detail {
padding: 24rpx 24rpx 0;
margin-bottom: 24rpx;
&-box {
background: rgba(111, 162, 86, 0.1);
font-weight: bold;
font-size: 24rpx;
color: #6FA256;
padding: 14rpx 30rpx;
border-radius: 16rpx;
display: flex;
justify-content: space-between;
position: relative;
}
&-box::after {
content: '';
position: absolute;
top: -10rpx;
right: 20rpx;
transform: translateY(-75%);
border-top: 20rpx solid transparent;
border-bottom: 20rpx solid rgba(111, 162, 86, 0.1);
border-left: 18rpx solid transparent;
border-right: 18rpx solid transparent;
}
}
}
.flex-space-between {
display: flex;
justify-content: space-between;
}
.item-flex-end {
align-items: flex-end;
}
.item-center {
align-items: center;
}
.mb16 {
margin-bottom: 16rpx;
}
.mx16 {
margin-left: 16rpx;
margin-right: 16rpx;
}
.text-one {
font-weight: bold;
font-size: 28rpx;
color: #232323;
}
.text-two {
font-weight: 400;
font-size: 24rpx;
color: #666666;
}
.text-three {
font-family: DIN, DIN;
font-weight: bold;
font-size: 44rpx;
color: #232323;
}
.text-bold {
font-weight: bold;
}
.line {
height: 0rpx;
border-bottom: 2rpx solid #EEEEEE;
margin: 24rpx 0 26rpx;
}
}
</style>

200
pages/order/order.vue Normal file
View File

@@ -0,0 +1,200 @@
<template>
<view class="order">
<z-paging ref="paging" v-model="dataList" use-page-scroll @query="queryList">
<view>
<statusBar />
<view class="p30">
<view class="order_header">
<view
class="order_header_view"
@click="chanStatus(item.type)"
v-for="(item, index) in status_list"
:key="index"
:class="status == item.type ? 'order_header_active' : ''"
>
{{ item.name }}
<view class="order_header_xian" v-if="item.type == status"></view>
</view>
</view>
</view>
</view>
<view class="p30">
<view class="order_list" v-for="(item, index) in dataList" :key="index" @click="toLink(item)">
<view class="order_list_header">订单编号{{ item.orderNo }}</view>
<view class="order_list_view">
<view>充电时间</view>
<view>{{ item.startTime }}</view>
</view>
<view class="order_list_view">
<view>结束时间</view>
<view>{{ item.endTime }}</view>
</view>
<view class="order_list_view">
<view>充电电量</view>
<view>{{ item.useDegree }}</view>
</view>
<view class="order_list_view">
<view>服务费</view>
<view>{{ item.serviceAmount }}</view>
</view>
<view class="order_list_view">
<view>电费</view>
<view>{{ item.electricityAmount }}</view>
</view>
<view class="order_list_view">
<view>预付金额</view>
<view>{{ item.preAmount }}</view>
</view>
<view class="order_list_total">实付金额{{ item.actuallyAmount }}</view>
</view>
</view>
</z-paging>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onPullDownRefresh, onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app';
import { ordersList } from '@/api/api.js';
const paging = ref(null);
let dataList = ref([]);
let list = ref([]);
let status = ref(1);
let status_list = ref([
{
name: '全部',
type: ''
},
{
name: '进行中',
type: 1
},
{
name: '已完成',
type: 2
},
{
name: '待支付',
type: 3
}
]);
let chanStatus = (e) => {
status.value = e;
paging.value.reload();
};
onLoad(async () => {
});
let toLink = (e) => {
// 1-订单初始化;2-启动充电中;3-正在充电;4-充电结束中;5:交易记录确认;-1-启动失败;-2-启动超时
if (e.status == 2 || e.status == 3 || e.status == 4) {
uni.navigateTo({
url: `/pageOrder/recharge/recharge?transactionNo=${e.transactionNo}&type=order`
});
}
};
let isPagingRefNotFound = () => {
return !paging.value;
};
onPullDownRefresh(() => {
if (isPagingRefNotFound()) return;
paging.value.reload().catch(() => {});
});
onPageScroll((e) => {
if (isPagingRefNotFound()) return;
paging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && paging.value.doChatRecordLoadMore();
});
onReachBottom(() => {
if (isPagingRefNotFound()) return;
paging.value.pageReachBottom();
});
const upChange = (e) => {
console.log(dataFrom);
paging.value.reload();
};
const queryList = (pageNo, pageSize) => {
const params = {
current: pageNo,
pageSize: pageSize,
type: status.value
};
ordersList(params)
.then((res) => {
paging.value.complete(res);
})
.catch((res) => {
paging.value.complete(false);
});
};
</script>
<style lang="scss" scoped>
.order {
&_header {
@include flex($space: space-between);
font-weight: bold;
font-size: 36rpx;
color: #232323;
border-bottom: 4rpx solid #e9ecf2;
&_view {
padding: 15rpx 0;
position: relative;
view {
position: absolute;
left: calc(50% - 49rpx);
bottom: -4rpx;
width: 98rpx;
height: 8rpx;
background: #4879e6;
border-radius: 8rpx 8rpx 8rpx 8rpx;
}
}
&_active {
color: #4879e6;
}
}
&_list {
padding: 25rpx;
background: #ffffff;
border-radius: 8rpx 8rpx 8rpx 8rpx;
margin-top: 30rpx;
&_header {
font-weight: bold;
font-size: 26rpx;
color: #4879e6;
padding-bottom: 20rpx;
border-bottom: 2rpx solid #ebebeb;
margin-bottom: 20rpx;
}
&_view {
@include flex($space: space-between);
font-weight: 400;
font-size: 26rpx;
color: #232323;
margin-bottom: 20rpx;
}
&_total {
flex: 1;
text-align: right;
font-weight: bold;
font-size: 40rpx;
color: #4879e6;
}
}
}
</style>

77
pages/protocol/buy.vue Normal file
View File

@@ -0,0 +1,77 @@
<template>
<view class="xkl-com-bg">
<view style="height: 20rpx"></view>
<view style="font-size: 34rpx; font-weight: 700; text-align: center">充电桩购销合同</view>
<view style="height: 20rpx"></view>
<view style="line-height: 46rpx">
<view>买方用户名{{ shopinfo.username }} 手机号{{ shopinfo.mobile }}</view>
<view>卖方电小芮(河南)新能源科技有限公司</view>
<view>合同签订地点 河南郑州</view>
<view style="text-indent: 2em">
根据中华人民共和国民法典及相关法律法规甲乙双方本着平等自愿公平互惠互利和诚实守信的原则为满足甲方的需求就充电桩买卖事宜协商一致订立本合同以资共同遵守
</view>
<view style="text-indent: 2em">购买标的方式</view>
<view style="text-indent: 2em">
本协议项下的买卖标的物为乙方公司销售的充电桩甲方自行在乙方开发或告知的网站上进行独立购买自行选择型号和数量并全款支付合同订立购买充电桩数的总价
</view>
<view style="text-indent: 2em">品名型号数量金额总价</view>
<view style="text-indent: 2em">交货方式</view>
<view style="text-indent: 2em">甲方购买的充电桩经第三方公司安装结束后由甲方在后台系统上电子签署收到货物确认单甲方签署后视为乙方交付本合同项下的充电桩</view>
<view style="text-indent: 2em">付款方式由甲方在购买时一次性支付</view>
<view style="text-indent: 2em">双方权利及义务</view>
<view style="text-indent: 2em">1甲方的权利及义务</view>
<view style="text-indent: 2em">甲方应在选定型号后及时支付款项</view>
<view style="text-indent: 2em">2乙方的权利及义务</view>
<view style="text-indent: 2em">乙方应保证所售充电桩的质量及技术标准符合国家的最低标准要求</view>
<view style="text-indent: 2em">产品质保</view>
<view style="text-indent: 2em">
质保期五年在质保期内乙方应积极履行质保义务出现质量问题乙方应免费及时更换维修合格产品及配件乙方未尽到质保义务时须承担所有维修费用质保期自甲方所购充电桩安装结束并由甲方签署到货确认函后第二日起算
</view>
<view style="text-indent: 2em">违约责任</view>
<view style="text-indent: 2em">1甲方在购买充电桩后不能因任何除产品质量有缺陷外的原因要求解除本合同及退款</view>
<view style="text-indent: 2em">2乙方充电桩存在质量问题由乙方协调各方进行免费更换维修</view>
<view style="text-indent: 2em">解决合同纠纷方式</view>
<view style="text-indent: 2em">本合同在履行过程中发生争议由双方当事人协商解决协商或调解不成的可依法在乙方所在地人民法院起诉</view>
<view style="text-indent: 2em">其他</view>
<view style="text-indent: 2em">本合同一式两份甲乙双方各执一份自双方签字盖章之日起生效</view>
</view>
<view v-if="!hide">
<view style="height: 50rpx"></view>
<u-button type="primary" @click="submit(1)">我已阅读并同意充电桩购销合同</u-button>
<view style="height: 50rpx"></view>
<u-button @click="submit(0)">取消</u-button>
</view>
<view style="height: 100rpx"></view>
</view>
</template>
<script>
let self;
export default {
data() {
return {
shopinfo: {
username: '',
mobile: ''
},
hide: ''
};
},
onLoad(options) {
this.shopinfo = uni.getStorageSync('user');
},
methods: {
submit(e) {
if (e) {
uni.$emit('buy', 1);
uni.navigateBack();
} else {
uni.navigateBack();
}
}
}
};
</script>
<style lang="scss"></style>

View File

@@ -0,0 +1,130 @@
<template>
<view class="xkl-com-bg">
<view style="height: 20rpx"></view>
<view style="font-size: 34rpx; font-weight: 700; text-align: center">充电桩托管协议</view>
<view style="height: 20rpx"></view>
<view style="line-height: 46rpx">
<view>甲方(运营方)电小芮(河南)新能源科技有限公司</view>
<view>乙方(投资方)用户名{{ shopinfo.username }} 手机号{{ shopinfo.mobile }}</view>
<view>合同签订地点 河南郑州</view>
<view style="text-indent: 2em">
鉴于乙方购买了电小芮(河南)新能源科技有限公司 个充电桩端口乙方因工作及地域 等原因无法亲自管理自己的充电桩现为节省乙方精力提高充电桩的运营效率
甲乙双方本着平等自愿互利的原则根据中华人民共和国民法典及相关 法律法规的规定就乙方购买的新能源汽车充电桩运营相关事宜协商一致签订 本协议
</view>
<view style="text-indent: 2em">项目概况</view>
<view style="text-indent: 2em">1项目名称</view>
<view style="text-indent: 2em">2项目地址电小芮(河南)新能源科技有限公司后台系统自动显示  </view>
<view style="text-indent: 2em">3合作期限 5 自站点正式竣工投运日开始计算</view>
<view style="text-indent: 2em">4项目规模计划投建___个充电专用车位在60天之内完成</view>
<view style="text-indent: 2em">合作内容</view>
<view style="text-indent: 2em">1甲方承担充电桩的选址场地协调规划设计项目备案终端服务 客户引流等</view>
<view style="text-indent: 2em">合作方式</view>
<view style="text-indent: 2em">
1 甲方负责安装及运营充电桩交由甲方主导运营甲方通过运营平台向 充电用户收取充电费用电费+充电服务费等甲方提供运营平台系统给乙方查
阅及对账甲方将所有站点时时赚取利润按双方约定分红比例每月定期支付给乙
</view>
<view style="text-indent: 2em">2利润核算方式利润 = 当月平台收益 - 当月缴纳电费 - 公共开支 平台活动保险消防设施税票等</view>
<view style="text-indent: 2em">
3电费缴纳方式电价选用下列第 种方式申报缴纳1甲方独立申报/ 改造新能源专用电与国家电网申请独立电表执行新能源专用电乙方将变压
器户头过户至甲方由甲方单独与国家电网结算2乙方配合协调甲方在充电 桩上端加装独立计量电表以甲方每月进行对独立计量电表缴费
</view>
<view style="text-indent: 2em">4甲方享有该项目利润的 50 %乙方享有该项目利润的 50 %</view>
<view style="text-indent: 2em">
充电桩运营充电费用是指甲方向新能源汽车充电客户统一收取的充电费用 充电电费 充电服务费 两部分组成,运营决策权归甲方所有乙方不 参与运营
</view>
<view style="text-indent: 2em">支付方式</view>
<view style="text-indent: 2em">1 充电服务费甲乙双方分红结算每周由乙方在甲方系统上自动提取收 </view>
<view style="text-indent: 2em">2 乙方按确认的分成收益金额向甲方开具财务凭证甲方在收到乙方的财 务凭证后 日内向乙方支付上述费用</view>
<view style="text-indent: 2em">乙方账户信息 开户名称 </view>
<view style="text-indent: 2em">甲乙双方的权利和义务</view>
<view style="text-indent: 2em">1 建设运营期内甲方在该项目场地内的消防和用电安全应当符合国家 法律法规要求并采取必要的保障措施确保项目的安全运营</view>
<view style="text-indent: 2em">
2 甲方应在协议期内协调好本协议充电场站所在土地房屋电力基础设 施的所有权或使用权无纠纷并确保场地租赁期限符合本协议要求充分满足项
目建设运营的需要若甲方故意隐瞒或无法保证协议期内充电设施的正常运营 造成的损失由甲方承担不可抗力因素除外因甲方与产权方之间不能继续场
地租赁协议导致本协议未能正常履行完毕的甲方应协调产权人将此协议继续履
</view>
<view style="text-indent: 2em">3甲方有义务对充电桩的日常充电站的卫生清洁不允许非充电车辆占用 新能源车位提供较好的充电场站运营环境</view>
<!-- <view style="text-indent: 2em">
4乙方若对预期收益不满可在充电桩安装落地收益产生后两年内向甲方提补贴申请总收益已超过投资收益2倍不可申请甲方受理后会在安装收益产生满两年时通过股票定增融资同意以乙方购买价两倍减去全部收益来回购充电桩的所有权与收益权归甲方所有
</view>
<view style="text-indent: 2em">5乙方有权调自己的充电桩经营数据</view> -->
<view style="text-indent: 2em">
4乙方在充电站开始建设后或运营中提出位置更改并经甲方同意的因更 改产生的相关费用由乙方承担在协议期限内若因不可抗力场地整体重新规
划导致该充电桩场地改造影响到该项目正常运营甲方不承担相关运营损失 但有关充电站改造费用由甲方承担因法律法规变动政府规划城市更新需要
而须调整或终止该项目的情况甲方须需提前一个月书面知会并协调相关单位保 障乙方的利益
</view>
<view style="text-indent: 2em">违约责任</view>
<view style="text-indent: 2em">
1合作期限内双方应按照协议约定各自履行相应的义务因任何一方原 因无法保证该项目正常运营且在守约方书面催告后仍未处理/仍不纠正的 7
日时守约方有权单方面解除协议
</view>
<view style="text-indent: 2em">
2本协议生效后各方均应全面履行本协议约定的义务任何一方不履行 或不完全履行本协议约定义务的应当承担相应的违约责任并赔偿由此给守约 方造成的损失
</view>
<view style="text-indent: 2em">其他</view>
<view style="text-indent: 2em">
保密条款1甲乙双方应对在本协议洽谈和项目合作过程中获取的对方的 保密信息及对方关联方的保密信息包括但不限于商业秘密财务资料经营方
技术资料等以及双方合作内容相关的一切信息应予保密并采取必要的保密 措施2甲乙双方应严格保密双方的合作内容以及协议模式等信息不得向任
何第三方透露3未经一方事先书面同意另一方不得将任何该等信息披露给 任何第三方或者自行复制保存等4甲乙双方应严格遵循上述保密条款
违约方违反上述约定给守约方造成损失的违约方应就守约方由此遭受的损失承 担损失赔偿责任
</view>
<view style="text-indent: 2em">
风险约定本协议项下的充电桩营运场所所有权为甲方场所内发生的第三 方人员及车辆的所有者责任交通事故等意外损害等均按法律规定处理
</view>
<view style="text-indent: 2em">
不可抗力本协议履行过程中 如一方因发生无法预见又无法避免的事件 而不能全部或部分履行协议可以根据不可抗力的影响减免相应责任但须在不 可抗力因素发生后 48
小时内通知对方并采取措施避免损失的扩大
</view>
<view style="text-indent: 2em">
订立本协议所依据的法律法规或所依据的客观情况发生重大变化致使本 协议无法履行的经甲乙双方协商一致可以变更本协议有关内容但均应以 书面方式盖章确认
</view>
<view style="text-indent: 2em">适用法律及争议解决</view>
<view style="text-indent: 2em">
在履行本协议过程中若发生争议双方应本着友好互让的原则协商解决
未能协商一致可向甲方所在地人民法院提起诉讼解决当任何争议发生时或该争议处于协商或提交诉讼解决时除争议事项外双方应继续享有本协议规定的其它权利履行本协议规定的其它义务
</view>
<view style="text-indent: 2em">本协议一式四份甲乙双方各执贰份 自双方盖章后生效</view>
<view style="text-indent: 2em">
本协议附件为本协议有效组成部分与本协议具有同等法律效力本协议未 尽事宜由甲乙双方友好协商后以书面形式加以补充补充协议具有同等的法 律效力
</view>
</view>
<view v-if="!hide">
<view style="height: 50rpx"></view>
<u-button type="primary" @click="submit(1)">我已阅读并同意充电桩托管协议</u-button>
<view style="height: 50rpx"></view>
<u-button @click="submit(0)">取消</u-button>
</view>
<view style="height: 100rpx"></view>
</view>
</template>
<script>
let self;
export default {
data() {
return {
shopinfo: {
username: '',
mobile: ''
},
hide: ''
};
},
onLoad(options) {
this.shopinfo = uni.getStorageSync('user');
},
methods: {
submit(e) {
if (e) {
uni.$emit('trusteeship', 1);
uni.navigateBack();
} else {
uni.navigateBack();
}
}
}
};
</script>
<style lang="scss"></style>

130
pages/sweep/sweep.vue Normal file
View File

@@ -0,0 +1,130 @@
<template>
<view class="sweep">
<statusBar />
<view class="sweep_note">
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/djk.png" mode="widthFix"></image>
</view>
<view>插上</view>
<view>充电枪</view>
</view>
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/djs.png" mode="widthFix"></image>
</view>
<view>点击</view>
<view>扫码充电</view>
</view>
<view class="sweep_note_view">
<view class="sweep_note_view_img">
<image src="/static/image/cs.png" mode="widthFix"></image>
</view>
<view>点击</view>
<view>开始充电</view>
</view>
</view>
<view class="sweep_scan" style="margin-top: 300rpx">
<up-input placeholder="请输入充电枪编号" type="number" border="surround" v-model="value"></up-input>
<view style="width: 100rpx">
<up-button type="primary" text="确定" @click="toCd"></up-button>
</view>
</view>
<view class="sweep_scan" style="margin-top: 150rpx">
<up-button @click="scan" type="primary" shape="circle" text="扫码充电"></up-button>
</view>
<cc-myTabbar :tabBarShow="2"></cc-myTabbar>
<!-- <tabbar path="/pages/sweep/sweep" /> -->
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { useNav } from '@/hooks/useNav.js';
import { urlQuery } from '@/utils/fun.js';
const { nav, navTo } = useNav();
let value = ref('');
onLoad(() => {
});
const scan = async () => {
uni.scanCode({
success: function (res) {
let query = urlQuery(res.result);
if (!query.num) {
uni.showToast({
title: '请扫描正确的设备码',
icon: 'none'
});
} else {
navTo(`/pages/home/star?id=${query.num}`);
}
// navTo(`/pages/home/star?id=${res.result}`);
}
});
};
const toCd = async () => {
if (!value.value) {
uni.showToast({
title: '请输入枪号',
icon: 'none'
});
return;
}
navTo(`/pages/home/star?id=${value.value}`);
};
</script>
<style scoped lang="scss">
.sweep {
&_note {
padding: 0 60rpx;
@include flex($space: space-between);
&_view {
@include flex($direction: column, $space: center);
font-weight: 800;
font-size: 32rpx;
color: #4879e6;
&_img {
display: flex;
align-items: flex-end;
height: 115rpx;
margin-bottom: 30rpx;
}
}
&_view:nth-child(1) {
image {
width: 151rpx;
height: 99rpx;
}
}
&_view:nth-child(2) {
image {
width: 120rpx;
height: 99rpx;
}
}
&_view:nth-child(3) {
image {
width: 106rpx;
height: 113rpx;
}
}
}
&_scan {
@include flex;
padding: 0 120rpx;
}
}
</style>

136
request/index.js Normal file
View File

@@ -0,0 +1,136 @@
import config from '@/config'
import {
toast
} from '@/uni_modules/uview-plus'
export const http = (url, params, method) => {
return new Promise((resolve, reject) => {
let Authorization = uni.getStorageSync('token') || ''
let version = uni.getStorageSync('version') || uni.getSystemInfoSync()
let isInvest = uni.getStorageSync('isInvest') || config.isInvest;
if (!uni.getStorageSync('version')) uni.setStorageSync('version', version);
let {
deviceId,
deviceBrand,
deviceModel,
osVersion,
} = version
let header = {
deviceId,
deviceBrand,
deviceModel,
osVersion,
platform: 1,
Authorization
}
uni.request({
url: config.baseUrl + url,
data: params || {},
params: {},
method: method || 'POST',
header: header,
success: (res) => {
// uni.hideLoading()
if (res.statusCode == 401) {
uni.removeStorageSync('token');
uni.removeStorageSync('user');
uni.hideLoading()
uni.showModal({
title: '提示',
content: '为提供更好的服务,请前往登录',
success: (res) => {
if (res.confirm) {
if(isInvest){
uni.navigateTo({
url: '/pageInvest/login/login'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
return
}
const data = res.data
if (data.code == 10 && !data.success) {
reject(data)
return
}
if (data.code !== 1 && !data.success) {
toast(data.msg)
reject(data)
return
}
resolve(data.data || null)
},
fail: (err) => {
if (err.statusCode == 401) {
uni.removeStorageSync('token');
uni.removeStorageSync('user');
uni.hideLoading()
uni.showModal({
title: '提示',
content: '为提供更好的服务,请前往登录',
success: (res) => {
if (res.confirm) {
if(isInvest){
uni.navigateTo({
url: '/pageInvest/login/login'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
return
}
const data = err.data
if (data.code !== 1 && !data.success) {
toast(data.msg)
reject(data)
return
}
uni.hideLoading()
reject(err)
}
})
});
};
// import {requestInterceptors,responseInterceptors} from './interceptors.js'
// // 引入luch-request
// import { http } from '@/uni_modules/uview-plus'
// // 初始化请求配置
// const initRequest=(vm)=>{
// http.setConfig((defaultConfig) => {
// /* defaultConfig 为默认全局配置 */
// defaultConfig.baseURL = config.baseUrl /* 根域名 */
// return defaultConfig
// })
// requestInterceptors()
// responseInterceptors()
// }
// export {
// initRequest
// }

BIN
static/address.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
static/all.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
static/gps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
static/icon/9you.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

BIN
static/icon/b1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
static/icon/b2.png Normal file

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