提交
16
.hbuilderx/launch.json
Normal file
@ -0,0 +1,16 @@
|
||||
{ // 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": [{
|
||||
"default" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"mp-weixin" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"type" : "uniCloud"
|
||||
}
|
||||
]
|
||||
}
|
5
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
23
App.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
page,
|
||||
uni-page-body,
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
72
api/login.js
Normal file
@ -0,0 +1,72 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 登录方法
|
||||
export function login(username, password, code, uuid) {
|
||||
const data = {
|
||||
username,
|
||||
password,
|
||||
code,
|
||||
uuid
|
||||
}
|
||||
return request({
|
||||
'url': '/rescue/login',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
'method': 'post',
|
||||
'data': data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
return request({
|
||||
'url': '/rescue/getInfo',
|
||||
'method': 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 退出方法
|
||||
export function logout() {
|
||||
return request({
|
||||
'url': '/rescue/logout',
|
||||
'method': 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
export function getCodeImg() {
|
||||
return request({
|
||||
'url': '/rescue/captchaImage',
|
||||
headers: {
|
||||
isToken: false,
|
||||
},
|
||||
method: 'get',
|
||||
timeout: 20000
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 获取验证码
|
||||
export function loginApp(data) {
|
||||
return request({
|
||||
'url': '/rescue/loginApp',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
method: 'post',
|
||||
timeout: 20000,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 使用租户域名(标识),获得租户编号
|
||||
export function getTenantIdByWebsite(website) {
|
||||
return request({
|
||||
url: '/system/tenant/getListByWebsite',
|
||||
method: 'get',
|
||||
params: {
|
||||
website
|
||||
}
|
||||
})
|
||||
}
|
41
api/system/user.js
Normal file
@ -0,0 +1,41 @@
|
||||
import upload from '@/utils/upload'
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 用户密码重置
|
||||
export function updateUserPwd(oldPassword, newPassword) {
|
||||
const data = {
|
||||
oldPassword,
|
||||
newPassword
|
||||
}
|
||||
return request({
|
||||
url: '/system/user/profile/updatePwd',
|
||||
method: 'put',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
// 查询用户个人信息
|
||||
export function getUserProfile() {
|
||||
return request({
|
||||
url: '/system/user/profile',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 修改用户个人信息
|
||||
export function updateUserProfile(data) {
|
||||
return request({
|
||||
url: '/system/user/profile',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 用户头像上传
|
||||
export function uploadAvatar(data) {
|
||||
return upload({
|
||||
url: '/system/user/profile/avatar',
|
||||
name: data.name,
|
||||
filePath: data.filePath
|
||||
})
|
||||
}
|
112
components/VNavigationBar.vue
Normal file
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<!-- header -->
|
||||
<view :style="{ backgroundColor, paddingTop: homeHeaderPaddingTop + 'px', height: homeHeaderMenuHeight + 'px' }"
|
||||
class="navigationBar" :class="{leftTitle: leftTitle}">
|
||||
<template v-if="leftTitle">
|
||||
<view class="navigationBarTitle" :style="{ color: titleColor }">
|
||||
{{ title ? title : '' }}
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="navigationBarBack" @click="back" >
|
||||
<slot name="back">
|
||||
<uni-icons size="24" type="left"
|
||||
:color="titleColor"></uni-icons>
|
||||
</slot>
|
||||
</view>
|
||||
<view class="navigationBarTitle" :style="{ color: titleColor }">
|
||||
{{ title }}
|
||||
</view>
|
||||
</template>
|
||||
<view class="navigationBarBackExtra">
|
||||
<slot name="extra">
|
||||
</slot?>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* 计算标题位置 */
|
||||
import {
|
||||
getWXStatusHeight
|
||||
} from "@/utils/utils";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '#317DFA'
|
||||
},
|
||||
title: String,
|
||||
titleColor: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
leftTitle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// #ifdef MP
|
||||
const {
|
||||
barHeight,
|
||||
barTop,
|
||||
menuButtonLeft
|
||||
} = getWXStatusHeight()
|
||||
console.log('barHeight, barTop, menuButtonLeft: ', barHeight, barTop, menuButtonLeft);
|
||||
this.homeHeaderPaddingTop = barTop || 0
|
||||
this.homeHeaderMenuHeight = barHeight
|
||||
this.homeHeaderMenuLeft = menuButtonLeft - 6
|
||||
// #endif
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// #ifdef MP
|
||||
homeHeaderPaddingTop: 0,
|
||||
homeHeaderMenuHeight: 0,
|
||||
homeHeaderMenuLeft: 0,
|
||||
// #endif
|
||||
// #ifdef APP || H5
|
||||
homeHeaderPaddingTop: 20,
|
||||
homeHeaderMenuHeight: 50,
|
||||
homeHeaderMenuLeft: 0
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navigationBar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.leftTitle {
|
||||
justify-content: start;
|
||||
padding-left: 28rpx;
|
||||
}
|
||||
|
||||
.navigationBarBack {
|
||||
position: absolute;
|
||||
left: 20rpx;
|
||||
}
|
||||
|
||||
.navigationBarBackExtra {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
}
|
||||
|
||||
.navigationBarTitle {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
138
components/mote-lines-divide/mote-lines-divide.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<view>
|
||||
<view style="position: relative" v-if="isHide">
|
||||
<view class="dt-content" :style="'-webkit-line-clamp:'+line">
|
||||
<text class="content">
|
||||
<slot>{{ dt ? dt : '' }}</slot>
|
||||
</text>
|
||||
</view>
|
||||
<view class="button-show" @tap="isHide = false" v-if="enableButton&&lines>line">
|
||||
<text style="color: blue">{{ expandText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view>
|
||||
<text class="content">
|
||||
<slot>{{ dt ? dt : '' }}</slot>
|
||||
</text>
|
||||
</view>
|
||||
<view class="fold-hint" v-if="foldHint">
|
||||
<view @tap="isHide = true">
|
||||
{{ foldHint }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<text class="placeholder">
|
||||
{{ placeholder }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 是否隐藏多余行。初始状态不隐藏
|
||||
isHide: true,
|
||||
// 全量所占文本高度
|
||||
textHeight: 0,
|
||||
// 单行文本所占高度
|
||||
lineHeight: 1,
|
||||
// 占位文本
|
||||
placeholder: '占位'
|
||||
};
|
||||
},
|
||||
props: {
|
||||
// 展示多少行
|
||||
line: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
// 文本
|
||||
dt: {
|
||||
type: [String],
|
||||
default: ''
|
||||
},
|
||||
enableButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 自定义展开提示
|
||||
expandText: {
|
||||
type: String,
|
||||
default: "展开"
|
||||
},
|
||||
// 自定义收起提示
|
||||
foldHint: {
|
||||
type: String,
|
||||
default: "收起"
|
||||
}
|
||||
},
|
||||
|
||||
watch:{
|
||||
dt(){
|
||||
let that = this
|
||||
setTimeout(() => {
|
||||
let query = uni.createSelectorQuery().in(that);
|
||||
// 获取所有文本在html中的高度
|
||||
query.select('.content').boundingClientRect(data => {
|
||||
that.textHeight = data.height
|
||||
}).exec();
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.enableButton) {
|
||||
let query = uni.createSelectorQuery().in(this);
|
||||
// 获取所有文本在html中的高度
|
||||
query.select('.content').boundingClientRect(data => {
|
||||
this.textHeight = data.height
|
||||
}).exec();
|
||||
|
||||
// 通过占位元素获取单行文本的高度
|
||||
query.select('.placeholder').boundingClientRect(data => {
|
||||
this.lineHeight = data.height
|
||||
}).exec();
|
||||
}
|
||||
// 获取单行文本高度后,置空占位元素,使其释放占位
|
||||
this.placeholder = ''
|
||||
},
|
||||
computed: {
|
||||
// 全文本所占总行数
|
||||
lines() {
|
||||
if (!this.enableButton) {
|
||||
return this.line
|
||||
}
|
||||
return Math.floor(this.textHeight > 0 && this.lineHeight > 0 ? this.textHeight / this.lineHeight : 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dt-content {
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.button-show {
|
||||
width: 70rpx;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 0;
|
||||
text-align: right;
|
||||
background-image: linear-gradient(-180deg, rgba(233, 236, 239, 0) 50%, #FFF 80%);
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.fold-hint {
|
||||
color: blue;
|
||||
text-align: right
|
||||
}
|
||||
</style>
|
172
components/reservationOrder/reservationOrder.vue
Normal file
@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="orderInfo">
|
||||
<view class="header">
|
||||
<text class="orderTitle">{{ orderInfo.title }}</text>
|
||||
<text class="orderStatus" :class="['status_' + orderInfo.status]">
|
||||
{{ getOrderStatusTxt() }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="detail">
|
||||
<view class="line">
|
||||
<image class="line-icon" src="../../static/icons/order-icon1.png" mode="aspectFit"></image>
|
||||
<text class="line-text">{{orderInfo.address}}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<image class="line-icon" src="../../static/icons/order-icon2.png" mode="aspectFit"></image>
|
||||
<text class="line-text">{{orderInfo.phone}}</text>
|
||||
</view>
|
||||
<view class="line">
|
||||
<image class="line-icon" src="../../static/icons/order-icon3.png" mode="aspectFit"></image>
|
||||
<text class="line-text">{{orderInfo.busiTypeStr}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!hideFooter" class="footer">
|
||||
<view class="btn" :class="{phone: isDetail}">
|
||||
<image v-if="isDetail" class="btnIcon" src="../../static/icons/order-icon7.png" mode="aspectFit"></image>
|
||||
<text>拨打电话</text>
|
||||
</view>
|
||||
<view class="btn" :class="{address: isDetail}">
|
||||
<image v-if="isDetail" class="btnIcon" src="../../static/icons/order-icon6.png" mode="aspectFit"></image>
|
||||
<text>地址导航</text>
|
||||
</view>
|
||||
<view v-if="!isDetail" class="btn primary" @click="showOrderDetail">查看订单</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "reservationOrder",
|
||||
props: {
|
||||
orderInfo: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
isDetail: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hideFooter: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getOrderStatusTxt() {
|
||||
switch (this.orderInfo.status) {
|
||||
case '1':
|
||||
return '等待维修'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
},
|
||||
showOrderDetail() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/orderDetail/orderDetail'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.orderInfo {
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
box-shadow: 2rpx 4rpx 8rpx #efefef;
|
||||
padding: 0 30rpx;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #EEEEEE;
|
||||
padding: 30rpx 0;
|
||||
|
||||
.orderTitle {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.orderStatus {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
|
||||
&.status_1 {
|
||||
color: #0174F6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
margin-bottom: 30rpx;
|
||||
border-bottom: 1rpx solid #EEEEEE;;
|
||||
.line {
|
||||
margin: 30rpx 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.line-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
.btn {
|
||||
margin-bottom: 30rpx;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
height: 60rpx;
|
||||
border-radius: 30rpx 30rpx 30rpx 30rpx;
|
||||
border: 1rpx solid #0174F6;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #0174F6;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 8rpx;
|
||||
|
||||
&.primary {
|
||||
background: #0174F6;
|
||||
color: #fff;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
&.address {
|
||||
background: #0174F6;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
&.phone {
|
||||
background: #E8A321;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btnIcon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
172
components/tabBar/tabBar.vue
Normal file
@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="bottoms">
|
||||
<view class="box" :class="{active: aindex == 1}" @click="getgogo(1)" v-if="identity == 'user' ">
|
||||
<view class="imgs">
|
||||
<image mode="aspectFit" src="@/static/icons/tabbar/home.png" v-show="aindex != 1"></image>
|
||||
<image mode="aspectFit" src="@/static/icons/tabbar/home-checked.png" v-show="aindex == 1"></image>
|
||||
</view>
|
||||
<view class="">首页</view>
|
||||
</view>
|
||||
<view class="box" :class="{active: aindex == 2}" @click="getgogo(2)">
|
||||
<view class="imgs">
|
||||
<image mode="aspectFit" src="@/static/icons/tabbar/order.png" v-show="aindex != 2"></image>
|
||||
<image mode="aspectFit" src="@/static/icons/tabbar/order-checked.png" v-show="aindex == 2"></image>
|
||||
</view>
|
||||
<view class="">订单</view>
|
||||
</view>
|
||||
<view class="box" :class="{active: aindex == 3}" @click="getgogo(3)">
|
||||
<view class="imgs">
|
||||
<image mode="aspectFit" src="@/static/icons/tabbar/my.png" v-show="aindex != 3"></image>
|
||||
<image mode="aspectFit" src="@/static/icons/tabbar/my-checked.png" v-show="aindex == 3"></image>
|
||||
</view>
|
||||
<view class="">我的</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '../../utils/request';
|
||||
import {
|
||||
getToken
|
||||
} from '@/utils/auth'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
aindex: 1,
|
||||
msgNum: null,
|
||||
identity: 'user',
|
||||
nowPageInterval: null,
|
||||
arr: [{
|
||||
text: '首页'
|
||||
},
|
||||
{
|
||||
text: '消息'
|
||||
},
|
||||
{
|
||||
text: '运力'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
props: {
|
||||
msg: String|Number
|
||||
},
|
||||
onLoad() {
|
||||
console.log('tabbag', uni.getStorageSync('identity'));
|
||||
|
||||
},
|
||||
onUnload() {
|
||||
if (this.nowPageInterval) {
|
||||
clearTimeout(this.nowPageInterval);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// #ifdef APP || H5
|
||||
this.identity = uni.getStorageSync('identity');
|
||||
// #endif
|
||||
this.aindex = this.msg
|
||||
this.getbottom()
|
||||
},
|
||||
methods: {
|
||||
async getbottom() {
|
||||
if (!getToken()) {
|
||||
return
|
||||
}
|
||||
let res = await request({
|
||||
url: '/announcement/announcement/getOwnNoRead',
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
console.log('jitiao', res);
|
||||
if (res.code == 200) {
|
||||
this.msgNum = res.data
|
||||
}
|
||||
},
|
||||
getgogo(index) {
|
||||
|
||||
|
||||
if (index == 1) {
|
||||
this.aindex = index
|
||||
uni.reLaunch({
|
||||
url: '/pages/home/home'
|
||||
})
|
||||
}
|
||||
if (index == 2) {
|
||||
this.aindex = index
|
||||
uni.reLaunch({
|
||||
url: '/pages/orderList/orderList'
|
||||
})
|
||||
}
|
||||
if (index == 3) {
|
||||
this.aindex = index
|
||||
uni.reLaunch({
|
||||
url: '/pages/my/my'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bottoms {
|
||||
width: 100%;
|
||||
// position: fixed;
|
||||
// bottom: 0px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
padding: 12rpx 40rpx;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 4rpx 2rpx 12rpx 0 #c3c3c3;
|
||||
position: relative;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.box {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
color: #929292;
|
||||
|
||||
&.active {
|
||||
color: #327DFB;
|
||||
}
|
||||
}
|
||||
|
||||
.imgs {
|
||||
margin: 0 auto;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.hongdian {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: crimson;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -8px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 2px;
|
||||
}
|
||||
</style>
|
30
config.js
Normal file
@ -0,0 +1,30 @@
|
||||
// 应用全局配置
|
||||
module.exports = {
|
||||
//baseUrl: 'https://www.nuoyunr.com/admin-api',
|
||||
baseUrl: 'http://192.168.1.4:48080/admin-api',
|
||||
imagesUrl: 'http://shequ.0315e.com/static/images/pages/',
|
||||
baseImageUrl: 'https://www.nuoyunr.com/minio',
|
||||
//wsUrl: 'wss://www.nuoyunr.com/admin-api',
|
||||
wsUrl: 'ws://192.168.1.4:48080/admin-api',
|
||||
// 应用信息
|
||||
appInfo: {
|
||||
// 应用名称
|
||||
name: "道路救援",
|
||||
// 应用版本
|
||||
version: "2.6",
|
||||
// 应用logo
|
||||
logo: "/static/logo.png'",
|
||||
// 官方网站
|
||||
site_url: "http://ruoyi.vip",
|
||||
// 政策协议
|
||||
agreements: [{
|
||||
title: "隐私政策",
|
||||
url: "https://ruoyi.vip/protocol.html"
|
||||
},
|
||||
{
|
||||
title: "用户服务协议",
|
||||
url: "https://ruoyi.vip/protocol.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
20
index.html
Normal 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>
|
22
main.js
Normal file
@ -0,0 +1,22 @@
|
||||
import App from './App'
|
||||
|
||||
// #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)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
73
manifest.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"name" : "qixiu",
|
||||
"appid" : "__UNI__FA456F7",
|
||||
"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" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false,
|
||||
"es6" : true
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "2"
|
||||
}
|
9
package.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"uview-ui": "^2.0.36"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.69.5",
|
||||
"sass-loader": "^10.4.1"
|
||||
}
|
||||
}
|
151
pages.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "uni-app"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/home/home",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/orderList/orderList",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/my",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/myReservation/myReservation",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/myCar/myCar",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/shopDetail/shopDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/orderDetail/orderDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/myInfo",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/myCar/carDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/myEquity",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/register",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/myReservation/addReservation",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/message",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/evaluate",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/my/cardRoll",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/myReservation/reservationSuccess",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/orderDetail/evaluate",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/guideList/guideList",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/guideList/guideDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"navigationStyle": "custom"
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
}
|
47
pages/guideList/guideDetail.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar background-color="rgba(0,0,0,0)" title-color="rgba(0,0,0,0)"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="title">如何在小程序上下单车辆维修</view>
|
||||
<view class="content"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f1f1f1;
|
||||
.body {
|
||||
background-color: #fff;
|
||||
flex: 1;
|
||||
height: 0;
|
||||
margin: 32rpx;
|
||||
padding: 30rpx;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 20rpx;
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
75
pages/guideList/guideList.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<v-navigation-bar title="操作指南" background-color="#fff" title-color="#333"></v-navigation-bar>
|
||||
<view class="body">
|
||||
<view @click="gotoDetail(item)" v-for="(item,index) in data" :key="index" class="guideItem">
|
||||
<text class="guide_content">如何在小程序上下单车辆维修</text>
|
||||
<image class="guideIcon" src="../../static/icons/homeInfoMore.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: [{}, {}]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
gotoDetail() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/guideList/guideDetail'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
background-color: #F3F5F7;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding: 0 0 20rpx;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.guideItem {
|
||||
margin: 20rpx 32rpx 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
|
||||
.guide_content {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.guideIcon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
295
pages/home/home.vue
Normal file
@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar leftTitle="true" backgroundColor="transparent" title="车辆检测维修"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="body-top-banner">
|
||||
<image class="banner" src="" mode="aspectFit" />
|
||||
</view>
|
||||
<view class="menus">
|
||||
<view @click="gotoPage(menu)" v-for="(menu, index) in menus" :key="index" class="menu-item">
|
||||
<image class="menu-icon" :src="menu.icon" mode="aspectFit"></image>
|
||||
<text class="menu-title">{{menu.title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info">
|
||||
<image class="info-icon" src="@/static/icons/homeInfo.png" mode="aspectFit"></image>
|
||||
<view class="infoList">
|
||||
<view v-for="(item, index) in infoList" :key="item.id" class="infoItem">
|
||||
<view class="infoIndex"></view>
|
||||
<view class="infoText">{{item.title}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<image class="more-icon" src="../../static/icons/homeInfoMore.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="repairShop">
|
||||
<view class="title">附近修理厂</view>
|
||||
<view class="shopList">
|
||||
<view v-for="(item, index) in shopList" :key="index" class="shopItem" @click="gotoShopDetail(item)">
|
||||
<image class="shopImg" :src="item.image" mode="aspectFill"></image>
|
||||
<view class="shopInfo">
|
||||
<view class="shopTitle">{{item.title}}</view>
|
||||
<view class="shopDetail">
|
||||
<view class="shopAddress">{{item.address}}</view>
|
||||
<view class="line"></view>
|
||||
<view class="shopDistance">{{item.distance}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<tabBarVue msg="1"></tabBarVue>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tabBarVue from '@/components/tabBar/tabBar.vue'
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
tabBarVue,
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menus: [{
|
||||
title: '预约记录',
|
||||
icon: require('@/static/icons/homeMenuIcon/menu1.png'),
|
||||
path: '/pages/myReservation/myReservation'
|
||||
},
|
||||
{
|
||||
title: '我的车辆',
|
||||
icon: require('@/static/icons/homeMenuIcon/menu2.png'),
|
||||
path: '/pages/myCar/myCar'
|
||||
},
|
||||
{
|
||||
title: '客服中心',
|
||||
icon: require('@/static/icons/homeMenuIcon/menu3.png'),
|
||||
path: ''
|
||||
},
|
||||
{
|
||||
title: '操作指南',
|
||||
icon: require('@/static/icons/homeMenuIcon/menu4.png'),
|
||||
path: '/pages/guideList/guideList'
|
||||
},
|
||||
],
|
||||
infoList: [{
|
||||
id: 1,
|
||||
title: '暖心!深夜汽车高速路上爆胎 彝良交警化身“修理工”帮忙换胎'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '车辆机件“焕新上岗”,武汉公交修旧创效出实招'
|
||||
},
|
||||
],
|
||||
shopList: [{
|
||||
id: 1,
|
||||
title: '顺捷汽车维修搭电救援补胎中心',
|
||||
address: '济南市历下区福瑞达历下护理院东南门旁',
|
||||
distance: '1.9km',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '顺捷汽车维修搭电救援补胎中心',
|
||||
address: '济南市历下区福瑞达历下护理院东南门旁',
|
||||
distance: '1.9km',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '顺捷汽车维修搭电救援补胎中心',
|
||||
address: '济南市历下区福瑞达历下护理院东南门旁',
|
||||
distance: '1.9km',
|
||||
image: ''
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
gotoShopDetail() {
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages/shopDetail/shopDetail'
|
||||
})
|
||||
},
|
||||
gotoPage(menu) {
|
||||
uni.navigateTo({
|
||||
url: menu.path
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
background: linear-gradient(180deg, #0174F6 0%, rgba(1, 116, 246, 0) 100%);
|
||||
background-size: 100% 600rpx;
|
||||
background-repeat: no-repeat;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
|
||||
|
||||
.body-top-banner {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.banner {
|
||||
margin: 24rpx 0 0;
|
||||
width: 686rpx;
|
||||
height: 290rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
background-color: #0174F6;
|
||||
}
|
||||
|
||||
.menus {
|
||||
margin: 30rpx auto 0;
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
padding: 40rpx 38rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 16rpx 0rpx rgba(10, 54, 104, 0.1);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 22rpx;
|
||||
font-size: 24rpx;
|
||||
|
||||
.menu-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
width: 686rpx;
|
||||
margin: 38rpx auto 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
|
||||
.info-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.infoList {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
.infoItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 10rpx;
|
||||
}
|
||||
|
||||
.infoIndex {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.infoText {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.more-icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.repairShop {
|
||||
width: 686rpx;
|
||||
margin: 38rpx auto 0;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.shopList {
|
||||
.shopItem {
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
.shopImg {
|
||||
width: 160rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
.shopInfo {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.shopTitle {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.shopDetail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
column-gap: 10rpx;
|
||||
}
|
||||
|
||||
.shopAddress {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 2rpx;
|
||||
height: 24rpx;
|
||||
background-color: #858BA0;
|
||||
}
|
||||
|
||||
.shopDistance {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
27
pages/index/index.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/home/home'
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
24
pages/my/cardRoll.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
107
pages/my/evaluate.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<v-navigation-bar background-color="#fff" title-color="#333" title="我的评价"></v-navigation-bar>
|
||||
<view class="body">
|
||||
<view v-for="(item, index) in evaluateList" :key="index" class="item">
|
||||
<view class="date">07-06</view>
|
||||
<view class="message">
|
||||
这家修理厂的喷漆工艺非常不错,特别均匀,师傅也很细心。如果您需要做喷漆或者维修服务,不要错过这里!
|
||||
</view>
|
||||
<view class="rate">
|
||||
<!-- 设置尺寸大小 -->
|
||||
<uni-rate allow-half :value="3.5"/>
|
||||
</view>
|
||||
<view class="shopInfo">
|
||||
<image class="shopImg" src="" mode="aspectFill"></image>
|
||||
<view class="shopInfo_content">
|
||||
<view class="shopName">顺捷汽车维修搭电救援补胎中心</view>
|
||||
<view class="shopAddress">济南市历下区福瑞达历下护理院东南门旁</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
evaluateList: [{}, {}, {}]
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
background-color: #F3F5F7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
padding: 20rpx 0;
|
||||
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
background-color: #fff;
|
||||
padding: 30rpx;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 20rpx;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.shopInfo {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
column-gap: 20rpx;
|
||||
|
||||
.shopImg {
|
||||
width: 160rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
.shopInfo_content {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 6rpx 0;
|
||||
}
|
||||
|
||||
.shopName {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.shopAddress {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
78
pages/my/message.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar background-color="#fff" title-color="#333" title="消息中心"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="messageList">
|
||||
<view v-for="(item, index) in messageList" :key="index" class="messageItem">
|
||||
<image class="messageIcon" src="../../static/icons/message-icon1.png" mode="aspectFit"></image>
|
||||
<view class="messageContent">
|
||||
<view class="messageTitle">系统通知</view>
|
||||
<view class="messageContent_content">节日快乐!在这美好的时刻,送上我最真挚的祝福:愿你的每一天都充满阳光和欢笑,每一步都走向成功和辉煌。</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
messageList: [{}, {}]
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.messageList {
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
.messageItem {
|
||||
padding: 30rpx 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
border-bottom: 1rpx solid #EEEEEE;
|
||||
|
||||
.messageIcon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.messageContent {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
.messageTitle {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.messageContent_content {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #858BA0;
|
||||
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
285
pages/my/my.vue
Normal file
@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="body">
|
||||
<VNavigationBar titleColor="rgba(0,0,0,0.9)" leftTitle="true" backgroundColor="transparent" title=" ">
|
||||
</VNavigationBar>
|
||||
<view class="body-top">
|
||||
<image class="userBmg" src="../../static/images/image1.png" mode="widthFix"></image>
|
||||
<view class="userInfo">
|
||||
<image class="avatar" src="../../static/images/avatar.png" mode="aspectFit"></image>
|
||||
<text class="userName">用户昵称</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="level">
|
||||
<image class="levelIcon" src="" mode="aspectFit"></image>
|
||||
<view class="levelInfo">
|
||||
<text class="levelNum">Lv.2</text>
|
||||
<text class="levelQy">当前可享受4项权益</text>
|
||||
</view>
|
||||
<view class="showQyBtn" @click="showEquity">
|
||||
查看权益
|
||||
<image class="showQyBtnIcon" src="../../static/icons/icon1.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu1">
|
||||
<view @click="goToPage('/pages/myCar/myCar')" style="background: linear-gradient( 90deg, #DEE5FC 0%, #CAD6FA 100%);"
|
||||
class="menu1-item menu-myCar">
|
||||
<image class="menu1-item-icon" src="../../static/icons/myCar.png" mode="aspectFit"></image>
|
||||
<text style="flex: 1;">我的车辆</text>
|
||||
<image class="menu1-item-btnIcon" src="../../static/icons/icon2.png" mode=""></image>
|
||||
<image class="bmg" src="../../static/images/image2.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view @click="goToPage('/pages/myReservation/myReservation')" style="background: linear-gradient( 90deg, #CFF3ED 0%, #9FE9DD 100%);"
|
||||
class="menu1-item menu-myOrder">
|
||||
<image class="menu1-item-icon" src="../../static/icons/myOrder.png" mode="aspectFit"></image>
|
||||
<text style="flex: 1;">我的预约</text>
|
||||
<image class="menu1-item-btnIcon" src="../../static/icons/icon3.png" mode=""></image>
|
||||
<image class="bmg" src="../../static/images/image2.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menuCard">
|
||||
<view @click="goToPage(item.path)" v-for="(item, index) in menuCard1" :key="item.title" class="menu-item">
|
||||
<image class="menu-item-icon" :src="item.icon" mode="aspectFit"></image>
|
||||
<text class="menu-item-title">{{ item.title }}</text>
|
||||
<text class="messageNum" v-if="item.title === '消息中心'">
|
||||
{{ '12' }}
|
||||
</text>
|
||||
<image class="menu-item-more" src="../../static/icons/homeInfoMore.png" mode="widthFix"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menuCard">
|
||||
<view @click="goToPage(item.path)" v-for="(item, index) in menuCard2" :key="item.title" class="menu-item">
|
||||
<image class="menu-item-icon" :src="item.icon" mode="aspectFit"></image>
|
||||
<text class="menu-item-title">{{ item.title }}</text>
|
||||
<image class="menu-item-more" src="../../static/icons/homeInfoMore.png" mode="widthFix"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<tabBarVue msg="3"></tabBarVue>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
import tabBarVue from '@/components/tabBar/tabBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
tabBarVue,
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menuCard1: [
|
||||
{ title: '我的资料', icon: require('@/static/icons/my-menu-icon1.png'), path: '/pages/my/myInfo' },
|
||||
{ title: '消息中心', icon: require('@/static/icons/my-menu-icon2.png'), path: '/pages/my/message' },
|
||||
{ title: '我的评价', icon: require('@/static/icons/my-menu-icon3.png'), path: '/pages/my/evaluate' },
|
||||
],
|
||||
menuCard2: [
|
||||
{ title: '客服中心', icon: require('@/static/icons/my-menu-icon4.png') },
|
||||
{ title: '操作指南', icon: require('@/static/icons/my-menu-icon5.png'), path: "/pages/guideList/guideList" },
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToPage(path) {
|
||||
uni.navigateTo({
|
||||
url: path
|
||||
})
|
||||
},
|
||||
showEquity() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/myEquity'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
background: linear-gradient(180deg, rgba(1, 116, 246, 0.3) 0%, rgba(1, 116, 246, 0) 100%);
|
||||
background-size: 100% 600rpx;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #333333;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding-bottom: 30rpx;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.body-top {
|
||||
position: relative;
|
||||
|
||||
.userBmg {
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.userInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.avatar {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.userName {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.level {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 30rpx auto 0;
|
||||
background: linear-gradient(90deg, #0174F6 0%, #01BBF6 100%);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 30rpx;
|
||||
column-gap: 20rpx;
|
||||
|
||||
.levelIcon {
|
||||
width: 68rpx;
|
||||
height: 68rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.levelInfo {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 8rpx;
|
||||
|
||||
.levelNum {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.levelQy {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.showQyBtn {
|
||||
width: 156rpx;
|
||||
height: 48rpx;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
border-radius: 24rpx 24rpx 24rpx 24rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
column-gap: 2rpx;
|
||||
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #0174F6;
|
||||
|
||||
.showQyBtnIcon {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu1 {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 30rpx auto 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 22rpx;
|
||||
|
||||
.menu1-item {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
padding: 38rpx 28rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 18rpx;
|
||||
|
||||
.bmg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
.menu1-item-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
}
|
||||
.menu1-item-btnIcon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.menuCard {
|
||||
width: 686rpx;
|
||||
margin: 30rpx auto 0;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 16rpx 0rpx rgba(10,54,104,0.1);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
.menu-item {
|
||||
padding: 40rpx 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
.menu-item-icon {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
}
|
||||
.menu-item-title {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.menu-item-more {
|
||||
width: 14rpx;
|
||||
}
|
||||
.messageNum {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
background: #D54941;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 20rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
261
pages/my/myEquity.vue
Normal file
@ -0,0 +1,261 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar title="权益信息" background-color="rgba(0,0,0,0)" title-color="#333"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="card1">
|
||||
<image class="card1Bg" src="../../static/images/image3.png" mode="aspectFit"></image>
|
||||
<view class="topLeft">
|
||||
当前等级
|
||||
</view>
|
||||
<view class="levelNum">
|
||||
Lv.2
|
||||
</view>
|
||||
</view>
|
||||
<view class="equityTitle">
|
||||
<image class="leftIcon" src="../../static/icons/my-icon1.png" mode="aspectFit"></image>
|
||||
<view class="">尊享<text class="colorTitle">4项</text>权益</view>
|
||||
<image class="rightIcon" src="../../static/icons/my-icon1.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="card2">
|
||||
<view v-for="(item, index) in equityList" :key="index" class="cardItem">
|
||||
<view class="dian"></view>
|
||||
<text>{{ item.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="equityTitle">
|
||||
<image class="leftIcon" src="../../static/icons/my-icon1.png" mode="aspectFit"></image>
|
||||
<view class=""><text class="colorTitle">等级</text>介绍</view>
|
||||
<image class="rightIcon" src="../../static/icons/my-icon1.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<view class="card3">
|
||||
<view class="card3Header card3Tr">
|
||||
<view class="card3Td">
|
||||
等级标识
|
||||
</view>
|
||||
<view class="card3Td">
|
||||
权益信息
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in levelEquityList" :key="index" class="card3Tr">
|
||||
<view class="card3Td">
|
||||
<image class="levelIcon" src="../../static/icons/my-icon2.png" mode="aspectFit"></image>
|
||||
<text>LV.{{item.level}}</text>
|
||||
</view>
|
||||
<view class="card3Td">
|
||||
{{ item.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
equityList: [{
|
||||
title: '进店送'
|
||||
},
|
||||
{
|
||||
title: '赠送原车'
|
||||
},
|
||||
{
|
||||
title: '赠送198'
|
||||
},
|
||||
{
|
||||
title: '赠送全车360'
|
||||
},
|
||||
],
|
||||
levelEquityList: [{
|
||||
level: '1',
|
||||
desc: '进店送精美礼品一份\n赠送原车配套空气滤芯一个\n赠送198空调雾化杀菌除味一次\n赠送全车360安全检测'
|
||||
},
|
||||
{
|
||||
level: '2',
|
||||
desc: '进店送精美礼品一份\n赠送原车配套空气滤芯一个\n赠送198空调雾化杀菌除味一次\n赠送全车360安全检测'
|
||||
},
|
||||
{
|
||||
level: '3',
|
||||
desc: '进店送精美礼品一份\n赠送原车配套空气滤芯一个\n赠送198空调雾化杀菌除味一次\n赠送全车360安全检测'
|
||||
},
|
||||
{
|
||||
level: '4',
|
||||
desc: '进店送精美礼品一份\n赠送原车配套空气滤芯一个\n赠送198空调雾化杀菌除味一次\n赠送全车360安全检测'
|
||||
},
|
||||
{
|
||||
level: '5',
|
||||
desc: '进店送精美礼品一份\n赠送原车配套空气滤芯一个\n赠送198空调雾化杀菌除味一次\n赠送全车360安全检测'
|
||||
},
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, #FFE8C2 0%, rgba(255, 255, 255, 0) 100%);
|
||||
background-size: 100% 750rpx;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding-bottom: 30rpx;
|
||||
overflow: auto;
|
||||
|
||||
.card1 {
|
||||
margin: 40rpx auto;
|
||||
position: relative;
|
||||
width: 686rpx;
|
||||
// background: linear-gradient( 135deg, #FDF6EB 0%, #E6CB94 100%);
|
||||
// border-radius: 24rpx 24rpx 24rpx 24rpx;
|
||||
// border: 2rpx solid;
|
||||
// border-image: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(223, 189, 126, 1)) 2 2;
|
||||
|
||||
.card1Bg {
|
||||
width: 100%;
|
||||
height: 200rpx;
|
||||
}
|
||||
|
||||
.topLeft {
|
||||
width: 172rpx;
|
||||
height: 68rpx;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 24rpx 0rpx 24rpx 0rpx;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.levelNum {
|
||||
position: absolute;
|
||||
left: 30rpx;
|
||||
bottom: 30rpx;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 64rpx;
|
||||
color: #62440C;
|
||||
}
|
||||
}
|
||||
|
||||
.card2 {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
padding: 30rpx;
|
||||
margin: 40rpx auto;
|
||||
background: #FFF5D0;
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
|
||||
font-size: 24rpx;
|
||||
color: #62440C;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 24rpx;
|
||||
|
||||
.cardItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 16rpx;
|
||||
}
|
||||
|
||||
.dian {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background-color: #62440C;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.card3 {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 40rpx auto;
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
border: 2rpx solid #FFF5D0;
|
||||
font-size: 28rpx;
|
||||
|
||||
|
||||
|
||||
.card3Tr {
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
|
||||
&.card3Header {
|
||||
color: #62440C;
|
||||
background: #FFF5D0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.card3Td {
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
flex-shrink: 0;
|
||||
white-space: break-spaces;
|
||||
|
||||
&:first-child {
|
||||
width: 200rpx;
|
||||
border-right: 1rpx solid #DDDDDD;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.levelIcon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.equityTitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 10rpx;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
|
||||
.leftIcon,
|
||||
.rightIcon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
|
||||
.rightIcon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.colorTitle {
|
||||
color: #E8A321;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
84
pages/my/myInfo.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBarVue titleColor="#333" backgroundColor="#fff" title="我的资料"></VNavigationBarVue>
|
||||
<view class="body">
|
||||
<view class="formItem">
|
||||
<text class="formLabel">头像</text>
|
||||
<image class="avatar" src="../../static/images/avatar.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<text class="formLabel">昵称</text>
|
||||
<text class="formValue">用户昵称</text>
|
||||
<image class="formBtn" src="../../static/icons/homeInfoMore.png" mode="aspectFit"></image>
|
||||
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<text class="formLabel">手机号</text>
|
||||
<text class="formValue">157****9706</text>
|
||||
<image class="formBtn" src="../../static/icons/homeInfoMore.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBarVue from '../../components/VNavigationBar.vue';
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBarVue
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
|
||||
.body {
|
||||
|
||||
}
|
||||
|
||||
.formItem {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 0 auto;
|
||||
padding: 40rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 20rpx;
|
||||
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
}
|
||||
|
||||
.formLabel {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.formValue {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
text-align: right;
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.formBtn {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 108rpx;
|
||||
height: 108rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
189
pages/my/register.vue
Normal file
@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar title-color="#333" background-color="#fff" title="信息填写"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="formItem">
|
||||
<view class="formLabel">姓名</view>
|
||||
<view class="formContainer">
|
||||
<input placeholder="请填写你的真实姓名" type="text" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<view class="formLabel">性别</view>
|
||||
<view class="formContainer">
|
||||
<radio-group class="radioGroup">
|
||||
<label class="radio">
|
||||
<radio activeBackgroundColor="#009EDA" value="r1" checked="true" />男
|
||||
</label>
|
||||
<label class="radio">
|
||||
<radio activeBackgroundColor="#009EDA" value="r2" />女
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<view class="formLabel">省份</view>
|
||||
<view class="formContainer">
|
||||
<picker :range="addressRange" mode="multiSelector" @columnchange="addressColumnChangeFun">
|
||||
<view class="formPicker">
|
||||
<input class="formPickerInput" type="text" disabled="true" placeholder="请选择所在省份/城市/区" />
|
||||
<image class="formPickerBtn" src="../../static/icons/homeInfoMore.png" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<view class="formLabel">详细地址</view>
|
||||
<view class="formContainer">
|
||||
<picker :range="detailAddress" mode="multiSelector" @columnchange="detailColumnChangeFun">
|
||||
<view class="formPicker">
|
||||
<input class="formPickerInput" type="text" disabled="true" placeholder="请选择所在街道/小区" />
|
||||
<image class="formPickerBtn" src="../../static/icons/homeInfoMore.png" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<view class="formLabel">上传图片</view>
|
||||
<view class="formContainer">
|
||||
<view class="">
|
||||
<uni-file-picker :image-styles="{width: 80, height: 80}" v-model="imageValue"
|
||||
fileMediatype="image" limit="1" mode="grid" @select="select" @progress="progress"
|
||||
@success="success" @fail="fail">
|
||||
<image style="width: 160rpx;height: 160rpx;" src="../../static/icons/addImageIcon.png"
|
||||
mode="aspectFit"></image>
|
||||
</uni-file-picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
detailAddress: [
|
||||
['a', 'b'],
|
||||
['b', 'a']
|
||||
],
|
||||
addressRange: [
|
||||
['山东'],
|
||||
['济南'],
|
||||
['历下区']
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
detailColumnChangeFun({
|
||||
detail
|
||||
}) {
|
||||
if (detail.column === 0) {
|
||||
// 动态配置第二列
|
||||
this.$set(this.detailAddress, 1, ['m', 'n'])
|
||||
}
|
||||
},
|
||||
addressColumnChangeFun({
|
||||
detail
|
||||
}) {
|
||||
if (detail.column === 0) {
|
||||
// 动态配置第二列
|
||||
this.$set(this.detailAddress, 1, ['济宁'])
|
||||
// 动态配置第三列
|
||||
this.$set(this.detailAddress, 2, ['任城'])
|
||||
} else if (detail.column === 1) {
|
||||
// 动态配置第三列
|
||||
this.$set(this.detailAddress, 2, ['任城'])
|
||||
}
|
||||
},
|
||||
// 获取上传状态
|
||||
select(e) {
|
||||
console.log('选择文件:', e)
|
||||
},
|
||||
// 获取上传进度
|
||||
progress(e) {
|
||||
console.log('上传进度:', e)
|
||||
},
|
||||
|
||||
// 上传成功
|
||||
success(e) {
|
||||
console.log('上传成功')
|
||||
},
|
||||
|
||||
// 上传失败
|
||||
fail(e) {
|
||||
console.log('上传失败:', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.formItem {
|
||||
padding: 40rpx 0;
|
||||
margin: 0 32rpx;
|
||||
border-bottom: 1rpx solid #EEEEEE;
|
||||
}
|
||||
|
||||
.formLabel {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.radioGroup {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 100rpx;
|
||||
}
|
||||
|
||||
.radio {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
/* #ifdef MP-WEIXIN */
|
||||
radio {
|
||||
filter: hue-rotate(90deg);
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.formPicker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
.formPickerInput {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.formPickerBtn {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
186
pages/myCar/carDetail.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar title="车辆详情" background-color="#fff" title-color="#333"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="card">
|
||||
<view class="formItem">
|
||||
<text class="formLabel">车辆照片</text>
|
||||
<image class="carImg" src="" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<text class="formLabel">车牌号</text>
|
||||
<text class="formValue">鲁A 781NB</text>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<text class="formLabel">车辆持有人</text>
|
||||
<text class="formValue">魏书豪</text>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<text class="formLabel">持有人电话</text>
|
||||
<text class="formValue">15726576890</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<view class="formItem1">
|
||||
<view class="labelVal">
|
||||
<text class="formLabel">车辆年检时间</text>
|
||||
<text class="formValue">2024年</text>
|
||||
</view>
|
||||
<image class="formImg" src="" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="formItem1">
|
||||
<view class="labelVal">
|
||||
<text class="formLabel">车辆保险时间</text>
|
||||
<text class="formValue">2024年</text>
|
||||
</view>
|
||||
<image class="formImg" src="" mode="aspectFill"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<view class="btnItem delete">
|
||||
<uni-icons type="trash" color="#F92C2C"></uni-icons>
|
||||
删除
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="btnItem edit">
|
||||
<uni-icons type="compose" color="#0174F6"></uni-icons>
|
||||
编辑
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
background-color: #F3F5F7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
|
||||
.card {
|
||||
margin: 20rpx 0;
|
||||
padding: 0 32rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.formItem {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 0 auto;
|
||||
padding: 40rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 20rpx;
|
||||
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.labelVal {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
.formItem1 {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 0 auto;
|
||||
padding: 40rpx;
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.formLabel {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.formValue {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
text-align: right;
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.carImg {
|
||||
width: 240rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
.formImg {
|
||||
margin-top: 30rpx;
|
||||
width: 240rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: #FFFFFF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.line {
|
||||
width: 2rpx;
|
||||
background-color: #DDDDDD;
|
||||
}
|
||||
|
||||
.btnItem {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
padding: 34rpx 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-size: 32rpx;
|
||||
|
||||
&.delete {
|
||||
color: #F92C2C;
|
||||
}
|
||||
|
||||
&.edit {
|
||||
color: #0174F6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
118
pages/myCar/myCar.vue
Normal file
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar titleColor="rgba(0,0,0,0.9)" backgroundColor="#fff" title="我的车辆">
|
||||
</VNavigationBar>
|
||||
<view class="body">
|
||||
<scroll-view style="height: 100%;" scroll-y="true">
|
||||
<view class="carList">
|
||||
<view v-for="(item, index) in carList" :key="index" class="carItem" @click="gotoDetail(item)">
|
||||
<image class="carImage" src="" mode="aspectFit"></image>
|
||||
<view class="carInfo">
|
||||
<view class="carNum">{{ item.carNum }}</view>
|
||||
<view class="name">车辆持有人:{{ item.name }}</view>
|
||||
<view class="phone">持有人电话:{{ item.phone }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="addCarBtn">
|
||||
<uni-icons color="#0174F6" type="plusempty"></uni-icons>
|
||||
添加车辆
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
carList: [{
|
||||
carNum: '鲁A 781NB',
|
||||
name: '魏书豪',
|
||||
phone: '15726786903',
|
||||
image: ''
|
||||
}]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
gotoDetail() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/myCar/carDetail'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
background-color: #F3F5F7;
|
||||
}
|
||||
|
||||
.carList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.carItem {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 20rpx auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
.carImage {
|
||||
background-color: #eee;
|
||||
width: 240rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
}
|
||||
|
||||
.carNum {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.name,
|
||||
.phone {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #858BA0;
|
||||
}
|
||||
|
||||
.addCarBtn {
|
||||
padding: 34rpx 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 12rpx;
|
||||
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #0174F6;
|
||||
}
|
||||
}
|
||||
</style>
|
435
pages/myReservation/addReservation.vue
Normal file
@ -0,0 +1,435 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar background-color="rgba(0,0,0,0)" title-color="#333" title="提交预约"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="carInfo">
|
||||
<view class="cardInfoHeader">
|
||||
<view class="carInfoLeftTop">
|
||||
<image class="carInfoLeftTopIcon" src="../../static/icons/order-icon10.png" mode="widthFix">
|
||||
</image>
|
||||
车辆信息
|
||||
</view>
|
||||
<view class="carInfoRightTop">
|
||||
<uni-icons type="compose" color="#0174F6"></uni-icons> 修改信息
|
||||
</view>
|
||||
</view>
|
||||
<view class="cardInfoBody">
|
||||
<view class="cardInfoBody_content">
|
||||
<view class="carForm">
|
||||
<view class="carForm_num">鲁A 781NB</view>
|
||||
<view class="carForm_carName">车辆持有人:位数好</view>
|
||||
<view class="carForm_carPhone">持有人电话:13111111111</view>
|
||||
</view>
|
||||
<image class="carImg" src="" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="cardInfoBody_footer">
|
||||
<view class="nj">
|
||||
年检时间:<text class="date">2024年</text>
|
||||
<image class="cardInfoBody_footerIcon" src="../../static/icons/icon2.png" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
<view class="bx">
|
||||
保险时间:<text class="date">2024年</text>
|
||||
<image class="cardInfoBody_footerIcon" src="../../static/icons/icon2.png" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="baseInfo">
|
||||
<view class="formItem">
|
||||
<view class="formItem_content">
|
||||
<view class="label">姓名</view>
|
||||
<input class="formItemInput" placeholder="请输入姓名" type="text" />
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<view class="formItem_content">
|
||||
<view class="label">联系电话</view>
|
||||
<input class="formItemInput" placeholder="请输入姓名" type="text" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="formItem">
|
||||
<picker mode="selector" :range="['汽车维修']" @change="">
|
||||
<view class="formItem_content">
|
||||
<view class="label">预约项目</view>
|
||||
<input disabled class="formItemInput" placeholder="请选择预约项目" type="text" />
|
||||
<image class="formItemBtn" src="../../static/icons/homeInfoMore.png" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dateCard">
|
||||
<view class="cardTitle">预约时间</view>
|
||||
<view class="datePicker">
|
||||
<view v-for="(date, index) in dateList" :key="date.date" class="dateItem"
|
||||
:class="{active: chooseDate === date.date, disabled: date.disabled}"
|
||||
@click="chooseDateFun(date)">
|
||||
<text>{{date.date}}</text>
|
||||
<text>{{date.title}}</text>
|
||||
<image v-if="chooseDate === date.date" class="activeIcon" src="../../static/icons/order-icon11.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="timerPicker">
|
||||
<view v-for="(time, index) in timeList" :key="index" class="timeItem"
|
||||
:class="{active: chooseTime === time.time, disabled: time.disabled}"
|
||||
@click="chooseTimeFun(time)">
|
||||
<text>{{time.time}}</text>
|
||||
<image v-if="chooseTime === time.time" class="activeIcon" src="../../static/icons/order-icon11.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<view class="footerBtn" @click="submit">提交预约</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dateList: [{
|
||||
date: '06-05',
|
||||
title: '周四',
|
||||
disabled: true
|
||||
}, {
|
||||
date: '06-06',
|
||||
title: '周四',
|
||||
disabled: false
|
||||
}, {
|
||||
date: '06-07',
|
||||
title: '周四',
|
||||
disabled: false
|
||||
}, {
|
||||
date: '06-08',
|
||||
title: '周四',
|
||||
disabled: false
|
||||
}, {
|
||||
date: '06-09',
|
||||
title: '周四',
|
||||
disabled: false
|
||||
}, ],
|
||||
chooseDate: '06-06',
|
||||
chooseTime: '13:00',
|
||||
timeList: [{
|
||||
time: '11:00',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
time: '13:00',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
time: '15:00',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
time: '16:30',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
time: '18:00',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
time: '15:00',
|
||||
disabled: false
|
||||
},
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
chooseTimeFun(time) {
|
||||
if (time.disabled) {
|
||||
return
|
||||
}
|
||||
this.chooseTime = time.time
|
||||
},
|
||||
chooseDateFun(date) {
|
||||
if (date.disabled) {
|
||||
return
|
||||
}
|
||||
this.chooseDate = date.date
|
||||
},
|
||||
submit() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/myReservation/reservationSuccess'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background: linear-gradient(180deg, #C1DEFF 0%, rgba(193, 222, 255, 0) 100%);
|
||||
background-size: 100% 500rpx;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
background: linear-gradient(180deg, rgba(193, 222, 255, 0) 0%, #F3F5F7 50%, #F3F5F7 100%);
|
||||
|
||||
.carInfo {
|
||||
margin: 20rpx 32rpx 30rpx;
|
||||
background: #022B9A;
|
||||
box-shadow: 0rpx 8rpx 16rpx 0rpx rgba(10, 54, 104, 0.1);
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.cardInfoHeader {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.carInfoLeftTop {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
padding: 20rpx;
|
||||
color: #fff;
|
||||
|
||||
.carInfoLeftTopIcon {
|
||||
width: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.carInfoRightTop {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
background-color: #fff;
|
||||
text-align: right;
|
||||
padding-right: 20rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
border: 10rpx;
|
||||
clip-path: polygon(20rpx 0, 100% 0, 100% 0, 100% 100%, 100% 100%, 0 100%, 10rpx 10rpx);
|
||||
}
|
||||
|
||||
.cardInfoBody {
|
||||
padding: 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx 0rpx 0 0;
|
||||
}
|
||||
|
||||
.cardInfoBody_content {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
column-gap: 32rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1rpx dashed #858BA0;
|
||||
|
||||
.carForm {
|
||||
padding: 10rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #858BA0;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.carForm_num {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.carImg {
|
||||
width: 240rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
|
||||
.cardInfoBody_footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
padding-top: 20rpx;
|
||||
|
||||
.nj {
|
||||
border-right: 1rpx solid #ddd;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.nj,
|
||||
.bx {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
}
|
||||
|
||||
.date {
|
||||
color: #0174F6;
|
||||
}
|
||||
|
||||
.cardInfoBody_footerIcon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.baseInfo {
|
||||
margin: 20rpx 32rpx 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
padding: 0 30rpx;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
|
||||
.formItem {
|
||||
padding: 40rpx 0;
|
||||
border-bottom: 1rpx solid #EEEEEE;
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.formItem_content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
}
|
||||
|
||||
.formItemInput {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.formItemBtn {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.dateCard {
|
||||
margin: 20rpx 32rpx 30rpx;
|
||||
padding: 22rpx 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
|
||||
.cardTitle {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.datePicker {
|
||||
display: flex;
|
||||
column-gap: 20rpx;
|
||||
overflow: auto;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #EEEEEE;
|
||||
|
||||
.dateItem {
|
||||
padding: 20rpx 40rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.1);
|
||||
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.timerPicker {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
padding-top: 30rpx;
|
||||
.timeItem {
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.1);
|
||||
padding: 30rpx 0;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.timeItem,
|
||||
.dateItem {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
&.active {
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 2rpx solid #0174F6;
|
||||
color: #0174F6;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 1rpx solid rgba(0,0,0,0.1);
|
||||
color: rgba(51,51,51,0.4);
|
||||
}
|
||||
.activeIcon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 36rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: #FFFFFF;
|
||||
padding: 12rpx 0;
|
||||
padding-bottom: calc(12rpx + env(safe-area-inset-bottom));
|
||||
|
||||
.footerBtn {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
padding: 22rpx 0;
|
||||
background: #0174F6;
|
||||
border-radius: 38rpx 38rpx 38rpx 38rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
</style>
|
78
pages/myReservation/myReservation.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar titleColor="rgba(0,0,0,0.9)" backgroundColor="transparent" title="我的预约">
|
||||
</VNavigationBar>
|
||||
<view class="body">
|
||||
<scroll-view style="height: 100%;" scroll-y="true">
|
||||
<view class="orderList">
|
||||
<reservationOrderVue v-for="(item, index) in orderList" :key="index" :orderInfo="item">
|
||||
</reservationOrderVue>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
import tabBarVue from '@/components/tabBar/tabBar.vue'
|
||||
import reservationOrderVue from '../../components/reservationOrder/reservationOrder.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
tabBarVue,
|
||||
VNavigationBar,
|
||||
reservationOrderVue
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
orderList: [{
|
||||
title: '顺捷汽车维修搭电救援补胎中心',
|
||||
status: '1',
|
||||
address: '济南市历下区福瑞达历下护理院东南门旁',
|
||||
phone: '15726506879',
|
||||
busiTypeStr: '汽车维修'
|
||||
},
|
||||
{
|
||||
title: '顺捷汽车维修搭电救援补胎中心',
|
||||
status: '1',
|
||||
address: '济南市历下区福瑞达历下护理院东南门旁',
|
||||
phone: '15726506879',
|
||||
busiTypeStr: '汽车维修'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
height: 100%;
|
||||
background: #F3F5F7;
|
||||
background: linear-gradient(180deg, #C1DEFF 0%, rgba(#F3F5F7, 0) 100%);
|
||||
background-size: 100% 600rpx;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #333333;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding: 16rpx 0 30rpx;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.orderList {
|
||||
width: 686rpx;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
164
pages/myReservation/reservationSuccess.vue
Normal file
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<v-navigation-bar background-color="rgba(0,0,0,0)" title-color="#333" title="预约成功"></v-navigation-bar>
|
||||
<view class="body">
|
||||
<view class="card">
|
||||
<view class="success">
|
||||
<image class="successIcon" src="../../static/icons/success.png" mode="aspectFit"></image>
|
||||
<text>预约成功</text>
|
||||
</view>
|
||||
|
||||
<view class="orderInfo">
|
||||
<view class="shopName">顺捷汽车维修搭电救援补胎中心</view>
|
||||
<view class="baseInfo">
|
||||
<image class="baseInfoIcon" src="../../static/icons/order-icon1.png" mode=""></image>
|
||||
济南市历下区福瑞达历下护理院东南门旁
|
||||
</view>
|
||||
<view class="baseInfo">
|
||||
<image class="baseInfoIcon" src="../../static/icons/order-icon2.png" mode=""></image>
|
||||
15726506879
|
||||
</view>
|
||||
<view class="baseInfo">
|
||||
<image class="baseInfoIcon" src="../../static/icons/order-icon3.png" mode=""></image>
|
||||
汽车维修
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="footer">
|
||||
<view class="showOrder" @click="showOrder">查看订单</view>
|
||||
|
||||
<view class="back" @click="back">完成</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
})
|
||||
},
|
||||
showOrder() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/myReservation/myReservation'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
|
||||
background: linear-gradient(180deg, #C1DEFF 0%, rgba(193, 222, 255, 0) 100%);
|
||||
background-size: 100% 500rpx;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: linear-gradient(180deg, rgba(193, 222, 255, 0) 0%, #f1f1f1 100%);
|
||||
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 40rpx 32rpx;
|
||||
padding: 60rpx 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
}
|
||||
|
||||
.success {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
padding-bottom: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
row-gap: 30rpx;
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
}
|
||||
|
||||
.successIcon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
}
|
||||
|
||||
.orderInfo {
|
||||
padding: 40rpx 0 60rpx;
|
||||
}
|
||||
|
||||
.shopName {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.baseInfo {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
margin-top: 30rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 12rpx;
|
||||
|
||||
.baseInfoIcon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
row-gap: 40rpx;
|
||||
|
||||
.showOrder, .back {
|
||||
width: 510rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 38rpx 38rpx 38rpx 38rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.showOrder {
|
||||
background: #0174F6;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.back {
|
||||
border-radius: 38rpx 38rpx 38rpx 38rpx;
|
||||
border: 2rpx solid #0174F6;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #0174F6;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
116
pages/orderDetail/evaluate.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<v-navigation-bar background-color="#fff" title-color="#333" title="服务评价"></v-navigation-bar>
|
||||
<view class="body">
|
||||
<view style="padding: 0 32rpx;">
|
||||
<view class="shopInfo">
|
||||
<image class="shopImg" src="" mode="aspectFill"></image>
|
||||
<view class="shopInfo_content">
|
||||
<view class="shopName">顺捷汽车维修搭电救援补胎中心</view>
|
||||
<view class="shopAdress">济南市历下区福瑞达历下护理院东南门旁</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="rate">
|
||||
<text>服务评价</text>
|
||||
<uni-rate allow-half="true" value=""></uni-rate>
|
||||
</view>
|
||||
<textarea class="message" value="" placeholder="可在此输入当前维修厂的服务评价" />
|
||||
<view class="submit" @click="submit">提交评价</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.shopInfo {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
column-gap: 20rpx;
|
||||
margin: 30rpx 0;
|
||||
|
||||
.shopImg {
|
||||
width: 160rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
.shopInfo_content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 6rpx 0;
|
||||
}
|
||||
.shopName {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.shopAdress {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
.rate {
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
column-gap: 28rpx;
|
||||
}
|
||||
.message {
|
||||
padding: 30rpx 0;
|
||||
height: 400rpx;
|
||||
}
|
||||
.submit {
|
||||
width: 510rpx;
|
||||
height: 76rpx;
|
||||
|
||||
margin: 0 auto;
|
||||
|
||||
background: #0174F6;
|
||||
border-radius: 38rpx 38rpx 38rpx 38rpx;
|
||||
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
324
pages/orderDetail/orderDetail.vue
Normal file
@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="containerBody">
|
||||
<VNavigationBar title="订单详情" background-color="rgba(0,0,0,0)" title-color="#333"></VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="orderStatus card">
|
||||
<template v-if="orderInfo.status === '1'">
|
||||
<image class="statusIcon" src="@/static/icons/order-icon8.png" mode="aspectFit"></image>
|
||||
<text>维修中</text>
|
||||
</template>
|
||||
<template v-else-if="orderInfo.status === '0'">
|
||||
<image class="statusIcon" src="@/static/icons/order-icon9.png" mode="aspectFit"></image>
|
||||
<text>等待维修</text>
|
||||
</template>
|
||||
</view>
|
||||
<view class="reservationOrder card">
|
||||
<reservationOrder :hideFooter="orderInfo.status === '0'" :order-info="orderInfo" :isDetail="true">
|
||||
</reservationOrder>
|
||||
</view>
|
||||
|
||||
<view v-if="orderInfo.status !== '0'" class="progress card">
|
||||
<view v-for="(item, index) in processList" :key="index" class="processItem">
|
||||
<view class="row1">
|
||||
<view v-if="item.status !== '3'" class="processIndex">{{ index + 1 }}</view>
|
||||
<view v-if="item.status === '3'" class="processIndex end">
|
||||
<uni-icons type="checkmarkempty" color="#fff"></uni-icons>
|
||||
</view>
|
||||
<text class="processTitle">{{ item.title }}</text>
|
||||
</view>
|
||||
<view class="row2">
|
||||
<view class="lineBox">
|
||||
<view v-if="index < processList.length - 1" class="line"></view>
|
||||
</view>
|
||||
<view class="row2_body">
|
||||
<view class="desc">{{item.desc}}</view>
|
||||
<view class="imageList">
|
||||
<image class="imageItem" v-for="(img, imgIndex) in item.imageList" :key="imgIndex"
|
||||
:src="img" mode="aspectFill"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="reservationInfo card">
|
||||
<view class="row">
|
||||
<text class="col1">姓名</text>
|
||||
<text class="col2">{{'魏书豪'}}</text>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="col1">联系电话</text>
|
||||
<text class="col2">{{'15728586970'}}</text>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="col1">预约项目</text>
|
||||
<text class="col2">{{'车辆维修'}}</text>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="col1">预约时间</text>
|
||||
<text class="col2">{{'2024-06-05 13:00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer" v-if="['0', '2'].includes(orderInfo.status)">
|
||||
<view v-if="orderInfo.status === '2'" class="footerBtn" @click="gotoEvaluate">服务评价</view>
|
||||
<template v-else-if="orderInfo.status === '0'">
|
||||
<view class="footerBtn phone">
|
||||
<image class="footerBtnIcon" src="../../static/icons/order-icon7.png" mode="aspectFit"></image>
|
||||
拨打电话
|
||||
</view>
|
||||
<view class="footerBtn address">
|
||||
<image class="footerBtnIcon" src="../../static/icons/order-icon6.png" mode="aspectFit"></image>地址导航
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
import reservationOrder from '@/components/reservationOrder/reservationOrder.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar,
|
||||
reservationOrder
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
orderInfo: {
|
||||
title: '顺捷汽车维修搭电救援补胎中心',
|
||||
address: '济南市历下区福瑞达历下护理院东南门旁',
|
||||
phone: '15726506879',
|
||||
busiTypeStr: '15726506879',
|
||||
status: '1'
|
||||
},
|
||||
processList: [{
|
||||
title: '接收车辆',
|
||||
desc: '车辆已到维修厂,工作人员正准备开始维修',
|
||||
imageList: ['', '', ''],
|
||||
status: '1'
|
||||
},
|
||||
{
|
||||
title: '开始维修轮胎',
|
||||
desc: '工作人员开始对车辆轮胎进行维修',
|
||||
imageList: [],
|
||||
status: '2'
|
||||
},
|
||||
{
|
||||
title: '车辆维修完成',
|
||||
desc: '车辆维修完成,请选择合适时间到店提车',
|
||||
imageList: [],
|
||||
status: '3'
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
gotoEvaluate() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/orderDetail/evaluate'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
background-color: #F3F5F7;
|
||||
|
||||
.containerBody {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, #C1DEFF 0%, rgba(193, 222, 255, 0) 100%);
|
||||
background-size: 100% 500rpx;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 30rpx auto;
|
||||
}
|
||||
|
||||
.orderStatus {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #0174F6;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 20rpx;
|
||||
|
||||
.statusIcon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.reservationOrder {
|
||||
box-sizing: border-box;
|
||||
width: 686rpx;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
|
||||
.progress {
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 20rpx;
|
||||
|
||||
.processItem {
|
||||
.row1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
}
|
||||
|
||||
.processIndex {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
background: #E1EFFF;
|
||||
border-radius: 22rpx 22rpx 22rpx 22rpx;
|
||||
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
color: #0174F6;
|
||||
line-height: 44rpx;
|
||||
|
||||
&.end {
|
||||
background: #0174F6;
|
||||
}
|
||||
}
|
||||
|
||||
.processTitle {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
|
||||
.row2 {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
column-gap: 10rpx;
|
||||
|
||||
.lineBox {
|
||||
width: 44rpx;
|
||||
position: relative;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 2rpx;
|
||||
height: 100%;
|
||||
background-color: #0174F6;
|
||||
}
|
||||
|
||||
.row2_body {
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
.desc {
|
||||
font-size: 24rpx;
|
||||
color: #858BA0;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.imageList {
|
||||
display: flex;
|
||||
row-gap: 20rpx;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
.imageItem {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reservationInfo {
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 40rpx;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
|
||||
.col1 {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.col2 {
|
||||
color: #858BA0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: #FFFFFF;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
padding: 12rpx 32rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 22rpx;
|
||||
|
||||
.footerBtn {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
height: 76rpx;
|
||||
margin: 0 auto;
|
||||
background: #0174F6;
|
||||
border-radius: 38rpx 38rpx 38rpx 38rpx;
|
||||
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 8rpx;
|
||||
line-height: 1.5;
|
||||
|
||||
&.phone {
|
||||
background: #E8A321;
|
||||
}
|
||||
|
||||
&.address {
|
||||
|
||||
}
|
||||
|
||||
.footerBtnIcon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
251
pages/orderList/orderList.vue
Normal file
@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<VNavigationBar titleColor="rgba(0,0,0,0.9)" leftTitle="true" backgroundColor="transparent" title="我的订单">
|
||||
</VNavigationBar>
|
||||
<view class="body">
|
||||
<view class="tabList">
|
||||
<view @click="changeTabFun(item.id)" v-for="(item, index) in tabList" :key="index" class="tabItem"
|
||||
:class="{actived: item.id === activeKey}">
|
||||
{{ item.title }}
|
||||
<view v-if="activeKey === item.id" class="activeLine"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="orderList">
|
||||
<view v-for="(item, index) in orderList" :key="index" class="orderItem">
|
||||
<view class="line1">
|
||||
<view class="orderNo">
|
||||
订单编号:{{item.orderNo}}
|
||||
</view>
|
||||
<text class="orderStatus" :class="['status_' + item.status]">
|
||||
{{ getStatus(item.status) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="orderInfo">
|
||||
<image class="orderInfoIcon" src="" mode="aspectFit"></image>
|
||||
<text class="orderInfoText">{{ item.busiTypeStr }}</text>
|
||||
</view>
|
||||
<view class="orderInfo">
|
||||
<image class="orderInfoIcon" src="" mode="aspectFit"></image>
|
||||
<text class="orderInfoText">{{ item.address }}</text>
|
||||
</view>
|
||||
<view class="line2">
|
||||
<view>
|
||||
共计
|
||||
<text class="orderAmountUnit">¥</text>
|
||||
<text class="orderAmount">781</text>
|
||||
</view>
|
||||
<text>{{ item.date }}</text>
|
||||
</view>
|
||||
<view class="line3">
|
||||
<view @click="gotoDetail(item)" class="showOrder" v-if="item.status === '1'">查看订单</view>
|
||||
<view @click="gotoEvaluate(item)" class="evaluate" v-if="item.status === '2'">评价订单</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<tabBarVue msg="2"></tabBarVue>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
import tabBarVue from '@/components/tabBar/tabBar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
tabBarVue,
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeKey: 0,
|
||||
tabList: [{
|
||||
id: 0,
|
||||
title: '全部订单'
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '维修中'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '待评价'
|
||||
},
|
||||
],
|
||||
orderList: [{
|
||||
orderNo: '20198104817050157810',
|
||||
status: '1',
|
||||
busiTypeStr: '维修轮胎',
|
||||
address: '顺捷汽车维修搭电救援补胎中心',
|
||||
amount: '781',
|
||||
date: '2024-07-02 12:00'
|
||||
},
|
||||
{
|
||||
orderNo: '20198104817050157810',
|
||||
status: '2',
|
||||
busiTypeStr: '维修轮胎',
|
||||
address: '顺捷汽车维修搭电救援补胎中心',
|
||||
amount: '781',
|
||||
date: '2024-07-02 12:00'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeTabFun(id) {
|
||||
this.activeKey = id
|
||||
},
|
||||
getStatus(status) {
|
||||
switch (status) {
|
||||
case '1':
|
||||
return '维修中'
|
||||
case '2':
|
||||
return '待评价'
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
gotoDetail() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/orderDetail/orderDetail'
|
||||
})
|
||||
},
|
||||
gotoEvaluate() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/orderDetail/evaluate'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
height: 100%;
|
||||
background: #F3F5F7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #333333;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding: 24rpx 32rpx;
|
||||
}
|
||||
|
||||
.tabList {
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 40rpx;
|
||||
|
||||
.tabItem {
|
||||
padding: 30rpx;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
font-size: 24rpx;
|
||||
|
||||
&.actived {
|
||||
color: #0174F6;
|
||||
}
|
||||
|
||||
.activeLine {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 96rpx;
|
||||
height: 6rpx;
|
||||
background: #0174F6;
|
||||
border-radius: 4rpx 4rpx 0rpx 0rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.orderList {
|
||||
padding: 30rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 20rpx;
|
||||
|
||||
.orderItem {
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
}
|
||||
.line1 {
|
||||
margin-bottom: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 24rpx;
|
||||
.orderNo {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
font-weight: 500;
|
||||
color: #858BA0;
|
||||
}
|
||||
.status_1 {
|
||||
color: #0174F6;
|
||||
}
|
||||
.status_2 {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
.orderInfo {
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 10rpx;
|
||||
.orderInfoIcon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
background: #ddd;
|
||||
}
|
||||
.orderInfoText {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
.line2 {
|
||||
margin: 30rpx 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #858BA0;
|
||||
.orderAmountUnit {
|
||||
color: #F92C2C;
|
||||
}
|
||||
.orderAmount {
|
||||
color: #F92C2C;
|
||||
font-weight: bold;
|
||||
font-size: 40rpx;
|
||||
}
|
||||
}
|
||||
.line3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.showOrder, .evaluate {
|
||||
width: 172rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 30rpx 30rpx 30rpx 30rpx;
|
||||
border: 2rpx solid #0174F6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: #0174F6;
|
||||
}
|
||||
.evaluate {
|
||||
border: 1rpx solid #EEEEEE;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
324
pages/shopDetail/shopDetail.vue
Normal file
@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="body">
|
||||
<view class="body-top">
|
||||
<view style="z-index: 2;position: relative;">
|
||||
<VNavigationBar titleColor="#fff" backgroundColor="rgba(0,0,0,0)">
|
||||
<template v-slot:back>
|
||||
<image style="width: 56rpx;height: 56rpx;" src="../../static/icons/backIcon.png"
|
||||
mode="aspectFit"></image>
|
||||
</template>
|
||||
</VNavigationBar>
|
||||
</view>
|
||||
<image class="shopImg" src="" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="shopBody">
|
||||
<view class="shopDetail">
|
||||
<view class="shopTitle">顺捷汽车维修搭电救援补胎中心</view>
|
||||
<view class="rate">
|
||||
<view class="rateNumBox">
|
||||
<text>4.5</text>
|
||||
<image style="width: 28rpx;height: 28rpx;" src="../../static/icons/rateIcon.png"
|
||||
mode="aspectFit"></image>
|
||||
</view>
|
||||
<text>强烈推荐</text>
|
||||
</view>
|
||||
<view class="shopDetailText">
|
||||
<mote-lines-divide :line="3" expandText="全部" foldHint="收起">
|
||||
<text class="shopDetailTextLabel">厂家介绍:</text>
|
||||
<text class="shopDetailTextValue">
|
||||
正安汽车维修服务有限公司成立于1993年10月25日,属东莞市成立最早、规模最大的民营汽修企业之一。现在莞城区及桥头镇开设有二家连锁经营分厂及直属汽车销售部,主要从事汽车销售、售后,
|
||||
</text>
|
||||
</mote-lines-divide>
|
||||
</view>
|
||||
<view class="shopDetailFooter">
|
||||
<view class="shopAddress">
|
||||
<image style="width: 32rpx;height: 32rpx;" src="../../static/icons/order-icon1.png"
|
||||
mode="aspectFit"></image>
|
||||
<text>济南市历下区福瑞达历下护理院东南门旁</text>
|
||||
</view>
|
||||
<view class="shopPhone">
|
||||
<image style="width: 32rpx;height: 32rpx;" src="../../static/icons/order-icon2.png"
|
||||
mode="aspectFit"></image>
|
||||
<text>电话</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="busiDetail">
|
||||
<view class="busiDetailTitle">顺捷汽车维修搭电救援补胎中心</view>
|
||||
<view class="busiList">
|
||||
<view v-for="(item, index) in busiList" :key="index" class="busiItem">
|
||||
<image class="busiTypeImg" :src="item.image" mode="aspectFill"></image>
|
||||
<view class="busiItemInfo">
|
||||
<view class="busiItemTitle">{{ item.title }}</view>
|
||||
<view class="busiItemDesc">{{ item.desc }}</view>
|
||||
</view>
|
||||
<view class="busiItemBtn">查看</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<view class="btn" @click="gotoReservation">开始预约</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VNavigationBar from '@/components/VNavigationBar.vue'
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
busiList: [{
|
||||
title: '钣金喷漆维修',
|
||||
desc: '钣金喷漆维修是一个汽车修理的技术手段,此方面汽车钣金等于汽车钣金修理,指汽车发生碰撞后要对车身进行修复,也即除对车身进行防腐和装饰的喷涂工作外其余的所有工作。如汽车车身损伤的分析,汽车车身的测量,汽车车身钣金的整形,拉伸矫正,去应力焊接,以及汽车车身附件装配,调整等工作。',
|
||||
image: ''
|
||||
}, {
|
||||
title: '钣金喷漆维修',
|
||||
desc: '钣金喷漆维修是一个汽车修理的技术手段,此方面汽车钣金等于汽车钣金修理,指汽车发生碰撞后要对车身进行修复,也即除对车身进行防腐和装饰的喷涂工作外其余的所有工作。如汽车车身损伤的分析,汽车车身的测量,汽车车身钣金的整形,拉伸矫正,去应力焊接,以及汽车车身附件装配,调整等工作。',
|
||||
image: ''
|
||||
}, {
|
||||
title: '钣金喷漆维修',
|
||||
desc: '钣金喷漆维修是一个汽车修理的技术手段,此方面汽车钣金等于汽车钣金修理,指汽车发生碰撞后要对车身进行修复,也即除对车身进行防腐和装饰的喷涂工作外其余的所有工作。如汽车车身损伤的分析,汽车车身的测量,汽车车身钣金的整形,拉伸矫正,去应力焊接,以及汽车车身附件装配,调整等工作。',
|
||||
image: ''
|
||||
}, {
|
||||
title: '钣金喷漆维修',
|
||||
desc: '钣金喷漆维修是一个汽车修理的技术手段,此方面汽车钣金等于汽车钣金修理,指汽车发生碰撞后要对车身进行修复,也即除对车身进行防腐和装饰的喷涂工作外其余的所有工作。如汽车车身损伤的分析,汽车车身的测量,汽车车身钣金的整形,拉伸矫正,去应力焊接,以及汽车车身附件装配,调整等工作。',
|
||||
image: ''
|
||||
}, ]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 去预约
|
||||
gotoReservation() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/myReservation/addReservation'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.body-top {
|
||||
position: relative;
|
||||
width: 750rpx;
|
||||
height: 468rpx;
|
||||
|
||||
.shopImg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.back {}
|
||||
}
|
||||
|
||||
.shopBody {
|
||||
position: relative;
|
||||
top: -50rpx;
|
||||
overflow: auto;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.shopDetail {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 30rpx 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 8rpx 16rpx 0rpx rgba(10, 54, 104, 0.1);
|
||||
border-radius: 32rpx 32rpx 0rpx 0rpx;
|
||||
|
||||
.shopTitle {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.rate {
|
||||
margin: 30rpx 0;
|
||||
box-sizing: border-box;
|
||||
width: 282rpx;
|
||||
height: 56rpx;
|
||||
background: #FFF1DB;
|
||||
border-radius: 30rpx 30rpx 30rpx 30rpx;
|
||||
padding-right: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #E8A321;
|
||||
|
||||
.rateNumBox {
|
||||
width: 120rpx;
|
||||
height: 56rpx;
|
||||
background: linear-gradient(180deg, #FFD187 0%, #FEB33A 100%);
|
||||
border-radius: 30rpx 30rpx 30rpx 30rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 4rpx;
|
||||
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.shopDetailText {
|
||||
padding-bottom: 30rpx;
|
||||
border-bottom: 1rpx solid #EEEEEE;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.shopDetailTextLabel {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.shopDetailTextValue {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.shopDetailFooter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.shopAddress {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
border-right: 1rpx solid #EEEEEE;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.shopPhone {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
row-gap: 4rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.busiDetail {
|
||||
padding: 30rpx 32rpx;
|
||||
background: #FFFFFF;
|
||||
|
||||
.busiDetailTitle {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.busiList {
|
||||
.busiItem {
|
||||
padding: 30rpx 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #DDDDDD;
|
||||
column-gap: 20rpx;
|
||||
}
|
||||
|
||||
.busiTypeImg {
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.busiItemInfo {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.busiItemTitle {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.busiItemDesc {
|
||||
font-size: 24rpx;
|
||||
color: #858BA0;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.busiItemBtn {
|
||||
width: 100rpx;
|
||||
height: 48rpx;
|
||||
background: #0174F6;
|
||||
border-radius: 24rpx 24rpx 24rpx 24rpx;
|
||||
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 12rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx -8rpx 16rpx 0rpx rgba(10, 54, 104, 0.1);
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
position: relative;
|
||||
|
||||
.btn {
|
||||
width: 510rpx;
|
||||
height: 76rpx;
|
||||
margin: 0 auto;
|
||||
background: #0174F6;
|
||||
border-radius: 38rpx 38rpx 38rpx 38rpx;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
BIN
static/icons/addImageIcon.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
static/icons/backIcon.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/icons/homeInfo.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
static/icons/homeInfoMore.png
Normal file
After Width: | Height: | Size: 479 B |
BIN
static/icons/homeMenuIcon/dqc.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/icons/homeMenuIcon/menu1.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
static/icons/homeMenuIcon/menu2.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
static/icons/homeMenuIcon/menu3.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
static/icons/homeMenuIcon/menu4.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
static/icons/icon1.png
Normal file
After Width: | Height: | Size: 332 B |
BIN
static/icons/icon2.png
Normal file
After Width: | Height: | Size: 883 B |
BIN
static/icons/icon3.png
Normal file
After Width: | Height: | Size: 873 B |
BIN
static/icons/message-icon1.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
static/icons/my-icon1.png
Normal file
After Width: | Height: | Size: 605 B |
BIN
static/icons/my-icon2.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
static/icons/my-menu-icon1.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/icons/my-menu-icon2.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
static/icons/my-menu-icon3.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/icons/my-menu-icon4.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/icons/my-menu-icon5.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
static/icons/myCar.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/icons/myOrder.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
static/icons/order-icon1.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/icons/order-icon10.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/icons/order-icon11.png
Normal file
After Width: | Height: | Size: 701 B |
BIN
static/icons/order-icon2.png
Normal file
After Width: | Height: | Size: 448 B |
BIN
static/icons/order-icon3.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
static/icons/order-icon4.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
static/icons/order-icon5.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/icons/order-icon6.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/icons/order-icon7.png
Normal file
After Width: | Height: | Size: 410 B |
BIN
static/icons/order-icon8.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/icons/order-icon9.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
static/icons/rateIcon.png
Normal file
After Width: | Height: | Size: 603 B |
BIN
static/icons/success.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
static/icons/tabbar/car-checked.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/icons/tabbar/car.png
Normal file
After Width: | Height: | Size: 997 B |
16
static/icons/tabbar/car.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>01运输中、物流-线性</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="首页修改" transform="translate(-175.000000, -860.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="底部" transform="translate(0.000000, 853.000000)">
|
||||
<g id="Tab-2" transform="translate(125.000000, 0.000000)">
|
||||
<g id="01运输中、物流-线性" transform="translate(50.000000, 7.000000)">
|
||||
<rect id="矩形" opacity="0" x="0" y="0" width="24.9756098" height="24.9756098"></rect>
|
||||
<path d="M23.3560976,13.9707317 L20.4097561,9.54146341 C20.3317073,9.42439024 20.2146341,9.36585366 20.0780488,9.36585366 L17.1707317,9.36585366 L17.1707317,5.46341463 C17.1707317,5.03414634 16.8195122,4.68292683 16.3902439,4.68292683 L2.34146341,4.68292683 C1.91219512,4.68292683 1.56097561,5.03414634 1.56097561,5.46341463 L1.56097561,16.3902439 C1.56097561,16.8195122 1.91219512,17.1707317 2.34146341,17.1707317 L3.12195122,17.1707317 C3.12195122,18.8878049 4.52682927,20.2926829 6.24390244,20.2926829 C7.96097561,20.2926829 9.36585366,18.8878049 9.36585366,17.1707317 L15.6097561,17.1707317 C15.6097561,18.8878049 17.0146341,20.2926829 18.7317073,20.2926829 C20.4487805,20.2926829 21.8536585,18.8878049 21.8536585,17.1707317 L22.6341463,17.1707317 C23.0634146,17.1707317 23.4146341,16.8195122 23.4146341,16.3902439 L23.4146341,14.1853659 C23.4146341,14.1073171 23.395122,14.0292683 23.3560976,13.9707317 Z M6.24390244,18.7317073 C5.38536585,18.7317073 4.68292683,18.0292683 4.68292683,17.1707317 C4.68292683,16.3121951 5.38536585,15.6097561 6.24390244,15.6097561 C7.10243902,15.6097561 7.80487805,16.3121951 7.80487805,17.1707317 C7.80487805,18.0292683 7.10243902,18.7317073 6.24390244,18.7317073 Z M15.6097561,15.6097561 L8.93658537,15.6097561 C8.3902439,14.6731707 7.39512195,14.0487805 6.24390244,14.0487805 C5.09268293,14.0487805 4.07804878,14.6731707 3.55121951,15.6097561 L3.12195122,15.6097561 L3.12195122,6.24390244 L15.6097561,6.24390244 L15.6097561,15.6097561 Z M18.7317073,18.7317073 C17.8731707,18.7317073 17.1707317,18.0292683 17.1707317,17.1707317 C17.1707317,16.3121951 17.8731707,15.6097561 18.7317073,15.6097561 C19.5902439,15.6097561 20.2926829,16.3121951 20.2926829,17.1707317 C20.2926829,18.0292683 19.5902439,18.7317073 18.7317073,18.7317073 Z M21.8536585,15.6097561 L21.4243902,15.6097561 C20.8780488,14.6731707 19.8829268,14.0487805 18.7317073,14.0487805 C18.1658537,14.0487805 17.6390244,14.204878 17.1707317,14.4780488 L17.1707317,10.9268293 L19.4926829,10.9268293 C19.6292683,10.9268293 19.7463415,10.9853659 19.804878,11.102439 L21.7756098,13.9512195 C21.8146341,14.0097561 21.8536585,14.0878049 21.8536585,14.1658537 L21.8536585,15.6097561 Z" id="形状"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
BIN
static/icons/tabbar/home-checked.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
14
static/icons/tabbar/home-checked.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>204首页</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="首页修改" transform="translate(-50.000000, -860.000000)" fill="#327DFB" fill-rule="nonzero">
|
||||
<g id="底部" transform="translate(0.000000, 853.000000)">
|
||||
<g id="204首页" transform="translate(50.000000, 7.000000)">
|
||||
<rect id="矩形" opacity="0" x="0" y="0" width="25" height="25"></rect>
|
||||
<path d="M22.4414063,10.234375 L12.96875,3.45703125 C12.6953125,3.26171875 12.3242188,3.26171875 12.0703125,3.45703125 L2.5390625,10.234375 C2.2265625,10.4492188 2.3828125,10.9375 2.7734375,10.9375 L4.6875,10.9375 L4.6875,21.484375 C4.6875,21.6992188 4.86328125,21.875 5.078125,21.875 L9.765625,21.875 C9.98046875,21.875 10.15625,21.6992188 10.15625,21.484375 L10.15625,15.625 L14.84375,15.625 L14.84375,21.484375 C14.84375,21.6992188 15.0195313,21.875 15.234375,21.875 L19.921875,21.875 C20.1367188,21.875 20.3125,21.6992188 20.3125,21.484375 L20.3125,10.9375 L22.2265625,10.9375 C22.5976563,10.9375 22.7539063,10.4492188 22.4414063,10.234375 Z" id="路径"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/icons/tabbar/home.png
Normal file
After Width: | Height: | Size: 806 B |
BIN
static/icons/tabbar/my-checked.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/icons/tabbar/my.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
16
static/icons/tabbar/my.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>个人</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="首页修改" transform="translate(-300.000000, -860.000000)" fill="#444444" fill-rule="nonzero">
|
||||
<g id="底部" transform="translate(0.000000, 853.000000)">
|
||||
<g id="Tab-3" transform="translate(250.000000, 0.000000)">
|
||||
<g id="个人" transform="translate(50.000000, 7.000000)">
|
||||
<rect id="矩形" opacity="0" x="0" y="0" width="24.9756098" height="24.9756098"></rect>
|
||||
<path d="M12.4878049,5.46341463 C11.1940683,5.46341463 10.1463415,6.51239024 10.1463415,7.80487805 L10.1463415,8.8451122 C10.1463415,10.1382667 11.1946503,11.1865756 12.4878049,11.1865756 C13.7809594,11.1865756 14.8292683,10.1382667 14.8292683,8.8451122 L14.8292683,7.80487805 C14.8292683,6.51114146 13.7802927,5.46341463 12.4878049,5.46341463 Z M15.1976585,11.6536195 C18.4090225,12.8004939 20.5526302,15.8424372 20.5524293,19.2524488 C20.5524293,20.2577171 19.7369756,21.0731707 18.7317073,21.0731707 L6.24390244,21.0731707 C5.23834547,21.0731707 4.42318049,20.2580057 4.42318049,19.2524488 C4.42297956,15.8424372 6.56658728,12.8004939 9.77795122,11.6536195 C9.01465278,10.9188471 8.58396957,9.90459938 8.58536585,8.8451122 L8.58536585,7.80487805 C8.58536585,5.64962049 10.3325473,3.90243902 12.4878049,3.90243902 C14.6430624,3.90243902 16.3902439,5.64962049 16.3902439,7.80487805 L16.3902439,8.8451122 C16.3902439,9.94778537 15.9331902,10.9430634 15.1976585,11.6536195 L15.1976585,11.6536195 Z M12.4878049,12.7475512 C10.7627136,12.7475512 9.1082958,13.4329265 7.88858916,14.6528673 C6.66888251,15.8728082 5.98382486,17.5273575 5.98415598,19.2524488 C5.98415598,19.3960585 6.10029268,19.5121951 6.24390244,19.5121951 L18.7317073,19.5121951 C18.8751613,19.5121951 18.9914538,19.3959027 18.9914538,19.2524488 C18.9917849,17.5273575 18.3067272,15.8728082 17.0870206,14.6528673 C15.867314,13.4329265 14.2128962,12.7475512 12.4878049,12.7475512 Z" id="形状"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
BIN
static/icons/tabbar/order-checked.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/icons/tabbar/order.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/images/avatar.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
static/images/image1.png
Normal file
After Width: | Height: | Size: 156 KiB |
BIN
static/images/image2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
static/images/image3.png
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
static/images/profile.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
8
store/getters.js
Normal file
@ -0,0 +1,8 @@
|
||||
const getters = {
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name,
|
||||
roles: state => state.user.roles,
|
||||
permissions: state => state.user.permissions
|
||||
}
|
||||
export default getters
|
15
store/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import user from '@/store/modules/user'
|
||||
import getters from './getters'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
user
|
||||
},
|
||||
getters
|
||||
})
|
||||
|
||||
export default store
|
98
store/modules/user.js
Normal file
@ -0,0 +1,98 @@
|
||||
import config from '@/config'
|
||||
import storage from '@/utils/storage'
|
||||
import constant from '@/utils/constant'
|
||||
import { login, logout, getInfo } from '@/api/login'
|
||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||
|
||||
const baseUrl = config.baseUrl
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: getToken(),
|
||||
name: storage.get(constant.name),
|
||||
avatar: storage.get(constant.avatar),
|
||||
roles: storage.get(constant.roles),
|
||||
permissions: storage.get(constant.permissions)
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
storage.set(constant.name, name)
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
storage.set(constant.avatar, avatar)
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
storage.set(constant.roles, roles)
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
storage.set(constant.permissions, permissions)
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 登录
|
||||
Login({ commit }, userInfo) {
|
||||
const username = userInfo.username.trim()
|
||||
const password = userInfo.password
|
||||
const code = userInfo.code
|
||||
const uuid = userInfo.uuid
|
||||
return new Promise((resolve, reject) => {
|
||||
login(username, password, code, uuid).then(res => {
|
||||
setToken(res.token)
|
||||
commit('SET_TOKEN', res.token)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(res => {
|
||||
const user = res.user
|
||||
const avatar = (user == null || user.avatar == "" || user.avatar == null) ? require("@/static/images/profile.jpg") : baseUrl + user.avatar
|
||||
const username = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName
|
||||
if (res.roles && res.roles.length > 0) {
|
||||
commit('SET_ROLES', res.roles)
|
||||
commit('SET_PERMISSIONS', res.permissions)
|
||||
} else {
|
||||
commit('SET_ROLES', ['ROLE_DEFAULT'])
|
||||
}
|
||||
commit('SET_NAME', username)
|
||||
commit('SET_AVATAR', avatar)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 退出系统
|
||||
LogOut({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout(state.token).then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
removeToken()
|
||||
storage.clean()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default user
|
10
uni.promisify.adaptor.js
Normal file
@ -0,0 +1,10 @@
|
||||
uni.addInterceptor({
|
||||
returnValue (res) {
|
||||
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
|
||||
return res;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
res.then((res) => res[0] ? reject(res[0]) : resolve(res[1]));
|
||||
});
|
||||
},
|
||||
});
|
76
uni.scss
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color:#333;//基本色
|
||||
$uni-text-color-inverse:#fff;//反色
|
||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable:#c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color:#ffffff;
|
||||
$uni-bg-color-grey:#f8f8f8;
|
||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color:#c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm:12px;
|
||||
$uni-font-size-base:14px;
|
||||
$uni-font-size-lg:16px;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm:20px;
|
||||
$uni-img-size-base:26px;
|
||||
$uni-img-size-lg:40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2C405A; // 文章标题颜色
|
||||
$uni-font-size-title:20px;
|
||||
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||
$uni-font-size-subtitle:26px;
|
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||
$uni-font-size-paragraph:15px;
|
81
uni_modules/uni-file-picker/changelog.md
Normal file
@ -0,0 +1,81 @@
|
||||
## 1.0.11(2024-07-19)
|
||||
- 修复 vue3 使用value报错的bug
|
||||
## 1.0.10(2024-07-09)
|
||||
- 优化 vue3兼容性
|
||||
## 1.0.9(2024-07-09)
|
||||
- 修复 value 属性不兼容vue3的bug
|
||||
## 1.0.8(2024-03-20)
|
||||
- 补充 删除文件时返回文件下标
|
||||
## 1.0.7(2024-02-21)
|
||||
- 新增 微信小程序选择视频时改用chooseMedia,并返回视频缩略图
|
||||
## 1.0.6(2024-01-06)
|
||||
- 新增 微信小程序不再调用chooseImage,而是调用chooseMedia
|
||||
## 1.0.5(2024-01-03)
|
||||
- 新增 上传文件至云存储携带本地文件名称
|
||||
## 1.0.4(2023-03-29)
|
||||
- 修复 手动上传删除一个文件后不能再上传的bug
|
||||
## 1.0.3(2022-12-19)
|
||||
- 新增 sourceType 属性, 可以自定义图片和视频选择的来源
|
||||
## 1.0.2(2022-07-04)
|
||||
- 修复 在uni-forms下样式不生效的bug
|
||||
## 1.0.1(2021-11-23)
|
||||
- 修复 参数为对象的情况下,url在某些情况显示错误的bug
|
||||
## 1.0.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
|
||||
## 0.2.16(2021-11-08)
|
||||
- 修复 传入空对象 ,显示错误的Bug
|
||||
## 0.2.15(2021-08-30)
|
||||
- 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug
|
||||
## 0.2.14(2021-08-23)
|
||||
- 新增 参数中返回 fileID 字段
|
||||
## 0.2.13(2021-08-23)
|
||||
- 修复 腾讯云传入fileID 不能回显的bug
|
||||
- 修复 选择图片后,不能放大的问题
|
||||
## 0.2.12(2021-08-17)
|
||||
- 修复 由于 0.2.11 版本引起的不能回显图片的Bug
|
||||
## 0.2.11(2021-08-16)
|
||||
- 新增 clearFiles(index) 方法,可以手动删除指定文件
|
||||
- 修复 v-model 值设为 null 报错的Bug
|
||||
## 0.2.10(2021-08-13)
|
||||
- 修复 return-type="object" 时,无法删除文件的Bug
|
||||
## 0.2.9(2021-08-03)
|
||||
- 修复 auto-upload 属性失效的Bug
|
||||
## 0.2.8(2021-07-31)
|
||||
- 修复 fileExtname属性不指定值报错的Bug
|
||||
## 0.2.7(2021-07-31)
|
||||
- 修复 在某种场景下图片不回显的Bug
|
||||
## 0.2.6(2021-07-30)
|
||||
- 修复 return-type为object下,返回值不正确的Bug
|
||||
## 0.2.5(2021-07-30)
|
||||
- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题
|
||||
## 0.2.3(2021-07-28)
|
||||
- 优化 调整示例代码
|
||||
## 0.2.2(2021-07-27)
|
||||
- 修复 vue3 下赋值错误的Bug
|
||||
- 优化 h5平台下上传文件导致页面卡死的问题
|
||||
## 0.2.0(2021-07-13)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 0.1.1(2021-07-02)
|
||||
- 修复 sourceType 缺少默认值导致 ios 无法选择文件
|
||||
## 0.1.0(2021-06-30)
|
||||
- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改
|
||||
## 0.0.11(2021-06-30)
|
||||
- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题
|
||||
## 0.0.10(2021-06-29)
|
||||
- 优化 文件上传后进度条消失时机
|
||||
## 0.0.9(2021-06-29)
|
||||
- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug
|
||||
## 0.0.8(2021-06-15)
|
||||
- 修复 删除文件时无法触发 v-model 的Bug
|
||||
## 0.0.7(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 0.0.6(2021-04-09)
|
||||
- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
|
||||
## 0.0.5(2021-04-09)
|
||||
- 优化 更新组件示例
|
||||
## 0.0.4(2021-04-09)
|
||||
- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
|
||||
## 0.0.3(2021-02-05)
|
||||
- 调整为uni_modules目录规范
|
||||
- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug
|
@ -0,0 +1,287 @@
|
||||
'use strict';
|
||||
|
||||
const ERR_MSG_OK = 'chooseAndUploadFile:ok';
|
||||
const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
|
||||
|
||||
function chooseImage(opts) {
|
||||
const {
|
||||
count,
|
||||
sizeType = ['original', 'compressed'],
|
||||
sourceType,
|
||||
extension
|
||||
} = opts
|
||||
return new Promise((resolve, reject) => {
|
||||
// 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.chooseMedia({
|
||||
count,
|
||||
sizeType,
|
||||
sourceType,
|
||||
mediaType: ['image'],
|
||||
extension,
|
||||
success(res) {
|
||||
res.tempFiles.forEach(item => {
|
||||
item.path = item.tempFilePath;
|
||||
})
|
||||
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
|
||||
},
|
||||
fail(res) {
|
||||
reject({
|
||||
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
|
||||
});
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.chooseImage({
|
||||
count,
|
||||
sizeType,
|
||||
sourceType,
|
||||
extension,
|
||||
success(res) {
|
||||
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
|
||||
},
|
||||
fail(res) {
|
||||
reject({
|
||||
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
|
||||
});
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function chooseVideo(opts) {
|
||||
const {
|
||||
count,
|
||||
camera,
|
||||
compressed,
|
||||
maxDuration,
|
||||
sourceType,
|
||||
extension
|
||||
} = opts;
|
||||
return new Promise((resolve, reject) => {
|
||||
// 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.chooseMedia({
|
||||
count,
|
||||
compressed,
|
||||
maxDuration,
|
||||
sourceType,
|
||||
extension,
|
||||
mediaType: ['video'],
|
||||
success(res) {
|
||||
const {
|
||||
tempFiles,
|
||||
} = res;
|
||||
resolve(normalizeChooseAndUploadFileRes({
|
||||
errMsg: 'chooseVideo:ok',
|
||||
tempFiles: tempFiles.map(item => {
|
||||
return {
|
||||
name: item.name || '',
|
||||
path: item.tempFilePath,
|
||||
thumbTempFilePath: item.thumbTempFilePath,
|
||||
size:item.size,
|
||||
type: (res.tempFile && res.tempFile.type) || '',
|
||||
width:item.width,
|
||||
height:item.height,
|
||||
duration:item.duration,
|
||||
fileType: 'video',
|
||||
cloudPath: '',
|
||||
}
|
||||
}),
|
||||
}, 'video'));
|
||||
},
|
||||
fail(res) {
|
||||
reject({
|
||||
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
|
||||
});
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.chooseVideo({
|
||||
camera,
|
||||
compressed,
|
||||
maxDuration,
|
||||
sourceType,
|
||||
extension,
|
||||
success(res) {
|
||||
const {
|
||||
tempFilePath,
|
||||
duration,
|
||||
size,
|
||||
height,
|
||||
width
|
||||
} = res;
|
||||
resolve(normalizeChooseAndUploadFileRes({
|
||||
errMsg: 'chooseVideo:ok',
|
||||
tempFilePaths: [tempFilePath],
|
||||
tempFiles: [{
|
||||
name: (res.tempFile && res.tempFile.name) || '',
|
||||
path: tempFilePath,
|
||||
size,
|
||||
type: (res.tempFile && res.tempFile.type) || '',
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
fileType: 'video',
|
||||
cloudPath: '',
|
||||
}, ],
|
||||
}, 'video'));
|
||||
},
|
||||
fail(res) {
|
||||
reject({
|
||||
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
|
||||
});
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
}
|
||||
|
||||
function chooseAll(opts) {
|
||||
const {
|
||||
count,
|
||||
extension
|
||||
} = opts;
|
||||
return new Promise((resolve, reject) => {
|
||||
let chooseFile = uni.chooseFile;
|
||||
if (typeof wx !== 'undefined' &&
|
||||
typeof wx.chooseMessageFile === 'function') {
|
||||
chooseFile = wx.chooseMessageFile;
|
||||
}
|
||||
if (typeof chooseFile !== 'function') {
|
||||
return reject({
|
||||
errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
|
||||
});
|
||||
}
|
||||
chooseFile({
|
||||
type: 'all',
|
||||
count,
|
||||
extension,
|
||||
success(res) {
|
||||
resolve(normalizeChooseAndUploadFileRes(res));
|
||||
},
|
||||
fail(res) {
|
||||
reject({
|
||||
errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeChooseAndUploadFileRes(res, fileType) {
|
||||
res.tempFiles.forEach((item, index) => {
|
||||
if (!item.name) {
|
||||
item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
|
||||
}
|
||||
if (fileType) {
|
||||
item.fileType = fileType;
|
||||
}
|
||||
item.cloudPath =
|
||||
Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
|
||||
});
|
||||
if (!res.tempFilePaths) {
|
||||
res.tempFilePaths = res.tempFiles.map((file) => file.path);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function uploadCloudFiles(files, max = 5, onUploadProgress) {
|
||||
files = JSON.parse(JSON.stringify(files))
|
||||
const len = files.length
|
||||
let count = 0
|
||||
let self = this
|
||||
return new Promise(resolve => {
|
||||
while (count < max) {
|
||||
next()
|
||||
}
|
||||
|
||||
function next() {
|
||||
let cur = count++
|
||||
if (cur >= len) {
|
||||
!files.find(item => !item.url && !item.errMsg) && resolve(files)
|
||||
return
|
||||
}
|
||||
const fileItem = files[cur]
|
||||
const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
|
||||
fileItem.url = ''
|
||||
delete fileItem.errMsg
|
||||
|
||||
uniCloud
|
||||
.uploadFile({
|
||||
filePath: fileItem.path,
|
||||
cloudPath: fileItem.cloudPath,
|
||||
fileType: fileItem.fileType,
|
||||
onUploadProgress: res => {
|
||||
res.index = index
|
||||
onUploadProgress && onUploadProgress(res)
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
fileItem.url = res.fileID
|
||||
fileItem.index = index
|
||||
if (cur < len) {
|
||||
next()
|
||||
}
|
||||
})
|
||||
.catch(res => {
|
||||
fileItem.errMsg = res.errMsg || res.message
|
||||
fileItem.index = index
|
||||
if (cur < len) {
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function uploadFiles(choosePromise, {
|
||||
onChooseFile,
|
||||
onUploadProgress
|
||||
}) {
|
||||
return choosePromise
|
||||
.then((res) => {
|
||||
if (onChooseFile) {
|
||||
const customChooseRes = onChooseFile(res);
|
||||
if (typeof customChooseRes !== 'undefined') {
|
||||
return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ?
|
||||
res : chooseRes);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.then((res) => {
|
||||
if (res === false) {
|
||||
return {
|
||||
errMsg: ERR_MSG_OK,
|
||||
tempFilePaths: [],
|
||||
tempFiles: [],
|
||||
};
|
||||
}
|
||||
return res
|
||||
})
|
||||
}
|
||||
|
||||
function chooseAndUploadFile(opts = {
|
||||
type: 'all'
|
||||
}) {
|
||||
if (opts.type === 'image') {
|
||||
return uploadFiles(chooseImage(opts), opts);
|
||||
} else if (opts.type === 'video') {
|
||||
return uploadFiles(chooseVideo(opts), opts);
|
||||
}
|
||||
return uploadFiles(chooseAll(opts), opts);
|
||||
}
|
||||
|
||||
export {
|
||||
chooseAndUploadFile,
|
||||
uploadCloudFiles
|
||||
};
|
@ -0,0 +1,668 @@
|
||||
<template>
|
||||
<view class="uni-file-picker">
|
||||
<view v-if="title" class="uni-file-picker__header">
|
||||
<text class="file-title">{{ title }}</text>
|
||||
<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
|
||||
</view>
|
||||
<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly"
|
||||
:image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview"
|
||||
:delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
|
||||
<slot>
|
||||
<view class="is-add">
|
||||
<view class="icon-add"></view>
|
||||
<view class="icon-add rotate"></view>
|
||||
</view>
|
||||
</slot>
|
||||
</upload-image>
|
||||
<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly"
|
||||
:list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon"
|
||||
@uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
|
||||
<slot><button type="primary" size="mini">选择文件</button></slot>
|
||||
</upload-file>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
chooseAndUploadFile,
|
||||
uploadCloudFiles
|
||||
} from './choose-and-upload-file.js'
|
||||
import {
|
||||
get_file_ext,
|
||||
get_extname,
|
||||
get_files_and_is_max,
|
||||
get_file_info,
|
||||
get_file_data
|
||||
} from './utils.js'
|
||||
import uploadImage from './upload-image.vue'
|
||||
import uploadFile from './upload-file.vue'
|
||||
let fileInput = null
|
||||
/**
|
||||
* FilePicker 文件选择上传
|
||||
* @description 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=4079
|
||||
* @property {Object|Array} value 组件数据,通常用来回显 ,类型由return-type属性决定
|
||||
* @property {Boolean} disabled = [true|false] 组件禁用
|
||||
* @value true 禁用
|
||||
* @value false 取消禁用
|
||||
* @property {Boolean} readonly = [true|false] 组件只读,不可选择,不显示进度,不显示删除按钮
|
||||
* @value true 只读
|
||||
* @value false 取消只读
|
||||
* @property {String} return-type = [array|object] 限制 value 格式,当为 object 时 ,组件只能单选,且会覆盖
|
||||
* @value array 规定 value 属性的类型为数组
|
||||
* @value object 规定 value 属性的类型为对象
|
||||
* @property {Boolean} disable-preview = [true|false] 禁用图片预览,仅 mode:grid 时生效
|
||||
* @value true 禁用图片预览
|
||||
* @value false 取消禁用图片预览
|
||||
* @property {Boolean} del-icon = [true|false] 是否显示删除按钮
|
||||
* @value true 显示删除按钮
|
||||
* @value false 不显示删除按钮
|
||||
* @property {Boolean} auto-upload = [true|false] 是否自动上传,值为true则只触发@select,可自行上传
|
||||
* @value true 自动上传
|
||||
* @value false 取消自动上传
|
||||
* @property {Number|String} limit 最大选择个数 ,h5 会自动忽略多选的部分
|
||||
* @property {String} title 组件标题,右侧显示上传计数
|
||||
* @property {String} mode = [list|grid] 选择文件后的文件列表样式
|
||||
* @value list 列表显示
|
||||
* @value grid 宫格显示
|
||||
* @property {String} file-mediatype = [image|video|all] 选择文件类型
|
||||
* @value image 只选择图片
|
||||
* @value video 只选择视频
|
||||
* @value all 选择所有文件
|
||||
* @property {Array} file-extname 选择文件后缀,根据 file-mediatype 属性而不同
|
||||
* @property {Object} list-style mode:list 时的样式
|
||||
* @property {Object} image-styles 选择文件后缀,根据 file-mediatype 属性而不同
|
||||
* @event {Function} select 选择文件后触发
|
||||
* @event {Function} progress 文件上传时触发
|
||||
* @event {Function} success 上传成功触发
|
||||
* @event {Function} fail 上传失败触发
|
||||
* @event {Function} delete 文件从列表移除时触发
|
||||
*/
|
||||
export default {
|
||||
name: 'uniFilePicker',
|
||||
components: {
|
||||
uploadImage,
|
||||
uploadFile
|
||||
},
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
|
||||
props: {
|
||||
modelValue: {
|
||||
type: [Array, Object],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: [Array, Object],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disablePreview: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
delIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 自动上传
|
||||
autoUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 最大选择个数 ,h5只能限制单选或是多选
|
||||
limit: {
|
||||
type: [Number, String],
|
||||
default: 9
|
||||
},
|
||||
// 列表样式 grid | list | list-card
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'grid'
|
||||
},
|
||||
// 选择文件类型 image/video/all
|
||||
fileMediatype: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
},
|
||||
// 文件类型筛选
|
||||
fileExtname: {
|
||||
type: [Array, String],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
listStyles: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
// 是否显示边框
|
||||
border: true,
|
||||
// 是否显示分隔线
|
||||
dividline: true,
|
||||
// 线条样式
|
||||
borderStyle: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
imageStyles: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
width: 'auto',
|
||||
height: 'auto'
|
||||
}
|
||||
}
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
returnType: {
|
||||
type: String,
|
||||
default: 'array'
|
||||
},
|
||||
sizeType: {
|
||||
type: Array,
|
||||
default () {
|
||||
return ['original', 'compressed']
|
||||
}
|
||||
},
|
||||
sourceType: {
|
||||
type: Array,
|
||||
default () {
|
||||
return ['album', 'camera']
|
||||
}
|
||||
},
|
||||
provider: {
|
||||
type: String,
|
||||
default: '' // 默认上传到 unicloud 内置存储 extStorage 扩展存储
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
files: [],
|
||||
localValue: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal, oldVal) {
|
||||
this.setValue(newVal, oldVal)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
modelValue: {
|
||||
handler(newVal, oldVal) {
|
||||
this.setValue(newVal, oldVal)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
filesList() {
|
||||
let files = []
|
||||
this.files.forEach(v => {
|
||||
files.push(v)
|
||||
})
|
||||
return files
|
||||
},
|
||||
showType() {
|
||||
if (this.fileMediatype === 'image') {
|
||||
return this.mode
|
||||
}
|
||||
return 'list'
|
||||
},
|
||||
limitLength() {
|
||||
if (this.returnType === 'object') {
|
||||
return 1
|
||||
}
|
||||
if (!this.limit) {
|
||||
return 1
|
||||
}
|
||||
if (this.limit >= 9) {
|
||||
return 9
|
||||
}
|
||||
return this.limit
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// TODO 兼容不开通服务空间的情况
|
||||
if (!(uniCloud.config && uniCloud.config.provider)) {
|
||||
this.noSpace = true
|
||||
uniCloud.chooseAndUploadFile = chooseAndUploadFile
|
||||
}
|
||||
this.form = this.getForm('uniForms')
|
||||
this.formItem = this.getForm('uniFormsItem')
|
||||
if (this.form && this.formItem) {
|
||||
if (this.formItem.name) {
|
||||
this.rename = this.formItem.name
|
||||
this.form.inputChildrens.push(this)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 公开用户使用,清空文件
|
||||
* @param {Object} index
|
||||
*/
|
||||
clearFiles(index) {
|
||||
if (index !== 0 && !index) {
|
||||
this.files = []
|
||||
this.$nextTick(() => {
|
||||
this.setEmit()
|
||||
})
|
||||
} else {
|
||||
this.files.splice(index, 1)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.setEmit()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 公开用户使用,继续上传
|
||||
*/
|
||||
upload() {
|
||||
let files = []
|
||||
this.files.forEach((v, index) => {
|
||||
if (v.status === 'ready' || v.status === 'error') {
|
||||
files.push(Object.assign({}, v))
|
||||
}
|
||||
})
|
||||
return this.uploadFiles(files)
|
||||
},
|
||||
async setValue(newVal, oldVal) {
|
||||
const newData = async (v) => {
|
||||
const reg = /cloud:\/\/([\w.]+\/?)\S*/
|
||||
let url = ''
|
||||
if(v.fileID){
|
||||
url = v.fileID
|
||||
}else{
|
||||
url = v.url
|
||||
}
|
||||
if (reg.test(url)) {
|
||||
v.fileID = url
|
||||
v.url = await this.getTempFileURL(url)
|
||||
}
|
||||
if(v.url) v.path = v.url
|
||||
return v
|
||||
}
|
||||
if (this.returnType === 'object') {
|
||||
if (newVal) {
|
||||
await newData(newVal)
|
||||
} else {
|
||||
newVal = {}
|
||||
}
|
||||
} else {
|
||||
if (!newVal) newVal = []
|
||||
for(let i =0 ;i < newVal.length ;i++){
|
||||
let v = newVal[i]
|
||||
await newData(v)
|
||||
}
|
||||
}
|
||||
this.localValue = newVal
|
||||
if (this.form && this.formItem &&!this.is_reset) {
|
||||
this.is_reset = false
|
||||
this.formItem.setValue(this.localValue)
|
||||
}
|
||||
let filesData = Object.keys(newVal).length > 0 ? newVal : [];
|
||||
this.files = [].concat(filesData)
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择文件
|
||||
*/
|
||||
choose() {
|
||||
if (this.disabled) return
|
||||
if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType ===
|
||||
'array') {
|
||||
uni.showToast({
|
||||
title: `您最多选择 ${this.limitLength} 个文件`,
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.chooseFiles()
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择文件并上传
|
||||
*/
|
||||
chooseFiles() {
|
||||
const _extname = get_extname(this.fileExtname)
|
||||
// 获取后缀
|
||||
uniCloud
|
||||
.chooseAndUploadFile({
|
||||
type: this.fileMediatype,
|
||||
compressed: false,
|
||||
sizeType: this.sizeType,
|
||||
sourceType: this.sourceType,
|
||||
// TODO 如果为空,video 有问题
|
||||
extension: _extname.length > 0 ? _extname : undefined,
|
||||
count: this.limitLength - this.files.length, //默认9
|
||||
onChooseFile: this.chooseFileCallback,
|
||||
onUploadProgress: progressEvent => {
|
||||
this.setProgress(progressEvent, progressEvent.index)
|
||||
}
|
||||
})
|
||||
.then(result => {
|
||||
this.setSuccessAndError(result.tempFiles)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('选择失败', err)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择文件回调
|
||||
* @param {Object} res
|
||||
*/
|
||||
async chooseFileCallback(res) {
|
||||
const _extname = get_extname(this.fileExtname)
|
||||
const is_one = (Number(this.limitLength) === 1 &&
|
||||
this.disablePreview &&
|
||||
!this.disabled) ||
|
||||
this.returnType === 'object'
|
||||
// 如果这有一个文件 ,需要清空本地缓存数据
|
||||
if (is_one) {
|
||||
this.files = []
|
||||
}
|
||||
|
||||
let {
|
||||
filePaths,
|
||||
files
|
||||
} = get_files_and_is_max(res, _extname)
|
||||
if (!(_extname && _extname.length > 0)) {
|
||||
filePaths = res.tempFilePaths
|
||||
files = res.tempFiles
|
||||
}
|
||||
|
||||
let currentData = []
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (this.limitLength - this.files.length <= 0) break
|
||||
files[i].uuid = Date.now()
|
||||
let filedata = await get_file_data(files[i], this.fileMediatype)
|
||||
filedata.progress = 0
|
||||
filedata.status = 'ready'
|
||||
this.files.push(filedata)
|
||||
currentData.push({
|
||||
...filedata,
|
||||
file: files[i]
|
||||
})
|
||||
}
|
||||
this.$emit('select', {
|
||||
tempFiles: currentData,
|
||||
tempFilePaths: filePaths
|
||||
})
|
||||
res.tempFiles = files
|
||||
// 停止自动上传
|
||||
if (!this.autoUpload || this.noSpace) {
|
||||
res.tempFiles = []
|
||||
}
|
||||
res.tempFiles.forEach((fileItem, index) => {
|
||||
this.provider && (fileItem.provider = this.provider);
|
||||
const fileNameSplit = fileItem.name.split('.')
|
||||
const ext = fileNameSplit.pop()
|
||||
const fileName = fileNameSplit.join('.').replace(/[\s\/\?<>\\:\*\|":]/g, '_')
|
||||
fileItem.cloudPath = fileName + '_' + Date.now() + '_' + index + '.' + ext
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 批传
|
||||
* @param {Object} e
|
||||
*/
|
||||
uploadFiles(files) {
|
||||
files = [].concat(files)
|
||||
return uploadCloudFiles.call(this, files, 5, res => {
|
||||
this.setProgress(res, res.index, true)
|
||||
})
|
||||
.then(result => {
|
||||
this.setSuccessAndError(result)
|
||||
return result;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 成功或失败
|
||||
*/
|
||||
async setSuccessAndError(res, fn) {
|
||||
let successData = []
|
||||
let errorData = []
|
||||
let tempFilePath = []
|
||||
let errorTempFilePath = []
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
const item = res[i]
|
||||
const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index
|
||||
|
||||
if (index === -1 || !this.files) break
|
||||
if (item.errMsg === 'request:fail') {
|
||||
this.files[index].url = item.path
|
||||
this.files[index].status = 'error'
|
||||
this.files[index].errMsg = item.errMsg
|
||||
// this.files[index].progress = -1
|
||||
errorData.push(this.files[index])
|
||||
errorTempFilePath.push(this.files[index].url)
|
||||
} else {
|
||||
this.files[index].errMsg = ''
|
||||
this.files[index].fileID = item.url
|
||||
const reg = /cloud:\/\/([\w.]+\/?)\S*/
|
||||
if (reg.test(item.url)) {
|
||||
this.files[index].url = await this.getTempFileURL(item.url)
|
||||
}else{
|
||||
this.files[index].url = item.url
|
||||
}
|
||||
|
||||
this.files[index].status = 'success'
|
||||
this.files[index].progress += 1
|
||||
successData.push(this.files[index])
|
||||
tempFilePath.push(this.files[index].fileID)
|
||||
}
|
||||
}
|
||||
|
||||
if (successData.length > 0) {
|
||||
this.setEmit()
|
||||
// 状态改变返回
|
||||
this.$emit('success', {
|
||||
tempFiles: this.backObject(successData),
|
||||
tempFilePaths: tempFilePath
|
||||
})
|
||||
}
|
||||
|
||||
if (errorData.length > 0) {
|
||||
this.$emit('fail', {
|
||||
tempFiles: this.backObject(errorData),
|
||||
tempFilePaths: errorTempFilePath
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取进度
|
||||
* @param {Object} progressEvent
|
||||
* @param {Object} index
|
||||
* @param {Object} type
|
||||
*/
|
||||
setProgress(progressEvent, index, type) {
|
||||
const fileLenth = this.files.length
|
||||
const percentNum = (index / fileLenth) * 100
|
||||
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
|
||||
let idx = index
|
||||
if (!type) {
|
||||
idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid)
|
||||
}
|
||||
if (idx === -1 || !this.files[idx]) return
|
||||
// fix by mehaotian 100 就会消失,-1 是为了让进度条消失
|
||||
this.files[idx].progress = percentCompleted - 1
|
||||
// 上传中
|
||||
this.$emit('progress', {
|
||||
index: idx,
|
||||
progress: parseInt(percentCompleted),
|
||||
tempFile: this.files[idx]
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param {Object} index
|
||||
*/
|
||||
delFile(index) {
|
||||
this.$emit('delete', {
|
||||
index,
|
||||
tempFile: this.files[index],
|
||||
tempFilePath: this.files[index].url
|
||||
})
|
||||
this.files.splice(index, 1)
|
||||
this.$nextTick(() => {
|
||||
this.setEmit()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取文件名和后缀
|
||||
* @param {Object} name
|
||||
*/
|
||||
getFileExt(name) {
|
||||
const last_len = name.lastIndexOf('.')
|
||||
const len = name.length
|
||||
return {
|
||||
name: name.substring(0, last_len),
|
||||
ext: name.substring(last_len + 1, len)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理返回事件
|
||||
*/
|
||||
setEmit() {
|
||||
let data = []
|
||||
if (this.returnType === 'object') {
|
||||
data = this.backObject(this.files)[0]
|
||||
this.localValue = data?data:null
|
||||
} else {
|
||||
data = this.backObject(this.files)
|
||||
if (!this.localValue) {
|
||||
this.localValue = []
|
||||
}
|
||||
this.localValue = [...data]
|
||||
}
|
||||
// #ifdef VUE3
|
||||
this.$emit('update:modelValue', this.localValue)
|
||||
// #endif
|
||||
// #ifndef VUE3
|
||||
this.$emit('input', this.localValue)
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理返回参数
|
||||
* @param {Object} files
|
||||
*/
|
||||
backObject(files) {
|
||||
let newFilesData = []
|
||||
files.forEach(v => {
|
||||
newFilesData.push({
|
||||
extname: v.extname,
|
||||
fileType: v.fileType,
|
||||
image: v.image,
|
||||
name: v.name,
|
||||
path: v.path,
|
||||
size: v.size,
|
||||
fileID:v.fileID,
|
||||
url: v.url,
|
||||
// 修改删除一个文件后不能再上传的bug, #694
|
||||
uuid: v.uuid,
|
||||
status: v.status,
|
||||
cloudPath: v.cloudPath
|
||||
})
|
||||
})
|
||||
return newFilesData
|
||||
},
|
||||
async getTempFileURL(fileList) {
|
||||
fileList = {
|
||||
fileList: [].concat(fileList)
|
||||
}
|
||||
const urls = await uniCloud.getTempFileURL(fileList)
|
||||
return urls.fileList[0].tempFileURL || ''
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getForm(name = 'uniForms') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false;
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.uni-file-picker {
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-file-picker__header {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.file-title {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.file-count {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.is-add {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon-add {
|
||||
width: 50px;
|
||||
height: 5px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.rotate {
|
||||
position: absolute;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
</style>
|
@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<view class="uni-file-picker__files">
|
||||
<view v-if="!readonly" class="files-button" @click="choose">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- :class="{'is-text-box':showType === 'list'}" -->
|
||||
<view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle">
|
||||
<!-- ,'is-list-card':showType === 'list-card' -->
|
||||
|
||||
<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
|
||||
'files-border':index !== 0 && styles.dividline}"
|
||||
:style="index !== 0 && styles.dividline &&borderLineStyle">
|
||||
<view class="uni-file-picker__item">
|
||||
<!-- :class="{'is-text-image':showType === 'list'}" -->
|
||||
<!-- <view class="files__image is-text-image">
|
||||
<image class="header-image" :src="item.logo" mode="aspectFit"></image>
|
||||
</view> -->
|
||||
<view class="files__name">{{item.name}}</view>
|
||||
<view v-if="delIcon&&!readonly" class="icon-del-box icon-files" @click="delFile(index)">
|
||||
<view class="icon-del icon-files"></view>
|
||||
<view class="icon-del rotate"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
|
||||
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
|
||||
:backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
|
||||
</view>
|
||||
<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
|
||||
点击重试
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "uploadFile",
|
||||
emits:['uploadFiles','choose','delFile'],
|
||||
props: {
|
||||
filesList: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
delIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
limit: {
|
||||
type: [Number, String],
|
||||
default: 9
|
||||
},
|
||||
showType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
listStyles: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
// 是否显示边框
|
||||
border: true,
|
||||
// 是否显示分隔线
|
||||
dividline: true,
|
||||
// 线条样式
|
||||
borderStyle: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
readonly:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
list() {
|
||||
let files = []
|
||||
this.filesList.forEach(v => {
|
||||
files.push(v)
|
||||
})
|
||||
return files
|
||||
},
|
||||
styles() {
|
||||
let styles = {
|
||||
border: true,
|
||||
dividline: true,
|
||||
'border-style': {}
|
||||
}
|
||||
return Object.assign(styles, this.listStyles)
|
||||
},
|
||||
borderStyle() {
|
||||
let {
|
||||
borderStyle,
|
||||
border
|
||||
} = this.styles
|
||||
let obj = {}
|
||||
if (!border) {
|
||||
obj.border = 'none'
|
||||
} else {
|
||||
let width = (borderStyle && borderStyle.width) || 1
|
||||
width = this.value2px(width)
|
||||
let radius = (borderStyle && borderStyle.radius) || 5
|
||||
radius = this.value2px(radius)
|
||||
obj = {
|
||||
'border-width': width,
|
||||
'border-style': (borderStyle && borderStyle.style) || 'solid',
|
||||
'border-color': (borderStyle && borderStyle.color) || '#eee',
|
||||
'border-radius': radius
|
||||
}
|
||||
}
|
||||
let classles = ''
|
||||
for (let i in obj) {
|
||||
classles += `${i}:${obj[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
borderLineStyle() {
|
||||
let obj = {}
|
||||
let {
|
||||
borderStyle
|
||||
} = this.styles
|
||||
if (borderStyle && borderStyle.color) {
|
||||
obj['border-color'] = borderStyle.color
|
||||
}
|
||||
if (borderStyle && borderStyle.width) {
|
||||
let width = borderStyle && borderStyle.width || 1
|
||||
let style = borderStyle && borderStyle.style || 0
|
||||
if (typeof width === 'number') {
|
||||
width += 'px'
|
||||
} else {
|
||||
width = width.indexOf('px') ? width : width + 'px'
|
||||
}
|
||||
obj['border-width'] = width
|
||||
|
||||
if (typeof style === 'number') {
|
||||
style += 'px'
|
||||
} else {
|
||||
style = style.indexOf('px') ? style : style + 'px'
|
||||
}
|
||||
obj['border-top-style'] = style
|
||||
}
|
||||
let classles = ''
|
||||
for (let i in obj) {
|
||||
classles += `${i}:${obj[i]};`
|
||||
}
|
||||
return classles
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
uploadFiles(item, index) {
|
||||
this.$emit("uploadFiles", {
|
||||
item,
|
||||
index
|
||||
})
|
||||
},
|
||||
choose() {
|
||||
this.$emit("choose")
|
||||
},
|
||||
delFile(index) {
|
||||
this.$emit('delFile', index)
|
||||
},
|
||||
value2px(value) {
|
||||
if (typeof value === 'number') {
|
||||
value += 'px'
|
||||
} else {
|
||||
value = value.indexOf('px') !== -1 ? value : value + 'px'
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.uni-file-picker__files {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.files-button {
|
||||
// border: 1px red solid;
|
||||
}
|
||||
|
||||
.uni-file-picker__lists {
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.file-picker__mask {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.uni-file-picker__lists-box {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-file-picker__item {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
padding: 8px 10px;
|
||||
padding-right: 5px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.files-border {
|
||||
border-top: 1px #eee solid;
|
||||
}
|
||||
|
||||
.files__name {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-right: 25px;
|
||||
/* #ifndef APP-NVUE */
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.icon-files {
|
||||
/* #ifndef APP-NVUE */
|
||||
position: static;
|
||||
background-color: initial;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
// .icon-files .icon-del {
|
||||
// background-color: #333;
|
||||
// width: 12px;
|
||||
// height: 1px;
|
||||
// }
|
||||
|
||||
|
||||
.is-list-card {
|
||||
border: 1px #eee solid;
|
||||
margin-bottom: 5px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.files__image {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.header-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.is-text-box {
|
||||
border: 1px #eee solid;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.is-text-image {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.rotate {
|
||||
position: absolute;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.icon-del-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
margin: auto 0;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 0;
|
||||
right: 5px;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
// border-radius: 50%;
|
||||
// background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.icon-del {
|
||||
width: 15px;
|
||||
height: 1px;
|
||||
background-color: #333;
|
||||
// border-radius: 1px;
|
||||
}
|
||||
|
||||
/* #ifdef H5 */
|
||||
@media all and (min-width: 768px) {
|
||||
.uni-file-picker__files {
|
||||
max-width: 375px;
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
@ -0,0 +1,292 @@
|
||||
<template>
|
||||
<view class="uni-file-picker__container">
|
||||
<view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle">
|
||||
<view class="file-picker__box-content" :style="borderStyle">
|
||||
<image class="file-image" :src="item.url" mode="aspectFill" @click.stop="prviewImage(item,index)"></image>
|
||||
<view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)">
|
||||
<view class="icon-del"></view>
|
||||
<view class="icon-del rotate"></view>
|
||||
</view>
|
||||
<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
|
||||
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
|
||||
:backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
|
||||
</view>
|
||||
<view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
|
||||
点击重试
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle">
|
||||
<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
|
||||
<slot>
|
||||
<view class="icon-add"></view>
|
||||
<view class="icon-add rotate"></view>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "uploadImage",
|
||||
emits:['uploadFiles','choose','delFile'],
|
||||
props: {
|
||||
filesList: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
disabled:{
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disablePreview: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
limit: {
|
||||
type: [Number, String],
|
||||
default: 9
|
||||
},
|
||||
imageStyles: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
border: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
delIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
readonly:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styles() {
|
||||
let styles = {
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
border: {}
|
||||
}
|
||||
return Object.assign(styles, this.imageStyles)
|
||||
},
|
||||
boxStyle() {
|
||||
const {
|
||||
width = 'auto',
|
||||
height = 'auto'
|
||||
} = this.styles
|
||||
let obj = {}
|
||||
if (height === 'auto') {
|
||||
if (width !== 'auto') {
|
||||
obj.height = this.value2px(width)
|
||||
obj['padding-top'] = 0
|
||||
} else {
|
||||
obj.height = 0
|
||||
}
|
||||
} else {
|
||||
obj.height = this.value2px(height)
|
||||
obj['padding-top'] = 0
|
||||
}
|
||||
|
||||
if (width === 'auto') {
|
||||
if (height !== 'auto') {
|
||||
obj.width = this.value2px(height)
|
||||
} else {
|
||||
obj.width = '33.3%'
|
||||
}
|
||||
} else {
|
||||
obj.width = this.value2px(width)
|
||||
}
|
||||
|
||||
let classles = ''
|
||||
for(let i in obj){
|
||||
classles+= `${i}:${obj[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
borderStyle() {
|
||||
let {
|
||||
border
|
||||
} = this.styles
|
||||
let obj = {}
|
||||
const widthDefaultValue = 1
|
||||
const radiusDefaultValue = 3
|
||||
if (typeof border === 'boolean') {
|
||||
obj.border = border ? '1px #eee solid' : 'none'
|
||||
} else {
|
||||
let width = (border && border.width) || widthDefaultValue
|
||||
width = this.value2px(width)
|
||||
let radius = (border && border.radius) || radiusDefaultValue
|
||||
radius = this.value2px(radius)
|
||||
obj = {
|
||||
'border-width': width,
|
||||
'border-style': (border && border.style) || 'solid',
|
||||
'border-color': (border && border.color) || '#eee',
|
||||
'border-radius': radius
|
||||
}
|
||||
}
|
||||
let classles = ''
|
||||
for(let i in obj){
|
||||
classles+= `${i}:${obj[i]};`
|
||||
}
|
||||
return classles
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
uploadFiles(item, index) {
|
||||
this.$emit("uploadFiles", item)
|
||||
},
|
||||
choose() {
|
||||
this.$emit("choose")
|
||||
},
|
||||
delFile(index) {
|
||||
this.$emit('delFile', index)
|
||||
},
|
||||
prviewImage(img, index) {
|
||||
let urls = []
|
||||
if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
|
||||
this.$emit("choose")
|
||||
}
|
||||
if(this.disablePreview) return
|
||||
this.filesList.forEach(i => {
|
||||
urls.push(i.url)
|
||||
})
|
||||
|
||||
uni.previewImage({
|
||||
urls: urls,
|
||||
current: index
|
||||
});
|
||||
},
|
||||
value2px(value) {
|
||||
if (typeof value === 'number') {
|
||||
value += 'px'
|
||||
} else {
|
||||
if (value.indexOf('%') === -1) {
|
||||
value = value.indexOf('px') !== -1 ? value : value + 'px'
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.uni-file-picker__container {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
flex-wrap: wrap;
|
||||
margin: -5px;
|
||||
}
|
||||
|
||||
.file-picker__box {
|
||||
position: relative;
|
||||
// flex: 0 0 33.3%;
|
||||
width: 33.3%;
|
||||
height: 0;
|
||||
padding-top: 33.33%;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.file-picker__box-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: 5px;
|
||||
border: 1px #eee solid;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.file-picker__progress {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* border: 1px red solid; */
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.file-picker__progress-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.file-picker__mask {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.file-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.is-add {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon-add {
|
||||
width: 50px;
|
||||
height: 5px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.rotate {
|
||||
position: absolute;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.icon-del-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.icon-del {
|
||||
width: 15px;
|
||||
height: 2px;
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
110
uni_modules/uni-file-picker/components/uni-file-picker/utils.js
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 获取文件名和后缀
|
||||
* @param {String} name
|
||||
*/
|
||||
export const get_file_ext = (name) => {
|
||||
const last_len = name.lastIndexOf('.')
|
||||
const len = name.length
|
||||
return {
|
||||
name: name.substring(0, last_len),
|
||||
ext: name.substring(last_len + 1, len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展名
|
||||
* @param {Array} fileExtname
|
||||
*/
|
||||
export const get_extname = (fileExtname) => {
|
||||
if (!Array.isArray(fileExtname)) {
|
||||
let extname = fileExtname.replace(/(\[|\])/g, '')
|
||||
return extname.split(',')
|
||||
} else {
|
||||
return fileExtname
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件和检测是否可选
|
||||
*/
|
||||
export const get_files_and_is_max = (res, _extname) => {
|
||||
let filePaths = []
|
||||
let files = []
|
||||
if(!_extname || _extname.length === 0){
|
||||
return {
|
||||
filePaths,
|
||||
files
|
||||
}
|
||||
}
|
||||
res.tempFiles.forEach(v => {
|
||||
let fileFullName = get_file_ext(v.name)
|
||||
const extname = fileFullName.ext.toLowerCase()
|
||||
if (_extname.indexOf(extname) !== -1) {
|
||||
files.push(v)
|
||||
filePaths.push(v.path)
|
||||
}
|
||||
})
|
||||
if (files.length !== res.tempFiles.length) {
|
||||
uni.showToast({
|
||||
title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`,
|
||||
icon: 'none',
|
||||
duration: 5000
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
filePaths,
|
||||
files
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取图片信息
|
||||
* @param {Object} filepath
|
||||
*/
|
||||
export const get_file_info = (filepath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.getImageInfo({
|
||||
src: filepath,
|
||||
success(res) {
|
||||
resolve(res)
|
||||
},
|
||||
fail(err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 获取封装数据
|
||||
*/
|
||||
export const get_file_data = async (files, type = 'image') => {
|
||||
// 最终需要上传数据库的数据
|
||||
let fileFullName = get_file_ext(files.name)
|
||||
const extname = fileFullName.ext.toLowerCase()
|
||||
let filedata = {
|
||||
name: files.name,
|
||||
uuid: files.uuid,
|
||||
extname: extname || '',
|
||||
cloudPath: files.cloudPath,
|
||||
fileType: files.fileType,
|
||||
thumbTempFilePath: files.thumbTempFilePath,
|
||||
url: files.path || files.path,
|
||||
size: files.size, //单位是字节
|
||||
image: {},
|
||||
path: files.path,
|
||||
video: {}
|
||||
}
|
||||
if (type === 'image') {
|
||||
const imageinfo = await get_file_info(files.path)
|
||||
delete filedata.video
|
||||
filedata.image.width = imageinfo.width
|
||||
filedata.image.height = imageinfo.height
|
||||
filedata.image.location = imageinfo.path
|
||||
} else {
|
||||
delete filedata.image
|
||||
}
|
||||
return filedata
|
||||
}
|
84
uni_modules/uni-file-picker/package.json
Normal file
@ -0,0 +1,84 @@
|
||||
{
|
||||
"id": "uni-file-picker",
|
||||
"displayName": "uni-file-picker 文件选择上传",
|
||||
"version": "1.0.11",
|
||||
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"图片上传",
|
||||
"文件上传"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss"],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "n"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
uni_modules/uni-file-picker/readme.md
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
## FilePicker 文件选择上传
|
||||
|
||||
> **组件名:uni-file-picker**
|
||||
> 代码块: `uFilePicker`
|
||||
|
||||
|
||||
文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
42
uni_modules/uni-icons/changelog.md
Normal file
@ -0,0 +1,42 @@
|
||||
## 2.0.10(2024-06-07)
|
||||
- 优化 uni-app x 中,size 属性的类型
|
||||
## 2.0.9(2024-01-12)
|
||||
fix: 修复图标大小默认值错误的问题
|
||||
## 2.0.8(2023-12-14)
|
||||
- 修复 项目未使用 ts 情况下,打包报错的bug
|
||||
## 2.0.7(2023-12-14)
|
||||
- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug
|
||||
## 2.0.6(2023-12-11)
|
||||
- 优化 兼容老版本icon类型,如 top ,bottom 等
|
||||
## 2.0.5(2023-12-11)
|
||||
- 优化 兼容老版本icon类型,如 top ,bottom 等
|
||||
## 2.0.4(2023-12-06)
|
||||
- 优化 uni-app x 下示例项目图标排序
|
||||
## 2.0.3(2023-12-06)
|
||||
- 修复 nvue下引入组件报错的bug
|
||||
## 2.0.2(2023-12-05)
|
||||
-优化 size 属性支持单位
|
||||
## 2.0.1(2023-12-05)
|
||||
- 新增 uni-app x 支持定义图标
|
||||
## 1.3.5(2022-01-24)
|
||||
- 优化 size 属性可以传入不带单位的字符串数值
|
||||
## 1.3.4(2022-01-24)
|
||||
- 优化 size 支持其他单位
|
||||
## 1.3.3(2022-01-17)
|
||||
- 修复 nvue 有些图标不显示的bug,兼容老版本图标
|
||||
## 1.3.2(2021-12-01)
|
||||
- 优化 示例可复制图标名称
|
||||
## 1.3.1(2021-11-23)
|
||||
- 优化 兼容旧组件 type 值
|
||||
## 1.3.0(2021-11-19)
|
||||
- 新增 更多图标
|
||||
- 优化 自定义图标使用方式
|
||||
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
|
||||
## 1.1.7(2021-11-08)
|
||||
## 1.2.0(2021-07-30)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 1.1.5(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 1.1.4(2021-02-05)
|
||||
- 调整为uni_modules目录规范
|