Commit 924930ca authored by wanglongchao's avatar wanglongchao

feat: 首次提交

parents
/*
* Eslint config file
* Documentation: https://eslint.org/docs/user-guide/configuring/
* Install the Eslint extension before using this feature.
*/
module.exports = {
env: {
es6: true,
browser: true,
node: true,
},
ecmaFeatures: {
modules: true,
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
globals: {
wx: true,
App: true,
Page: true,
getCurrentPages: true,
getApp: true,
Component: true,
requirePlugin: true,
requireMiniProgram: true,
},
// extends: 'eslint:recommended',
rules: {},
}
miniprogram_npm
node_modules
\ No newline at end of file
## 安装
### 使用 NPM
小程序已经支持使用 NPM 安装第三方包。
具体使用方式,可以参考小程序官网文档: [《NPM 支持》](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html?search-key=npm)
```bash
npm i tdesign-miniprogram -S --production
```
> 建议使用 NPM,不再推荐“源码拷贝的方式”
## 使用组件
以按钮组件为例,只需要在 `JSON` 文件中引入按钮对应的自定义组件即可
```json
{
"usingComponents": {
"t-button": "tdesign-miniprogram/button/button"
}
}
\ No newline at end of file
const { loginStatus } = require("./utils/common");
App({
onLaunch() {
const TOKEN = wx.getStorageSync('token') == '' ? '' : 'Bearer ' + wx.getStorageSync('token')
this.globalData.token = TOKEN
this.globalData.userId = wx.getStorageSync('userId')
loginStatus(TOKEN.length > 0)
},
globalData:{
token: '',
cateId: 0,
roleType: 0,
userId: 0
}
});
{
"pages": [
"pages/home/home",
"pages/mine/mine",
"pages/service/service",
"pages/service/service-detail",
"pages/address/index",
"pages/address/add-address",
"pages/auth/login",
"pages/order/order-service",
"pages/order/order-result",
"pages/order/order-list",
"pages/order/order-detail",
"pages/mine/user-info",
"pages/mine/change-phone",
"pages/process/choose",
"pages/process/user-list",
"pages/process/dispatch",
"pages/workbench/index",
"pages/workbench/order-list",
"pages/search/index",
"pages/mine/about-us",
"pages/service/service-agreement",
"pages/mine/official-account"
],
"usingComponents": {
"t-popup": "tdesign-miniprogram/popup/popup"
},
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#ffffff",
"backgroundColor": "#f6f6f6",
"navigationBarTitleText": "城市匠人",
"navigationBarTextStyle": "black"
},
"tabBar": {
"color": "#9F9F9F",
"selectedColor": "#437CFD",
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/assets/tabbar/home-unselect.png",
"selectedIconPath": "/assets/tabbar/home-selected.png"
},
{
"pagePath": "pages/service/service",
"text": "服务",
"iconPath": "/assets/tabbar/service-unselect.png",
"selectedIconPath": "/assets/tabbar/service-selected.png"
},
{
"pagePath": "pages/mine/mine",
"text": "我的",
"iconPath": "/assets/tabbar/mine-unselect.png",
"selectedIconPath": "/assets/tabbar/mine-selected.png"
}
]
},
"sitemapLocation": "sitemap.json"
}
\ No newline at end of file
page {
--bgcolor: #f8f8f8;
--position-fixed: fixed;
--default-font-size: 14px;
--at: 'auto';
--primary-color: #437CFD;
background: var(--bgcolor);
}
.flex-column{
display: flex;
flex-direction: column;
}
.flex-row{
display: flex;
flex-direction: row;
}
.width100{
width: 100vw;
}
.column-center{
align-items: center;
}
.flex-1{
flex: 1;
}
\ No newline at end of file
// components/date-picker/date-picker.js
Component({
/**
* 组件的属性列表
*/
properties: {
range: { //可预约的日期范围。默认日期从今天开始,到第range天后为止,这里设为10天
type: Number,
value: 10
},
start_time: { //开始时间,设为整点
type: Number,
value: 8
},
step: { //预约时间的步长,设置为30,表示30分钟
type: Number
},
end_time: { //结束时间,设为整点
type: Number,
value: 22
}
},
/**
* 组件的初始数据
*/
data: {
isShow: false,
selectDate: "",
dialogh: 0,
//日期列表和时间列表
date_list: [],
time_list: [],
value: []
},
lifetimes:{
attached(){
let minute = new Date().getMinutes()
let startTime = 8
if(minute > 20){
startTime = new Date().getHours() + 2
}else{
startTime = new Date().getHours() + 1
}
this.setData({
start_time: startTime
})
console.log("---" + this.properties.start_time)
let start_day = this.ts_string(new Date().getTime())
let end_day = this.ts_string(new Date().setDate(new Date().getDate() + this.properties.range))
//获取日期列表
let date_list = this.getDiffDate(start_day, end_day)
//获取时间列表
let time_list = this.getTimeList(this.properties.start_time, this.properties.end_time, this.properties.step)
this.setData({
// date_time: [date_column, time_column],
date_list: date_list,
time_list: time_list,
})
//动画
this.animation = wx.createAnimation({
duration: 250
})
//500rpx转成px
let dialoghpx = 800 / 750 * wx.getSystemInfoSync().windowWidth
this.setData({
dialogh: dialoghpx,
selectDate: this.data.date_list[0]+this.data.time_list[0]
})
}
},
methods: {
getDiffDate(start, end) {
console.log(start)
let startTime = new Date(start.replace(/-/g,'/'))
let endTime = new Date(end.replace(/-/g,'/'))
console.log(startTime)
let dateArr = []
while ((endTime.getTime() - startTime.getTime()) >= 0) {
dateArr.push(this.ts_string(startTime.getTime()))
startTime.setDate(startTime.getDate() + 1)
}
return dateArr
},
zfill(num, length) {
return (Array(length).join('0') + num).slice(-length)
},
//把日期转换成xxxx-xx-xx的形式
ts_string(timestamp) {
let d = new Date(timestamp)
let string = (d.getFullYear()) + "-" +
this.zfill((d.getMonth() + 1), 2) + "-" +
this.zfill((d.getDate()), 2) + " "
return string
},
//获取时间区间列表,输入(起始时间,结束时间,步长)
getTimeList(start, end, step) {
let start_time = new Date()
//设置起始时间
start_time.setHours(start, 0, 0)
//设置结束时间
let end_time = new Date()
end_time.setHours(end, 0, 0)
let startG = start_time.getTime() //起始时间的格林时间
let endG = end_time.getTime() //起始时间的格林时间
let step_ms = step * 60 * 1000
let timeArr = []
while (startG < endG) {
let time = this.timeAdd(startG, step_ms)
timeArr.push(time)
startG += step_ms
}
return timeArr
},
timeAdd(time1, add) {
var nd = new Date(time1) //创建时间对象
//获取起始时间的时分秒
var hh1 = nd.getHours()
var mm1 = nd.getMinutes()
if (hh1 <= 9) hh1 = "0" + hh1
if (mm1 <= 9) mm1 = "0" + mm1
nd = nd.valueOf() //转换为毫秒数
nd = nd + Number(add)
nd = new Date(nd)
var hh2 = nd.getHours()
var mm2 = nd.getMinutes()
if (hh2 <= 9) hh2 = "0" + hh2
if (mm2 <= 9) mm2 = "0" + mm2
var time = hh1 + ":" + mm1
return time //时间段
},
change: function (e) {
const val = e.detail.value
//val[0]表示选择的第一列序号,val[1]表示选择的第二列序号
let select = this.data.date_list[val[0]] + this.data.time_list[val[1]]
console.log(select)
this.setData({
selectDate: select,
value: val
})
},
showDialog() {
this.setData({
isShow: true
})
//先向下移动dialog高度,然后恢复原位从而形成从下向上弹出效果
this.animation.translateY(this.data.dialogh).translateY(0).step()
this.setData({
animation: this.animation.export()
})
},
dimsss() {
//从原位向下移动dailog高度,形成从上向下的收起效果
this.animation.translateY(this.data.dialogh).step()
this.setData({
animation: this.animation.export()
})
//动画结束后蒙层消失
setTimeout(() => {
this.setData({
isShow: false
})
}, 250)
},
cancel() {
this.triggerEvent("cancel")
this.dimsss()
},
confirm() {
this.triggerEvent("confirm", {
selectDate: this.data.selectDate
})
this.dimsss()
}
}
})
\ No newline at end of file
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/date-picker/date-picker.wxml-->
<view class="mask" wx:if="{{isShow}}" catchtap="cancel">
<view class="content" style="height:800rpx" animation="{{animation}}">
<view class="top">
<view class="top-text top-left-color" hover-class="top-left-color-hover" catchtap="cancel">取消</view>
<view class="top-text top-right-color" hover-class="top-right-color-hover" catchtap="confirm">确定</view>
</view>
<picker-view style="width: 100%; height: 80%;" value="{{value}}" bindchange="change" catchtap="no">
<picker-view-column>
<view wx:for="{{date_list}}" wx:key="date_list" class="item">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{time_list}}" wx:key="time_list" class="item">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
</view>
\ No newline at end of file
/* components/date-picker/date-picker.wxss */
.mask {
position: fixed;
width: 100%;
height: 100%;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
background-color: rgba(0, 0, 0, 0.7);
z-index: 9999;
flex-direction: column;
justify-content: flex-end;
}
.content {
display: flex;
flex-direction: column;
width: 100%;
background: white;
border-top-right-radius: 10rpx;
border-top-left-radius: 10rpx;
}
.top {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
border-bottom: 1px solid #e3e3e3;
}
.top-text {
font-size: 30rpx;
width: 150rpx;
height: 100rpx;
line-height: 100rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.top-left-color {
color: #878787;
}
.top-left-color-hover {
color: #f1eaea;
}
.top-right-color {
color: #1296DB;
}
.top-right-color-hover {
color: #82ccf3;
}
.item {
width: 100%;
align-items: center;
justify-content: center;
display: flex;
flex-direction: row;
font-size: 28rpx;
}
\ No newline at end of file
// components/empty-view/empty-view.js
Component({
options: {
addGlobalClass: true,
},
/**
* 组件的属性列表
*/
properties: {
imageName: {
type: String,
value: ""
},
emptyTitle: {
type: String,
value: "暂无数据"
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/empty-view/empty-view.wxml-->
<view class="empty-content">
<image class="empty-icon" src="{{imageName}}"/>
<view class="empty-text">{{emptyTitle ? emptyTitle : '暂无数据'}}</view>
<slot></slot>
</view>
/* components/empty-view/empty-view.wxss */
.empty-content{
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.empty-icon{
width: 224rpx;
height: 224rpx;
margin-top: -200rpx;
}
.empty-text{
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 36rpx;
margin-top: 24rpx;
}
\ No newline at end of file
// components/order-item/manager-order-item.js
Component({
/**
* 组件的属性列表
*/
properties: {
item: {
value: null,
type: Object
},
roleType: {
value: null,
type: Number
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
dealAction(){
this.triggerEvent("dealAction",{id: this.data.item.id})
},
cancelAction(){
this.triggerEvent("cancelAction",{id: this.data.item.id})
},
finishAction(){
this.triggerEvent("finishAction",{id: this.data.item.id})
},
dispatchAction(){
this.triggerEvent("dispatchAction",{id: this.data.item.id})
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/order-item/manager-order-item.wxml-->
<view class="order-item-wrapper">
<view class="group-1">
<view class="t1">{{item.serviceSubclassName}}</view>
<view style="flex:1" />
<view class="status-t1">{{item.orderStatusValue}}</view>
</view>
<view class="order-no">订单编号:{{item.orderNo}}</view>
<view class="line1" />
<view class="group-2">
<image class="group-image" src="{{item.subclassImg}}"/>
<view class="group-2-column">
<view class="c1">{{item.serviceName}}</view>
<view class="c2">x{{item.num}}</view>
<view class="status-t1" style="margin-top: 10rpx;" wx:if="{{item.price}}">¥{{item.price}}</view>
</view>
</view>
<view class="line1" style="margin-bottom: 20rpx;" />
<view class="flex-row">
<image class="mini-icon" src="/assets/order/order-addr.png" />
<view class="time-text">{{item.address}}</view>
</view>
<view class="flex-row">
<image class="mini-icon" src="/assets/order/order-time.png" />
<view class="time-text">{{item.createTime}}</view>
</view>
<view class="flex-row">
<image class="mini-icon" src="/assets/order/order-user.png" />
<view class="time-text">{{item.name}}</view>
</view>
<view class="group-3" wx:if="{{item.orderStatus == 1 || item.orderStatus == 3 || item.orderStatus == 4|| item.orderStatus == 5 || roleType == 1}}">
<view style="flex: 1;" />
<view class="cp-1" wx:if="{{item.orderStatus == 1 || item.orderStatus == 2}}" catchtap="dealAction">处理</view>
<view class="cp-2" wx:if="{{item.orderStatus == 1 || item.orderStatus == 3}}" catchtap="cancelAction">取消订单</view>
<view class="cp-1" wx:if="{{item.orderStatus == 4}}" catchtap="dispatchAction">派单</view>
<view class="cp-1" wx:if="{{item.orderStatus == 5}}" catchtap="finishAction">完成</view>
</view>
</view>
\ No newline at end of file
/* components/order-item/manager-order-item.wxss */
.order-item-wrapper {
width: 630rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin: 0 auto;
display: flex;
flex-direction: column;
padding: 0 30rpx;
margin-top: 30rpx;
}
.group-1 {
display: flex;
flex-direction: row;
height: 94rpx;
justify-content: space-between;
align-items: center;
}
.order-no {
height: 40rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-bottom: 18rpx;
}
.t1 {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 40rpx;
}
.status-t1 {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 600;
color: #FF5A47;
line-height: 36rpx;
margin-right: 10rpx;
}
.line1 {
width: 626rpx;
height: 1px;
background: #F1F1F1;
}
.group-2 {
display: flex;
flex-direction: row;
height: 212rpx;
align-items: center;
}
.group-image {
width: 164rpx;
height: 164rpx;
border-radius: 8rpx;
}
.group-2-column {
display: flex;
flex-direction: column;
margin-left: 30rpx;
height: 100%;
}
.c1 {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
margin-top: 35rpx;
}
.c2 {
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
margin-top: 10rpx;
}
.time-text {
height: 56rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 56rpx;
margin-left: 10rpx;
}
.group-3 {
width: 100%;
height: 118rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.price {
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FF5A47;
line-height: 42rpx;
}
.cp-1 {
width: 148rpx;
height: 60rpx;
background: #437CFD;
border-radius: 34rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 60rpx;
text-align: center;
margin-left: 20rpx;
}
.djs {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #437CFD;
line-height: 36rpx;
}
.cp-2 {
width: 148rpx;
height: 60rpx;
border: 1px solid #437CFD;
border-radius: 34rpx;
margin-left: 20rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #437CFD;
line-height: 60rpx;
text-align: center;
}
.flex-row{
display: flex;
flex-direction: row;
align-items: center;
}
.mini-icon{
width: 34rpx;
height: 34rpx;
}
\ No newline at end of file
const {
timeConvert
} = require("../../utils/common")
// components/order-item/order-item.js
Component({
/**
* 组件的属性列表
*/
properties: {
itemData: {
value: null,
type: Object
}
},
/**
* 组件的初始数据
*/
data: {
timeStr: '',
leftTime: null
},
/**
* 组件的方法列表
*/
methods: {
payAction(){
this.triggerEvent("payAction",{orderId: this.data.itemData.id})
},
cancelAction(){
this.triggerEvent("cancelAction",{orderId: this.data.itemData.id})
},
serviceAction(){
this.triggerEvent("serviceAction")
},
finishAction(){
this.triggerEvent("finishAction",{orderId: this.data.itemData.id})
}
},
lifetimes: {
attached() {
if (this.data.itemData.leftTime) {
let timeStr = timeConvert(this.data.itemData.leftTime)
this.setData({
leftTime: this.data.itemData.leftTime,
timeStr
})
let that = this
this.timer = setInterval(function(){
let leftTime = that.data.leftTime
let timeStr = timeConvert(leftTime)
leftTime -= 1
if(leftTime < 0){
leftTime = 0
}
that.setData({
leftTime,
timeStr
})
}, 1000)
}
},
},
detached(){
clearInterval(this.timer)
}
})
\ No newline at end of file
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/order-item/order-item.wxml-->
<view class="order-item-wrapper">
<view class="group-1">
<view class="t1">{{itemData.serviceSubclassName}}</view>
<view class="status-t1">{{itemData.orderStatusValue}}</view>
</view>
<view class="line1"/>
<view class="group-2">
<image class="group-image" src="{{itemData.subclassImg}}"/>
<view class="group-2-column">
<view class="c1">{{itemData.serviceName}}</view>
<view class="c2">x{{itemData.num}}</view>
</view>
</view>
<view class="time-text">下单时间:{{itemData.createTime}}</view>
<view class="line1" wx:if="{{itemData.orderStatus == 3 || itemData.orderStatus == 5 || itemData.orderStatus == 6 || itemData.price}}"/>
<view class="group-3" wx:if="{{itemData.orderStatus == 3 || itemData.orderStatus == 5 || itemData.orderStatus == 6 || itemData.price}}">
<view class="price" wx:if="{{itemData.price}}">¥{{itemData.price}}</view>
<view style="flex: 1;"/>
<view class="djs" wx:if="{{itemData.leftTime}}">还剩{{timeStr}}</view>
<view class="cp-3" wx:if="{{itemData.orderStatus == 3}}" catchtap="cancelAction">取消订单</view>
<view class="cp-1" wx:if="{{itemData.orderStatus == 3}}" catchtap="payAction">去支付</view>
<view class="cp-2" wx:if="{{itemData.orderStatus == 6}}" catchtap="serviceAction">再来一单</view>
<view class="cp-1" wx:if="{{itemData.orderStatus == 5}}" catchtap="finishAction">完成服务</view>
</view>
</view>
/* components/order-item/order-item.wxss */
.order-item-wrapper {
width: 630rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin: 0 auto;
display: flex;
flex-direction: column;
padding: 0 30rpx;
margin-bottom: 20rpx;
}
.group-1 {
display: flex;
flex-direction: row;
height: 94rpx;
justify-content: space-between;
align-items: center;
}
.t1 {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 40rpx;
}
.status-t1 {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FF5A47;
line-height: 36rpx;
}
.line1 {
width: 626rpx;
height: 1px;
background: #F1F1F1;
}
.group-2 {
display: flex;
flex-direction: row;
height: 212rpx;
align-items: center;
}
.group-image {
width: 164rpx;
height: 164rpx;
border-radius: 8rpx;
}
.group-2-column {
display: flex;
flex-direction: column;
margin-left: 30rpx;
height: 100%;
}
.c1 {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
margin-top: 35rpx;
}
.c2 {
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
margin-top: 10rpx;
}
.time-text {
height: 76rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 76rpx;
}
.group-3 {
width: 100%;
height: 118rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.price {
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FF5A47;
line-height: 42rpx;
}
.cp-1 {
width: 148rpx;
height: 60rpx;
background: #437CFD;
border: 1px solid #437CFD;
border-radius: 34rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 60rpx;
text-align: center;
margin-left: 20rpx;
}
.djs {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #437CFD;
line-height: 36rpx;
}
.cp-2 {
width: 148rpx;
height: 60rpx;
background: #F1F1F1;
border-radius: 34rpx;
margin-left: 20rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #828282;
line-height: 60rpx;
text-align: center;
}
.cp-3 {
width: 148rpx;
height: 60rpx;
border: 1px solid #437CFD;
border-radius: 34rpx;
margin-left: 20rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #437CFD;
line-height: 60rpx;
text-align: center;
}
const itemHeight = 56 * 2;
Component({
data: {
childBoxHeight: 0,
},
externalClasses: ['t-class'],
properties: {
defaultOpen: {
type: Boolean,
value: false,
},
name: {
type: String,
value: '',
},
icon: {
type: String,
value: '',
},
childArr: {
type: Array,
value: [],
observer(childArr) {
this.setData({
childBoxHeight: this.data.defaultOpen ? itemHeight * childArr.length : 0,
});
},
},
},
methods: {
switchHandle() {
const { childArr, childBoxHeight } = this.data;
this.setData({
childBoxHeight: childBoxHeight > 0 ? 0 : childArr.length * itemHeight,
});
},
tapChild(e) {
this.triggerEvent('click', e.target.dataset);
},
},
});
{
"component": true
}
\ No newline at end of file
<view class="pullDownList t-class {{ childBoxHeight > 0 ? 'actived' : '' }}">
<view class="switchBox" catch:tap="switchHandle">
<view class="name">{{ name }}</view>
<t-icon name="{{icon}}" size="48rpx" color="#A6A6A6" t-class="icon" />
</view>
<view class="childBox" style="height: {{ childBoxHeight }}rpx">
<view class="child" wx:for="{{childArr}}" wx:key="name" data-item="{{item}}" bind:tap="tapChild">
{{ item.name }} {{ item.label }}
<t-icon name="chevron-right" color="#bbb" />
</view>
</view>
</view>
.pullDownList {
width: 100%;
box-sizing: border-box;
background-color: #fff;
border-radius: 8rpx;
margin-bottom: 24rpx;
overflow: hidden;
}
.pullDownList .switchBox {
height: 120rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 32rpx;
font-size: 32rpx;
line-height: 48rpx;
color: #333;
}
.pullDownList .name,
.pullDownList .icon {
transition: opacity 0.3s;
}
.pullDownList .name {
opacity: 0.9;
}
.pullDownList.actived .name {
opacity: 0.4;
}
.pullDownList.actived .icon {
opacity: 0.4;
}
.pullDownList .childBox {
transition: height 0.3s;
}
.pullDownList .childBox .child {
box-sizing: border-box;
border-bottom: 1rpx solid #e5e5e5;
height: 112rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-left: 32rpx;
margin-right: 32rpx;
font-size: 32rpx;
opacity: 0.9;
}
.pullDownList .childBox .child:last-of-type {
border-bottom-color: transparent;
}
// 获取授权token
const ApiAuth = '/weixin/login'
//服务列表
const ApiService = '/category/list'
//首页
const ApiHome = '/common/home'
//服务详情
const ApiServiceDetail = '/subclass/get/'
//用户信息
const ApiUserInfo = '/user/info'
//绑定手机号
const ApiBindPhone = '/weixin/phone'
//我的地址
const ApiAddressList = '/address/page'
//区域树
const ApiAreaTree = '/common/tree'
//新增地址
const ApiSaveAddr = '/address/save'
//删除地址
const ApiDeleteAddr = '/address/delete/'
//设置默认地址
const ApiDefAddr = '/address/def-address/'
//地址详情
const ApiAddrDt = '/address/get/'
//编辑地址
const ApiAddrUpdate = '/address/update'
//上传文件
const ApiUpload = '/upload'
//获取默认地址
const ApiDefAddrInfo = '/order/def-detail'
//预约下单
const ApiOrder = '/order/reserve'
//订单列表
const ApiOrderList = '/order/mine-page'
//家政服务协议
const ApiOrderAgreement = '/order/agreement'
//订单详情
const ApiOrderDetail = '/order/get/'
//管理员订单
const ApiManagerOrderList = '/order/page'
//估价员列表
const ApiValuator = '/valuator/get'
//订单估价
const ApiOrderValuator = '/order/valuation'
//取消订单
const ApiOrderCancel = '/order/cancel'
//发送订单
const ApiSendOrder = '/order/send'
//发起支付
const ApiOrderPay = '/order/pay/'
//完成订单
const ApiFinishOrder = '/order/finish'
//发送验证码
const ApiSendCode = '/user/send_code'
//换绑手机
const ApiRebind = '/user/rebind'
//修改估价员
const ApiRevaluator = '/order/revaluation'
//获取维修工
const ApiWorker = '/worker/get'
//派单
const ApiDispatch = '/order/dispatch'
//搜索服务
const ApiSearch = '/category/list'
//关于我们
const ApiAboutUs = '/common/about-us'
//公众号信息
const ApiMpInfo = '/common/mp-info'
//微信二维码
const ApiWXCode = '/weixin/qr-code'
//获取用户身份
const ApiGetRoleType = '/user/role-type'
module.exports = {
ApiAuth,
ApiService,
ApiHome,
ApiServiceDetail,
ApiUserInfo,
ApiBindPhone,
ApiAddressList,
ApiAreaTree,
ApiSaveAddr,
ApiDeleteAddr,
ApiDefAddr,
ApiAddrDt,
ApiAddrUpdate,
ApiUpload,
ApiDefAddrInfo,
ApiOrder,
ApiOrderList,
ApiOrderAgreement,
ApiOrderDetail,
ApiManagerOrderList,
ApiValuator,
ApiOrderValuator,
ApiOrderCancel,
ApiSendOrder,
ApiOrderPay,
ApiFinishOrder,
ApiSendCode,
ApiRebind,
ApiRevaluator,
ApiWorker,
ApiDispatch,
ApiSearch,
ApiAboutUs,
ApiMpInfo,
ApiWXCode,
ApiGetRoleType
}
\ No newline at end of file
const { loginStatus } = require("../utils/common")
const { ApiUpload } = require("./api")
const APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8"
const APPLICATION_JSON_UTF8_FORM = 'application/x-www-form-urlencoded;charset=UTF-8'
const RESPONSE_OK = 200
const TOKEN_BEOVERDUE = 400
const BASE_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NTg5MDY2NjEsInN1YiI6IntcInVzZXJJZFwiOjB9IiwiaXNzIjoib25zaXRlLXNlcnZpY2UtbWluaS1hcHAifQ.o8f8sa9CTyGjpg-Bw5Qqp80QckkudFzk6UKK97CagCk'
const app = getApp()
const HOST = 'http://172.16.1.55:9261'
// const HOST = 'https://chengshijiangren.antaikeji.top'
function fun(url, type, data, otherType) {
let TOKEN = app.globalData.token ? app.globalData.token : 'Bearer ' + BASE_TOKEN
let promise = new Promise((resolve, reject) => {
console.log('发起请求')
wx.request({
url: HOST + url,
method: type,
data: type == 'GET' ? data : JSON.stringify(data),
header: {
'content-type': otherType ? APPLICATION_JSON_UTF8_FORM : APPLICATION_JSON_UTF8_VALUE,
'Authorization': TOKEN
},
success: function (res) {
wx.hideLoading()
console.log('==========================================================================')
console.log('== token:' + TOKEN)
console.log('== 接口地址:' + url)
console.log('== 接口参数:' + JSON.stringify(data))
console.log('== 请求类型:' + type)
console.log("== 接口状态:" + res.statusCode);
console.log('== 请求结果:' + JSON.stringify(res.data))
console.log('==========================================================================')
wx.stopPullDownRefresh();
if (res.statusCode == RESPONSE_OK && res.data.code == RESPONSE_OK) {
resolve(res.data)
} else {
if(res.data.code == 401){
loginStatus(false)
app.globalData.token = ""
wx.removeStorageSync('token')
}
wx.showToast({
title: res.data.msg,
icon: 'none',
duration: 2000
})
reject()
}
},
fail: function (res) {
wx.hideLoading()
wx.stopPullDownRefresh();
reject(res)
//服务器连接异常
console.log('==========================================================================')
console.log('== 接口地址:' + url)
console.log('== 接口参数:' + JSON.stringify(data))
console.log('== 请求类型:' + type)
console.log("== 服务器连接异常")
console.log('==========================================================================')
}
})
})
return promise
}
module.exports = {
wxGet: function (url, data) {
return fun(url, 'GET', data)
},
wxPost: function (url, data) {
return fun(url, 'POST', data)
},
wxFormPost: function (url, data) {
return fun(url, 'POST', data, 'formPost')
},
wxPut: function (url, data) {
return fun(url, 'PUT', data)
},
wxDelete: function (url, data) {
return fun(url, 'DELETE', data)
},
wxUpload: function (path,fileType) {
let promise = new Promise((resolve, reject) => {
wx.uploadFile({
filePath: path,
name: 'files',
url: HOST + ApiUpload,
header: {
"Authorization": app.globalData.token
},
formData: {
fileType: fileType
},
success:function(res){
let data = JSON.parse(res.data)
if (res.statusCode == RESPONSE_OK && data.code == RESPONSE_OK) {
resolve(data)
} else {
wx.showToast({
title: res.data.msg,
icon: 'none',
duration: 2000
})
reject(data)
}
},
fail(){
reject()
}
})
})
return promise
},
HOST
}
\ No newline at end of file
const {
ApiAreaTree, ApiSaveAddr, ApiAddrDt, ApiAddrUpdate
} = require("../../http/api")
const {
wxGet, wxPost, wxPut
} = require("../../http/network")
const { showToast } = require("../../utils/common")
// pages/address/add-address.js
Page({
/**
* 页面的初始数据
*/
data: {
id: 0,
visible: false,
cityList: [],
countyList: [],
streetList: [],
cityName: "",
countyName: "",
streetName: "",
currentPos: 0,
namePath: "",
areaId: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
let id = options.id
if(id){
wx.setNavigationBarTitle({
title: '修改地址',
})
this.setData({
id
})
this.getData()
}
this.getArea()
},
getData(){
wxGet(ApiAddrDt + this.data.id).then(res=>{
this.setData({
address: res.data.address,
areaId: res.data.areaId,
name: res.data.name,
namePath: res.data.namePath,
phone: res.data.phone
})
})
},
getArea() {
wxGet(ApiAreaTree).then(res => {
this.setData({
cityList: res.data
})
})
},
chooseAddress() {
this.setData({
visible: true
})
},
dismissAction() {
this.setData({
visible: false
})
},
chooseCity(e){
let index = e.currentTarget.dataset.index
this.setData({
cityName: this.data.cityList[index].name,
countyList: this.data.cityList[index].children,
currentPos: 1
})
},
chooseCounty(e){
let index = e.currentTarget.dataset.index
this.setData({
countyName: this.data.countyList[index].name,
streetList: this.data.countyList[index].children,
currentPos: 2
})
},
chooseStreet(e){
let index = e.currentTarget.dataset.index
this.setData({
streetName: this.data.streetList[index].name,
visible: false,
areaId: this.data.streetList[index].id
})
this.setData({
namePath: this.data.cityName + this.data.countyName + this.data.streetName
})
},
changeCity(){
this.setData({
currentPos: 0
})
},
changeCounty(){
if(this.data.cityName.length == 0){
showToast("请先选择市")
return
}
this.setData({
currentPos: 1
})
},
changeStreet(){
if(this.data.countyName.length == 0){
showToast("请先选择区/县")
return
}
this.setData({
currentPos: 2
})
},
saveAction(){
if(this.data.name.length == 0){
showToast("请输入姓名")
return
}
if(this.data.phone.length == 0){
showToast("请输入手机号")
return
}
if(this.data.namePath.length == 0){
showToast("请选择地址")
return
}
if(this.data.address.length == 0){
showToast("请输入详细地址")
return
}
if(this.data.id > 0){
wxPut(ApiAddrUpdate,{
"address": this.data.address,
"areaId": this.data.areaId,
"name": this.data.name,
"namePath": this.data.namePath,
"phone": this.data.phone,
"id": this.data.id
}).then(res=>{
wx.showToast({
icon: 'none',
title: '保存成功',
complete:function(){
wx.navigateBack()
}
})
})
}else{
wxPost(ApiSaveAddr,{
"address": this.data.address,
"areaId": this.data.areaId,
"name": this.data.name,
"namePath": this.data.namePath,
"phone": this.data.phone
}).then(res=>{
wx.showToast({
icon: 'none',
title: '保存成功',
complete:function(){
wx.navigateBack()
}
})
})
}
}
})
\ No newline at end of file
{
"usingComponents": {
"t-popup": "tdesign-miniprogram/popup/popup"
},
"navigationBarTitleText": "新增地址"
}
\ No newline at end of file
<!--pages/address/add-address.wxml-->
<view class="flex-column">
<view class="content-item">
<view class="item-name">联系人</view>
<input class="item-input" placeholder="姓名" model:value="{{name}}"/>
</view>
<view class="content-item">
<view class="item-name">手机号</view>
<input class="item-input" placeholder="手机号" type="number" maxlength="11" model:value="{{phone}}"/>
</view>
<view class="content-item">
<view class="item-name">选择地址</view>
<input class="item-input" placeholder="选择服务地区" bindtap="chooseAddress" model:value="{{namePath}}"/>
</view>
<view class="content-item">
<view class="item-name">详细地址</view>
<input class="item-input" placeholder="街道门牌信息" model:value="{{address}}"/>
</view>
<image class="save-image" src="{{name.length > 0 && phone.length > 0 && namePath.length > 0 && address.length > 0 ? '/assets/address/address-save.png' : '/assets/address/address-dont.png'}}" bindtap="saveAction"/>
</view>
<t-popup visible="{{visible}}" placement="bottom">
<view slot="content" class="pop-wrapper">
<view class="pop-h">
<image class="pop-c" src="/assets/address/down-circle.png" bindtap="dismissAction"/>
<view class="pop-t">选择地区</view>
<view class="pop-c" />
</view>
<view class="pop-tab-wrapper">
<view bindtap="changeCity" class="pop-tab {{cityName.length > 0 ? 'pop-tab-selected' : ''}}">{{cityName.length > 0 ? cityName : '市'}}</view>
<view bindtap="changeCounty" class="pop-tab {{countyName.length > 0 ? 'pop-tab-selected' : ''}}">{{countyName.length > 0 ? countyName : '区/县'}}</view>
<view bindtap="changeStreet" class="pop-tab {{streetName.length > 0 ? 'pop-tab-selected' : ''}}">{{streetName.length > 0 ? streetName : '街道/镇'}}</view>
</view>
<scroll-view class="pop-sc" wx:if="{{currentPos == 0}}">
<view class="pop-sc-item" wx:for="{{cityList}}" wx:key="*this" data-index="{{index}}" bindtap="chooseCity">{{item.name}}</view>
</scroll-view>
<scroll-view class="pop-sc" wx:if="{{currentPos == 1}}">
<view class="pop-sc-item" wx:for="{{countyList}}" wx:key="*this" data-index="{{index}}" bindtap="chooseCounty">{{item.name}}</view>
</scroll-view>
<scroll-view class="pop-sc" wx:if="{{currentPos == 2}}">
<view class="pop-sc-item" wx:for="{{streetList}}" wx:key="*this" data-index="{{index}}" bindtap="chooseStreet">{{item.name}}</view>
</scroll-view>
</view>
</t-popup>
\ No newline at end of file
/* pages/address/add-address.wxss */
page{
background: white;
}
.content-item {
display: flex;
flex-direction: row;
margin: 0 30rpx;
height: 110rpx;
border-bottom: 1px #F1F1F1 solid;
}
.item-name {
width: 120rpx;
height: 110rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 110rpx;
}
.item-input {
height: 110rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 110rpx;
flex: 1;
margin-left: 40rpx;
}
.save-image {
width: 690rpx;
height: 90rpx;
margin: 0 auto;
margin-top: 80rpx;
}
.pop-wrapper {
width: 750rpx;
height: 858rpx;
background: #FFFFFF;
border-radius: 28rpx 28rpx 0px 0px;
display: flex;
flex-direction: column;
}
.pop-h {
display: flex;
flex-direction: row;
width: 100%;
height: 120rpx;
align-items: center;
justify-content: space-between;
}
.pop-t {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 40rpx;
}
.pop-c {
width: 40rpx;
height: 40rpx;
margin: 0 30rpx;
}
.pop-tab-wrapper {
display: flex;
flex-direction: row;
align-items: center;
}
.pop-tab {
height: 80rpx;
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 80rpx;
margin: 0 30rpx;
}
.pop-tab-selected{
color: #3E3E3E;
}
.pop-sc {
width: 100%;
height: 658rpx;
}
.pop-sc-item {
width: 670rpx;
height: 102rpx;
border-bottom: 1px #EEEEEE solid;
margin: 0 auto;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 102rpx;
}
\ No newline at end of file
// pages/address/index.js
import {
ApiAddressList, ApiDefAddr, ApiDeleteAddr
} from '../../http/api'
import {
wxDelete,
wxPost
} from '../../http/network'
import {
jumpPage, showToast
} from '../../utils/common'
var canLoadMore = true
var page = 1
Page({
/**
* 页面的初始数据
*/
data: {
list: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.path = options.path
},
onShow(){
this.getData(true)
},
addAddressAction: jumpPage(function (e) {
wx.navigateTo({
url: './add-address',
})
}, true),
getData(refresh) {
if (refresh) {
page = 1
}
wxPost(ApiAddressList, {
"page": page
}).then(res => {
var list = this.data.list
if (refresh) {
list = res.data.list
} else {
list = list.concat(res.data.list)
}
this.setData({
list
})
canLoadMore = res.data.hasNextPage
})
},
onPullDownRefresh(e) {
this.getData(true)
},
onReachBottom(e) {
if (canLoadMore) {
this.getData(false)
}
},
defaultAction(e){
let id = e.currentTarget.dataset.id
let that = this
wxPost(ApiDefAddr + id).then(res=>{
that.getData(true)
showToast("设置成功")
})
},
deleteAction(e){
let id = e.currentTarget.dataset.id
let that = this
wx.showModal({
title:"删除提示",
content: "您是否要删除该地址?",
complete:function(e){
if(e.confirm){
wxDelete(ApiDeleteAddr + id).then(res=>{
showToast(res.msg)
that.getData(true)
})
}
}
})
},
modifyAction(e){
let id = e.currentTarget.dataset.id
wx.navigateTo({
url: './add-address?id=' + id,
})
},
chooseAction(e){
let index = e.currentTarget.dataset.index
if(this.path){
let data = this.data.list[index]
const eventChannel = this.getOpenerEventChannel()
eventChannel.emit("getBackData",data)
wx.navigateBack()
}
}
})
\ No newline at end of file
{
"usingComponents": {
"empty-view":"/components/empty-view/empty-view"
},
"navigationBarTitleText": "地址",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}
\ No newline at end of file
<!--pages/address/index.wxml-->
<import src="/templates/address-item-template"/>
<empty-view imageName="/assets/address/no-address.png" wx:if="{{list.length == 0}}">
<view class="add-btn" bindtap="addAddressAction">添加地址</view>
</empty-view>
<view class="list-wrapper">
<template is="address-item" wx:for="{{list}}" wx:key="*this" data="{{...item,index}}"></template>
</view>
<view class="add-fixed" bindtap="addAddressAction" wx:if="{{list.length > 0}}">添加新地址</view>
\ No newline at end of file
/* pages/address/index.wxss */
@import "/templates/address-item-template.wxss";
page {
background: #F8F8F8;
}
.add-btn {
width: 236rpx;
height: 74rpx;
background: #437CFD;
border-radius: 56rpx;
color: white;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 74rpx;
margin-top: 50rpx;
text-align: center;
}
.add-fixed {
width: 690rpx;
height: 88rpx;
border-radius: 44rpx;
background: #437CFD;
position: fixed;
z-index: 2;
bottom: 100rpx;
left: 30rpx;
line-height: 88rpx;
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
text-align: center;
}
\ No newline at end of file
// pages/login/login.js
import api from '../../http/api'
import {
wxPost
} from '../../http/network'
import { loginStatus } from '../../utils/common'
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.login({
timeout: 2000,
})
},
getUserInfo(e) {
let that = this
wx.showLoading({
title: '授权中'
})
wx.getUserProfile({
desc: 'desc',
success(e) {
wx.hideLoading()
that.loginAction(e)
},
fail(e) {
wx.hideLoading()
console.log(e)
}
})
},
loginAction(data) {
let that = this
wx.login({
timeout: 3000,
success(e) {
data['code'] = e.code
that.getAuth(data)
}
})
},
getAuth(data) {
wx.showLoading({
title: '登录中'
})
const recommendUserId = wx.getStorageSync('recommendUserId')
if(recommendUserId){
data.shareUserId = recommendUserId
}
wxPost(api.ApiAuth, data).then((res) => {
wx.hideLoading()
app.globalData.token = res.data.token
app.globalData.userId = res.data.userId
wx.setStorageSync('token', res.data.token)
wx.setStorageSync('userId', res.data.userId)
app.globalData.roleType = res.data.roleType
loginStatus(true)
wx.showToast({
icon: 'none',
title: res.msg,
success(){
wx.navigateBack()
}
})
}).catch(()=>{
wx.hideLoading()
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "登录"
}
\ No newline at end of file
<!--pages/login/login.wxml-->
<view class="container center">
<image src="/assets/mine/logo.png" class="logo" />
<text class="auth">城市匠人申请获得以下权限</text>
<text class="auth-info">获得您的公开信息(昵称、头像等)</text>
<image bindtap="getUserInfo" class="login" src="/assets/mine/login-btn.png" />
</view>
\ No newline at end of file
/* pages/login/login.wxss */
page{
background: white;
}
.container{
display: flex;
flex-direction: column;
}
.center {
align-items: center;
position: relative;
height: 100vh;
}
.logo {
width: 350rpx;
height: 350rpx;
margin-top: 100rpx;
}
.auth {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
margin-top: 40rpx;
}
.auth-info {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-top: 10rpx;
}
.login{
width: 624rpx;
height: 112rpx;
position: absolute;
bottom: 160rpx;
border: none;
background: none;
padding: 0;
}
\ No newline at end of file
// pages/home/home.js
import {
ApiHome,
ApiWXCode,
ApiGetRoleType
} from '../../http/api'
import {
wxGet,
HOST
} from '../../http/network'
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
headTop: 0,
height: 0,
top: 0,
data: null,
roleType: -1,
noticeIndex: 1,
showPoster: false,
base64Data: null,
canvas: null,
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
const recommendUserId = options.scene
if(recommendUserId){
const p = wx.getStorageSync('recommendUserId')
if(!p){
wx.setStorageSync('recommendUserId', recommendUserId)
}
}
const {
height,
top
} = wx.getMenuButtonBoundingClientRect()
this.setData({
headTop: top + height + 10,
height,
top
})
this.getData()
},
onShow() {
wxGet(ApiGetRoleType).then(res => {
this.setData({
roleType: res.data
})
app.globalData.roleType = res.data
})
},
getData() {
wxGet(ApiHome).then(res => {
this.setData({
data: res.data
})
})
},
searchAction() {
wx.navigateTo({
url: '/pages/search/index',
})
},
noticeChange(e) {
this.setData({
noticeIndex: e.detail.current + 1
})
},
serviceItemClick(e) {
let index = e.currentTarget.dataset.index
let p1 = index.split("-")[0]
let p2 = index.split("-")[1]
let id = this.data.data.serviceList[p1].children[p2].id
let serviceName = this.data.data.serviceList[p1].children[p2].serviceName
wx.navigateTo({
url: `../service/service-detail?id=${id}&serviceName=${serviceName}`
})
},
serviceCateClick(e) {
let id = e.currentTarget.dataset.id
app.globalData.cateId = id
wx.switchTab({
url: '/pages/service/service',
})
},
getQrcode() {
wx.showLoading({
title: '生成中',
})
let url = HOST + ApiWXCode
let param = {
"path": "pages/home/home",
"scene": app.globalData.userId,
"width": 0
}
let that = this
wx.request({
url: url,
method: 'POST',
data: param,
header: {
'Authorization': app.globalData.token
},
success: function (res) {
if (res.data.code == 200) {
let base64data = 'data:image/png;base64,' + res.data.data
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || []
if (!format) {
wx.showToast({
icon: "none",
title: '生成失败',
duration: 1000,
})
} else {
const buffer = wx.base64ToArrayBuffer(bodyData);
let fsm = wx.getFileSystemManager()
wx.hideLoading()
fsm.writeFile({
filePath: `${wx.env.USER_DATA_PATH}/qrcode.png`,
encoding: 'binary',
data: buffer,
success: res => {
that.setData({
base64Data: `${wx.env.USER_DATA_PATH}/qrcode.png`,
showPoster: true
})
that.saveImageToPhotosAlbum()
}
})
}
}else{
wx.showToast({
icon: "none",
title: '生成失败',
duration: 1000,
})
}
},
fail: function (e) {
console.log(e)
wx.hideLoading()
}
})
},
saveImageToPhotosAlbum() {
let that = this
const query = wx.createSelectorQuery()
query.select('#share')
.fields({
node: true,
size: true
})
.exec(async (res) => {
const canvas = res[0].node
that.setData({
canvas: canvas
})
const ctx = canvas.getContext('2d')
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
// 创建一个图片
const image = canvas.createImage()
let width = canvas.width / dpr
let height = canvas.height / dpr
let topHeight = height * 920 / 1180
await new Promise(resolve => {
image.onload = resolve
image.src = "/assets/main/poster-center.png"
})
ctx.drawImage(image, 0, 0, width, height)
// 创建一个图片
const icon = canvas.createImage()
await new Promise(resolve => {
icon.onload = resolve
icon.src = that.data.base64Data
})
// 开始创建一个路径
ctx.beginPath()
// 画一个圆形裁剪区域
ctx.arc(width/2, topHeight + 15 + 40, 40, 0, Math.PI * 2, false)
// 裁剪
ctx.clip()
ctx.drawImage(icon, width/2 - 40, topHeight + 15, 80, 80)
})
},
saveAction(){
// 将生成的canvas图片,转为真实图片
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvas: this.data.canvas,
success: function (res) {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: (rest) => {
wx.showToast({
title: '保存成功',
duration: 1000,
});
}
});
},
fail: function (res) {
console.log(res)
}
})
},
// 取消
cancelAction() {
this.setData({
showPoster: false
})
},
})
\ No newline at end of file
{
"usingComponents": {},
"navigationStyle": "custom"
}
\ No newline at end of file
<!--pages/home/home.wxml-->
<view class="flex-column">
<view class="header-wrapper">
<swiper class="swiper-class" autoplay>
<swiper-item class="swiper-item" wx:for="{{data.bannerList}}" wx:key="*this">
<image class="swiper-item" src="{{item.url}}" mode="aspectFill" />
</swiper-item>
</swiper>
<view class="search-wrapper" style="top:{{headTop}}px" bindtap="searchAction">
<image class="search-icon" src="/assets/main/urban-search.png" />
<view class="search-text">搜索您需要的服务</view>
</view>
</view>
<view class="content-wrapper">
<view class="cate-wrapper">
<image class="cate-item" wx:for="{{data.serviceList}}" wx:key="*this" src="{{item.img}}" bindtap="serviceCateClick" data-id="{{item.id}}"/>
</view>
<view class="notice-wrapper" wx:if="{{data.noticeList.length > 0}}">
<image class="notice-icon" src="/assets/main/notice.png" />
<swiper class="notice-swiper" autoplay bindchange="noticeChange" vertical>
<swiper-item class="notice-item" wx:for="{{data.noticeList}}" wx:key="*this">
<view class="notice-text">{{item.content}}</view>
</swiper-item>
</swiper>
<view class="notice-num">{{noticeIndex}}/{{data.noticeList.length}}</view>
</view>
<view class="cate-dt-wrapper" wx:for="{{data.serviceList}}" wx:key="*this">
<view class="cate-header" style="background: linear-gradient(180deg, {{item.backColor}} 0%, rgba(255, 255, 255, 0) 100%);" />
<view class="cate-top" bindtap="serviceCateClick" data-id="{{item.id}}">
<view class="ct-1">
<view class="ct-l" style="background: {{item.titleColor}};"/>
<view class="ct-tx">{{item.serviceName}}</view>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png" />
</view>
<view class="subtitle">{{item.description}}</view>
</view>
<view class="item-content-wrapper">
<view class="item-content" wx:for="{{item.children}}" wx:for-index="idx" wx:for-item="child" wx:key="*this" data-index="{{index}}-{{idx}}" bindtap="serviceItemClick">
<image class="item-thumb" src="{{child.detailImg}}" mode="aspectFill"/>
<view class="item-name">{{child.serviceName}}</view>
<view class="name-subtitle">{{child.description}}</view>
</view>
</view>
</view>
</view>
</view>
<image bindtap="getQrcode" class="poster" src="/assets/main/create-poster.png" wx:if="{{roleType == 3}}"/>
<button open-type="contact" wx:if="{{roleType == 0}}">
<image class="kefu" src="/assets/mine/kefu.png"/>
</button>
<view class="poster-wrapper" wx:if="{{showPoster}}" catchtouchmove="true">
<view class="model" />
<view class="poster-content">
<canvas type="2d" id="share" canvas-id="share" style="width: 590rpx; height: 1180rpx; border-radius: 4px;"></canvas>
<view class="poster-bottom">
<text class="poster-cancel" catchtap="cancelAction">取消</text>
<view class="line" />
<text class="poster-confirm" catchtap="saveAction">保存到相册</text>
</view>
</view>
</view>
\ No newline at end of file
/* pages/home/home.wxss */
page {
background: #F8F8F8;
}
.header-wrapper {
width: 750rpx;
height: 638rpx;
position: relative;
}
.swiper-class {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.swiper-item {
width: 100%;
height: 100%;
}
.search-wrapper {
width: 690rpx;
height: 72rpx;
background: #FFFFFF;
border-radius: 36rpx;
position: absolute;
left: 30rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.content-wrapper {
width: 750rpx;
min-height: 678rpx;
background: linear-gradient(175deg, #FFFFFF 0%, #F8F8F8 100%);
border-radius: 24rpx 24rpx 0px 0px;
margin-top: -30rpx;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 40rpx;
}
.cate-wrapper {
display: flex;
flex-direction: row;
width: 100%;
flex-wrap: wrap;
padding-bottom: 40rpx;
}
.cate-item {
width: 212rpx;
height: 272rpx;
margin: 40rpx 15rpx 0 22rpx;
border-radius: 10rpx;
}
.notice-wrapper {
width: 690rpx;
height: 96rpx;
background: #FFFFFF;
box-shadow: 0px 4rpx 10rpx 0px rgba(64, 42, 42, 0.0600);
border-radius: 8rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.notice-icon {
width: 60rpx;
height: 40rpx;
margin-left: 25rpx;
}
.notice-swiper {
flex: 1;
height: 50rpx;
margin-left: 20rpx;
}
.notice-item {
width: 100%;
height: 50rpx;
}
.notice-text {
height: 50rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 50rpx;
}
.notice-num {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin: 0 25rpx;
}
.cate-dt-wrapper {
width: 690rpx;
background: #FFFFFF;
box-shadow: 0px 0px 12rpx 0px rgba(0, 0, 0, 0.0600);
border-radius: 8rpx;
margin-top: 40rpx;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
}
.cate-header {
width: 690rpx;
height: 246rpx;
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
.cate-top {
display: flex;
flex-direction: column;
margin-top: 40rpx;
z-index: 20;
}
.ct-1 {
display: flex;
flex-direction: row;
align-items: center;
}
.ct-l {
width: 8rpx;
height: 36rpx;
background: #69ABFC;
border-radius: 2rpx;
margin-left: 30rpx;
}
.ct-tx {
height: 48rpx;
font-size: 34rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 48rpx;
margin-left: 20rpx;
flex: 1;
}
.arrow {
width: 24rpx;
height: 24rpx;
margin-right: 30rpx;
}
.subtitle {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-left: 56rpx;
}
.item-content-wrapper {
display: flex;
flex-direction: row;
width: 630rpx;
flex-wrap: wrap;
justify-content: space-between;
margin: 0 auto;
padding-bottom: 20rpx;
z-index: 3;
}
.item-content {
width: 300rpx;
display: flex;
flex-direction: column;
margin-top: 30rpx;
}
.item-thumb {
width: 300rpx;
height: 200rpx;
}
.item-name {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
margin-top: 20rpx;
}
.name-subtitle {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
color: #9F9F9F;
line-height: 34rpx;
}
.search-icon {
width: 34rpx;
height: 34rpx;
margin-left: 20rpx;
}
.search-text {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-left: 15rpx;
}
.kefu{
width: 174rpx;
height: 182rpx;
position: fixed;
z-index: 10;
right: 0;
bottom: 100rpx;
}
.poster{
width: 176rpx;
height: 60rpx;
position: fixed;
z-index: 10;
right: 0;
bottom: 300rpx;
}
.poster-wrapper {
width: 100vw;
height: 100vh;
position: fixed;
z-index: 10;
display: flex;
top: 0;
left: 0;
align-items: center;
justify-content: center;
}
.model {
width: 100%;
height: 100%;
background-color: black;
opacity: 0.4;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.poster-content {
width: 590rpx;
height:86%;
background-color: white;
position: absolute;
top: 10%;
left: calc(50% - 296rpx);
z-index: 10;
display: flex;
border-radius: 10rpx;
flex-direction: column;
overflow: hidden;
}
.poster-bottom {
width: 100%;
height: 100rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.poster-cancel {
flex: 1;
height: 100%;
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
display: flex;
align-items: center;
justify-content: center;
}
.poster-confirm {
height: 100%;
flex: 1;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #437CFD;
display: flex;
align-items: center;
justify-content: center;
}
.line {
width: 2rpx;
height: 28rpx;
background-color: #F1F1F1;
}
.wechat {
width: 158rpx;
height: 160rpx;
}
.poster-info {
width: 100%;
height: 160rpx;
display: flex;
flex-direction: row;
margin-top: 36rpx;
position: absolute;
}
.poster-info-left {
flex-direction: column;
display: flex;
flex: 1;
}
.poster-item {
height: 40rpx;
display: flex;
flex-direction: row;
align-items: center;
padding-left: 30rpx;
}
.name-tip {
width: 44rpx;
height: 32rpx;
font-size: 22rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #717171;
line-height: 32rpx;
}
.name-info {
height: 40rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #E60012;
line-height: 40rpx;
margin-left: 12rpx;
}
.position-info {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 34rpx;
margin-left: 12rpx;
}
.qrcode {
width: 160rpx;
height: 160rpx;
margin-right: 30rpx;
border-radius: 80rpx;
}
const { ApiAboutUs } = require("../../http/api")
const { wxGet } = require("../../http/network")
// pages/mine/about-us.js
Page({
/**
* 页面的初始数据
*/
data: {
html:""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wxGet(ApiAboutUs).then(res=>{
this.setData({
html: res.data
})
})
},
})
\ No newline at end of file
{
"usingComponents": {}
}
\ No newline at end of file
<!--pages/mine/about-us.wxml-->
<view class="rich">
<rich-text nodes="{{html}}"></rich-text>
</view>
/* pages/mine/about-us.wxss */
page{
background: white;
}
.rich{
width: 690rpx;
margin: 0 auto;
margin-top: 20rpx;
}
\ No newline at end of file
// pages/mine/change-phone.js
const {
ApiSendCode,
ApiRebind
} = require("../../http/api")
const {
wxPost
} = require("../../http/network")
const { showToast } = require("../../utils/common")
let intervalId
Page({
/**
* 页面的初始数据
*/
data: {
phone: '',
time: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
onUnload(){
clearInterval(intervalId)
},
submitAction() {
if (this.data.phone.length != 11) {
wx.showToast({
icon: 'none',
title: '请输入手机号',
})
return
}
if (this.data.code.length == 0) {
wx.showToast({
icon: 'none',
title: '请输入验证码',
})
return
}
wxPost(ApiRebind, {
phone: this.data.phone,
code: this.data.code
}).then(res => {
wx.navigateBack()
})
},
sendCodeAction() {
if (this.data.phone.length != 11) {
wx.showToast({
icon: 'none',
title: '请输入手机号',
})
return
}
this.sendCodeRequest(this.data.phone)
},
sendCodeRequest(phone) {
let that = this
wxPost(ApiSendCode, {
'to': phone
}).then((res) => {
showToast("发送成功")
that.setData({
time: 60
})
intervalId = setInterval(function () {
let time = that.data.time
time--
if (time <= 0) {
clearInterval(intervalId)
}
that.setData({
time
})
}, 1000)
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "换绑手机"
}
\ No newline at end of file
<!--pages/mine/change-phone.wxml-->
<view class="content">
<view class="phone-wrapper">
<input model:value="{{phone}}" class="phone" placeholder="请输入手机号" type="number" maxlength="11"/>
<text class="send" bindtap="sendCodeAction" wx:if="{{time <= 0}}">获取验证码</text>
<text id="po" class="send" wx:else>{{time}}s后重新发送</text>
</view>
<view class="phone-wrapper">
<input model:value="{{code}}" class="phone" placeholder="请输入验证码" type="number" maxlength="6"/>
</view>
<text class="submit-text" bindtap="submitAction">提交</text>
</view>
/* pages/mine/change-phone.wxss */
page{
background: white;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
}
.phone {
border-radius: 10rpx;
padding: 10rpx;
flex: 1;
}
.submit-text {
width: 90%;
height: 88rpx;
background: var(--primary-color);
border-radius: 44rpx;
text-align: center;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
margin: auto;
line-height: 88rpx;
margin-top: 48rpx;
margin-bottom: 20rpx;
position: fixed;
bottom: 60rpx;
}
.send {
min-width: 160rpx;
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: var(--primary-color);
line-height: 45rpx;
}
.phone-wrapper{
display: flex;
flex-direction: row;
width: 90%;
align-items: center;
height: 120rpx;
border-bottom: 1rpx #eee solid;
}
#po{
color: #9F9F9F;
}
// pages/mine/mine.js
import { ApiUserInfo } from '../../http/api'
import { wxGet } from '../../http/network'
import {jumpPage} from '../../utils/common'
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
isLogin: app.globalData.token.length > 0,
data: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
onShow(opt){
this.setData({
isLogin: app.globalData.token.length > 0
})
if(this.data.isLogin){
this.getUserInfo()
}
},
getUserInfo(){
wxGet(ApiUserInfo).then(res=>{
this.setData({
data: res.data
})
// 1客服 2估价员 3销售
app.globalData.roleType = res.data.roleType
}).catch(()=>{
this.setData({
isLogin: false
})
})
},
userInfoAction:jumpPage(function(e){
wx.navigateTo({
url: './user-info',
})
},true),
customerAction(){
},
offcialAction(){
wx.navigateTo({
url: '/pages/mine/official-account',
})
},
aboutAction(){
wx.navigateTo({
url: './about-us',
})
},
addressPage:jumpPage(function(e){
wx.navigateTo({
url: '../address/index',
})
},true),
orderListAction:jumpPage(function(e){
let status = e.currentTarget.dataset.status
wx.navigateTo({
url: '../order/order-list?orderStatus=' + status,
})
},true),
managerOrderList(){
wx.navigateTo({
url: '../workbench/order-list',
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
\ No newline at end of file
<!--pages/mine/mine.wxml-->
<view class="header-wrapper">
<view class="center-wrapper" bindtap="userInfoAction">
<image class="thumb" src="{{isLogin ? data.avatar : '/assets/mine/default-thumb.png'}}"/>
<view class="info-wrapper">
<view class="name">{{isLogin ? data.nickName : '去登录'}}</view>
<view class="phone" wx:if="{{data.phone}}">{{data.phone}}</view>
</view>
<view style="flex: 1;"/>
<image class="arrow" src="/assets/mine/urban-arrow.png"/>
</view>
</view>
<view class="order-wrapper">
<view class="order-top" bindtap="orderListAction" data-status="0">
<view class="order-header">我的订单</view>
<view class="order-all">全部</view>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png"/>
</view>
<view class="order-bottom">
<view class="order-item" bindtap="orderListAction" data-status="3">
<view class="order-icon-wrapper">
<image class="order-icon" src="/assets/mine/order-pay.png"/>
<view class="order-badge" wx:if="{{data.orderInfo[0].num > 0}}">{{data.orderInfo[0].num}}</view>
</view>
<view class="order-text">待付款</view>
</view>
<view class="order-item" bindtap="orderListAction" data-status="1">
<view class="order-icon-wrapper">
<image class="order-icon" src="/assets/mine/order-wait.png"/>
<view class="order-badge" wx:if="{{data.orderInfo[1].num > 0}}">{{data.orderInfo[1].num}}</view>
</view>
<view class="order-text">待受理</view>
</view>
<view class="order-item" bindtap="orderListAction" data-status="4">
<view class="order-icon-wrapper">
<image class="order-icon" src="/assets/mine/order-take.png"/>
<view class="order-badge" wx:if="{{data.orderInfo[2].num > 0}}">{{data.orderInfo[2].num}}</view>
</view>
<view class="order-text">待派单</view>
</view>
<view class="order-item" bindtap="orderListAction" data-status="5">
<view class="order-icon-wrapper">
<image class="order-icon" src="/assets/mine/order-complate.png"/>
<view class="order-badge" wx:if="{{data.orderInfo[3].num > 0}}">{{data.orderInfo[3].num}}</view>
</view>
<view class="order-text">服务中</view>
</view>
</view>
</view>
<view class="tp-wrapper">
<button class="tp-item-btn" style="height: 120rpx;" open-type="contact" bindtap="customerAction">
<image class="tp-icon" src="/assets/mine/tp-customer.png"/>
<view class="tp-text">客服中心</view>
<image class="arrow" style="margin-right:0rpx" src="/assets/mine/urban-arrow-gray.png"/>
</button>
<view class="tp-item" bindtap="addressPage">
<image class="tp-icon" src="/assets/mine/tp-address.png"/>
<view class="tp-text">地址信息</view>
<image class="arrow" style="margin-right:0rpx" src="/assets/mine/urban-arrow-gray.png"/>
</view>
<view class="tp-item" bindtap="aboutAction">
<image class="tp-icon" src="/assets/mine/tp-about.png"/>
<view class="tp-text">关于我们</view>
<image class="arrow" style="margin-right:0rpx" src="/assets/mine/urban-arrow-gray.png"/>
</view>
<view class="tp-item" bindtap="offcialAction">
<image class="tp-icon" src="/assets/mine/tp-push.png"/>
<view class="tp-text">公众号</view>
<image class="arrow" style="margin-right:0rpx" src="/assets/mine/urban-arrow-gray.png"/>
</view>
<view class="tp-item" wx:if="{{data.roleType == 1 || data.roleType == 2}}" bindtap="managerOrderList">
<image class="tp-icon" src="/assets/mine/workbench.png"/>
<view class="tp-text">工作台</view>
<view class="order-num">{{data.todo}}</view>
<image class="arrow" style="margin-right:0rpx" src="/assets/mine/urban-arrow-gray.png"/>
</view>
</view>
\ No newline at end of file
/* pages/mine/mine.wxss */
page {
display: flex;
flex-direction: column;
background: #F8F8F8;
align-items: center;
}
.header-wrapper {
width: 750rpx;
height: 406rpx;
background: #437CFD;
display: flex;
flex-direction: row;
align-items: center;
}
.thumb {
width: 80rpx;
height: 80rpx;
border-radius: 60rpx;
margin-left: 30rpx;
}
.info-wrapper {
display: flex;
flex-direction: column;
margin-left: 30rpx;
}
.name {
height: 56rpx;
font-size: 40rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
line-height: 56rpx;
}
.phone {
height: 34rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 34rpx;
}
.center-wrapper {
margin-top: 70rpx;
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
}
.arrow {
width: 24rpx;
height: 24rpx;
margin-right: 30rpx;
}
.order-wrapper {
width: 690rpx;
height: 224rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin-top: -60rpx;
display: flex;
flex-direction: column;
}
.order-top {
width: 100%;
height: 90rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.order-header {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #141F33;
line-height: 44rpx;
margin-left: 32rpx;
flex: 1;
}
.order-all {
height: 32rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 32rpx;
}
.order-item {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.order-bottom {
display: flex;
flex-direction: row;
flex: 1;
}
.order-icon-wrapper {
position: relative;
}
.order-icon {
width: 60rpx;
height: 60rpx;
}
.order-badge {
width: 34rpx;
height: 34rpx;
background: #FF6E6E;
border-radius: 17rpx;
position: absolute;
color: white;
text-align: center;
line-height: 34rpx;
font-size: 20rpx;
top: 0;
right: -6rpx;
}
.order-text {
height: 32rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 32rpx;
}
.tp-wrapper {
width: 690rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin-top: 20rpx;
display: flex;
flex-direction: column;
}
.tp-item {
display: flex;
flex-direction: row;
height: 120rpx;
margin: 0 30rpx;
border-bottom: 1px solid #F1F1F1;
align-items: center;
}
.tp-item-btn {
display: flex;
flex-direction: row;
margin: 0 30rpx;
border-bottom: 1px solid #F1F1F1;
align-items: center;
background: white;
padding: 0;
}
.tp-item-btn::after {
border: 0;
}
.tp-icon {
width: 40rpx;
height: 40rpx;
}
.tp-text {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 44rpx;
flex: 1;
margin-left: 20rpx;
text-align: left;
}
.order-num{
width: 38rpx;
height: 38rpx;
border-radius: 38rpx;
background: #FF6E6E;
margin-right: 10rpx;
text-align: center;
line-height: 38rpx;
font-size: 20rpx;
color: white;
}
\ No newline at end of file
const { ApiMpInfo } = require("../../http/api")
const { wxGet } = require("../../http/network")
const { showToast } = require("../../utils/common")
// pages/mine/official-account.js
Page({
/**
* 页面的初始数据
*/
data: {
MP_QRCODE: "",
MP_NAME: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wxGet(ApiMpInfo).then(res=>{
this.setData({
MP_QRCODE: res.data.MP_QRCODE,
MP_NAME: res.data.MP_NAME
})
})
},
copyAction(){
wx.setClipboardData({
data: this.data.MP_NAME,
success(){
showToast("复制成功")
}
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "关注公众号"
}
\ No newline at end of file
<!--pages/mine/official-account.wxml-->
<view class="flex-column">
<view class="container">
<view class="t1">关注公众号</view>
<view class="t2" style="margin-top: 20rpx;margin-bottom: 10rpx;">关注此公众号,了解更多详情</view>
<view class="t2">方法1.扫码关注公众号</view>
<view class="t2">方法2.一键复制公众号,微信搜索关注公众号</view>
<image class="icon" src="{{MP_QRCODE}}"/>
</view>
<view class="copy-text" bindtap="copyAction">一键复制公众号</view>
</view>
/* pages/mine/official-account.wxss */
.container {
width: 690rpx;
height: 776rpx;
background: #FFFFFF;
box-shadow: 0px 4rpx 12rpx 0px rgba(162, 162, 162, 0.1000);
border-radius: 16rpx;
margin: 0 auto;
margin-top: 40rpx;
display: flex;
flex-direction: column;
}
.t1 {
height: 60rpx;
font-size: 44rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 60rpx;
margin-left: 50rpx;
margin-top: 60rpx;
}
.t2 {
height: 40rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 36rpx;
margin-left: 50rpx;
}
.icon {
width: 300rpx;
height: 300rpx;
margin: 0 auto;
margin-top: 100rpx;
}
.copy-text {
width: 90%;
height: 88rpx;
background: var(--primary-color);
border-radius: 44rpx;
text-align: center;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
line-height: 88rpx;
position: fixed;
bottom: 60rpx;
left: 5%;
}
\ No newline at end of file
const { ApiUserInfo, ApiBindPhone } = require("../../http/api")
const { wxGet, wxPost } = require("../../http/network")
// pages/mine/user-info.js
Page({
/**
* 页面的初始数据
*/
data: {
data: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
onShow(){
this.getUserInfo()
},
getUserInfo(){
wxGet(ApiUserInfo).then(res=>{
this.setData({
data: res.data
})
})
},
getPhoneNumber(e) {
wx.showLoading({
title: '绑定中',
})
let that = this
wx.login({
timeout:3000,
success(t){
let param = {
code: t.code,
encryptedData: e.detail.encryptedData,
iv: e.detail.iv
}
wxPost(ApiBindPhone, param).then((res) => {
that.getUserInfo()
wx.hideLoading()
}).catch(()=>{
wx.hideLoading()
})
}
})
},
changePhone(){
wx.navigateTo({
url: './change-phone',
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "个人资料"
}
\ No newline at end of file
<!--pages/mine/user-info.wxml-->
<view class="flex-column">
<view class="item">
<view class="name">头像</view>
<image class="icon" src="{{data.avatar}}"/>
</view>
<view class="line"></view>
<view class="item">
<view class="name">昵称</view>
<view class="name">{{data.userName}}</view>
</view>
<view class="line"></view>
<view class="item">
<view class="name">性别</view>
<view class="name">{{data.sex}}</view>
</view>
<view class="line"></view>
<view class="item">
<view class="name">手机号</view>
<view style="flex: 1;"/>
<view class="name" bindtap="changePhone" style="margin-right: 20rpx;" wx:if="{{data.phone}}">{{data.phone}}</view>
<button class="bind" wx:else bindgetphonenumber="getPhoneNumber" open-type="getPhoneNumber">去绑定</button>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png"/>
</view>
<view class="line" style="height: 20rpx;"></view>
</view>
/* pages/mine/user-info.wxss */
page {
background: white;
}
.item {
width: 690rpx;
height: 110rpx;
background: #FFFFFF;
margin: 0 auto;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.line{
width: 100%;
height: 1px;
background: #F1F1F1;
}
.name {
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 42rpx;
}
.icon{
width: 90rpx;
height: 90rpx;
border-radius: 45rpx;
}
.arrow {
width: 24rpx;
height: 24rpx;
}
.bind{
width: 90rpx;
height: 45rpx;
background: red;
color: white;
font-size: 22rpx;
border-radius: 6rpx;
line-height: 45rpx;
text-align: center;
padding: 0;
margin-right: 15rpx;
}
\ No newline at end of file
const {
ApiOrderDetail,
ApiOrderCancel,
ApiSendOrder,
ApiOrderPay,
ApiFinishOrder
} = require("../../http/api")
const {
wxGet,
wxPost
} = require("../../http/network")
const {
showToast
} = require("../../utils/common")
const app = getApp()
// pages/order/order-detail.js
Page({
/**
* 页面的初始数据
*/
data: {
id: 0,
data: null,
admin: false,
overlayVisible: false,
price: null,
roleType: app.globalData.roleType
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
let id = options.id
let admin = options.admin
if (admin) {
this.setData({
admin: true
})
}
this.setData({
id
})
this.getData()
},
getData() {
wxGet(ApiOrderDetail + this.data.id).then(res => {
this.setData({
data: res.data
})
wx.setNavigationBarTitle({
title: res.data.orderStatusValue
})
})
},
bigAction(e) {
let index = e.currentTarget.dataset.index
wx.previewImage({
urls: this.data.data.demandImgUrls,
current: this.data.data.demandImgUrls[index]
})
},
choosegujia() {
let that = this
wx.navigateTo({
url: '../process/choose?id=' + this.data.id,
events: {
updateData: function (e) {
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
that.getData()
}
}
})
},
fixgujia(){
let that = this
wx.navigateTo({
url: '../process/choose?fix=1&id=' + this.data.id,
events: {
updateData: function (e) {
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
that.getData()
}
}
})
},
cancelAction() {
let that = this
wx.showModal({
title: "温馨提示",
content: "确认取消订单?",
cancelColor: "#3E3E3E",
confirmColor: "#437CFD",
success(e) {
if (e.confirm) {
that.cancelWork()
}
}
})
},
cancelWork() {
let that = this
wxPost(ApiOrderCancel, {
"id": this.data.id
}).then(res => {
wx.showToast({
title: '取消成功',
success() {
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
wx.navigateBack()
}
})
})
},
sendOrder() {
this.setData({
overlayVisible: true
})
},
cancelOverlay() {
this.setData({
overlayVisible: false
})
},
overlayAction() {
if (!this.data.price) {
showToast("请输入金额")
return
}
let that = this
wx.showLoading({
title: '请求中',
})
wxPost(ApiSendOrder, {
"id": this.data.id,
"price": this.data.price
}).then(res => {
showToast("发送成功")
that.setData({
overlayVisible: false
})
that.getData()
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
})
},
payAction() {
let orderId = this.data.id
wx.showLoading({
title: '请求中',
})
wxGet(ApiOrderPay + orderId).then(res => {
this.payWork(res.data.payParam)
})
},
payWork(payParam) {
let that = this
wx.requestPayment({
nonceStr: payParam.nonceStr,
package: payParam.package,
paySign: payParam.paySign,
signType: payParam.signType,
timeStamp: payParam.timeStamp,
success(e) {
that.getData()
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
},
fail(e) {}
})
},
dispatchAction(){
let that = this
wx.navigateTo({
url: '../process/dispatch?id=' + this.data.id,
events: {
updateData: function (e) {
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
that.getData()
}
}
})
},
serviceAction(){
wx.switchTab({
url: '/pages/service/service',
})
},
finishAction(e){
let id = e.detail.orderId
let that = this
wx.showModal({
title: "温馨提示",
content: "确认完成该订单?",
cancelColor: "#3E3E3E",
confirmColor: "#437CFD",
success(e) {
if (e.confirm) {
that.finishWork(id)
}
}
})
},
finishWork(id){
wxPost(ApiFinishOrder,{"id":id}).then(res=>{
showToast("操作成功")
this.getData(true)
})
}
})
\ No newline at end of file
{
"usingComponents": {
},
"navigationBarTitleText": "订单详情",
"navigationBarBackgroundColor": "#437CFD",
"navigationBarTextStyle": "white"
}
\ No newline at end of file
<!--pages/order/order-detail.wxml-->
<wxs module="statusUtil">
function backStatusImage(orderStatus) {
if (orderStatus == 1) {
return '/assets/order/order-dcl.png'
}
if (orderStatus == 3) {
return '/assets/order/order-fk.png'
}
if (orderStatus == 4) {
return '/assets/order/order-dpd.png'
}
if (orderStatus == 5) {
return '/assets/order/order-dfw.png'
}
if (orderStatus == 7) {
return '/assets/order/order-qx.png'
}
if (orderStatus == 6) {
return '/assets/order/order-wc.png'
}
}
module.exports = {
backStatusImage: backStatusImage
}
</wxs>
<view class="h-group">
<view class="h-column">
<image class="h-status-image" src="{{statusUtil.backStatusImage(data.orderStatus)}}" />
<view class="h-status-text">订单{{data.orderStatusValue}}</view>
</view>
</view>
<view class="project-info">
<view class="group-1">
<image class="p-image" src="{{data.subclassImg}}" />
<view class="flex-column" style="flex: 1;">
<view class="group-2">
<view class="g-t1">{{data.serviceName}}</view>
<view class="g-t2">x{{data.num}}</view>
</view>
<view class="g-t3">{{data.createTime}}</view>
</view>
</view>
<view class="g-line" />
<view class="g-info-wrapper">
<view class="g-row">
<view class="i-t1">服务地点:</view>
<view class="i-t2">{{data.address}}</view>
</view>
<view class="g-row">
<view class="i-t1">服务时间:</view>
<view class="i-t2">{{data.expectArrivalTime}}</view>
</view>
<view class="g-row">
<view class="i-t1">联 系 人:</view>
<view class="i-t2">{{data.name}}</view>
</view>
<view class="g-row">
<view class="i-t1">联系电话:</view>
<view class="i-t2">{{data.phone}}</view>
</view>
</view>
</view>
<view class="order-info-wrapper">
<view class="order-top">
<view class="order-t1" />
<view class="order-t2">订单信息</view>
</view>
<view class="g-line" />
<view class="g-row" style="margin: 24rpx 32rpx 0 32rpx;">
<view class="i-t1">订单编号:</view>
<view class="i-t2">{{data.orderNo}}</view>
</view>
<view class="g-row" style="margin: 24rpx 32rpx 0 32rpx;">
<view class="i-t1">创建时间:</view>
<view class="i-t2">{{data.createTime}}</view>
</view>
</view>
<view class="order-info-wrapper">
<view class="order-top">
<view class="order-t1" />
<view class="order-t2">需求说明</view>
</view>
<view class="g-line" />
<view class="thumb-wrapper" wx:if="{{data.demandImgUrls.length > 0}}">
<image class="thumb-item" wx:for="{{data.demandImgUrls}}" wx:key="*this" src="{{item}}" data-index="{{index}}" bindtap="bigAction" mode="aspectFill"/>
</view>
<view class="info-desc">{{data.demandDesc}}</view>
</view>
<view class="log-wrapper">
<view class="log-item" wx:for="{{data.process}}" wx:key="*this">
<view class="log-point-wrapper">
<image class="process-last" src="/assets/order/process-last.png" wx:if="{{index == 0}}" />
<view class="log-point" wx:else />
<view class="log-line" hidden="{{index == data.process.length - 1}}" />
</view>
<view class="log-info-wrapper">
<view class="log-name">{{item.description}}</view>
<view class="log-time">{{item.createTime}}</view>
<view class="log-time" wx:if="{{item.remark}}">{{item.remark}}</view>
</view>
</view>
</view>
<view class="bottom-opt-wrapper" wx:if="{{!admin && (data.price || data.leftTime || data.orderStatus == 3 || data.orderStatus == 6 || data.orderStatus == 5)}}">
<view class="opt-wrapper">
<view class="price" wx:if="{{data.price}}">¥{{data.price}}</view>
<view class="flex-1" />
<view class="djs" wx:if="{{data.leftTime}}">还剩4分25秒</view>
<view class="gujia" wx:if="{{data.orderStatus == 3}}" bindtap="cancelAction">取消订单</view>
<view class="cp-1" wx:if="{{data.orderStatus == 3}}" bindtap="payAction">去支付</view>
<view class="cp-2" wx:if="{{data.orderStatus == 6}}" bindtap="serviceAction">再来一单</view>
<view class="cp-1" wx:if="{{data.orderStatus == 5}}" bindtap="finishAction">完成服务</view>
</view>
</view>
<view class="bottom-opt-wrapper" wx:if="{{admin && data.orderStatus != 7}}">
<view class="opt-wrapper">
<view class="price" wx:if="{{data.price}}">¥{{data.price}}</view>
<view class="flex-1" />
<view class="cp-1" wx:if="{{data.orderStatus == 1 || data.orderStatus == 2}}" bindtap="sendOrder">发送订单</view>
<view class="cp-1" wx:if="{{data.orderStatus == 4 && roleType == 1}}" bindtap="dispatchAction">派单</view>
<view class="gujia" wx:if="{{data.orderStatus == 1 && roleType == 1}}" bindtap="choosegujia">现场估价</view>
<view class="gujia" wx:if="{{data.orderStatus == 2 && roleType == 1}}" bindtap="fixgujia">修改估价员</view>
<view class="gujia" wx:if="{{(data.orderStatus == 1 || data.orderStatus == 3) && roleType == 1}}" bindtap="cancelAction">取消订单</view>
<view class="cp-1" wx:if="{{data.orderStatus == 5 && roleType == 1}}" bindtap="finishAction">完成服务</view>
</view>
</view>
<view wx:if="{{overlayVisible}}" class="overlay">
<view class="overlay-wrapper">
<view class="overlay-title">订单发送</view>
<view class="overlay-input-wrapper">
<input class="overlay-input" placeholder="输入金额" type="digit" model:value="{{price}}"></input>
<view class="yuan">元</view>
</view>
<view class="flex-1"></view>
<view class="overlay-line"></view>
<view class="overlay-btns">
<view class="overlay-btn" bindtap="cancelOverlay">取消</view>
<view class="overlay-btn" style="color: #437CFD;" bindtap="overlayAction">确定</view>
</view>
</view>
</view>
\ No newline at end of file
/* pages/order/order-detail.wxss */
page {
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
}
.h-group {
width: 750rpx;
height: 170rpx;
background: #437CFD;
}
.h-column {
display: flex;
flex-direction: row;
}
.h-status-image {
width: 34rpx;
height: 34rpx;
margin-top: 38rpx;
margin-left: 38rpx;
}
.h-status-text {
height: 34rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 34rpx;
margin-top: 38rpx;
margin-left: 20rpx;
}
.project-info {
width: 690rpx;
min-height: 482rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin: 0 auto;
margin-top: -50rpx;
display: flex;
flex-direction: column;
}
.group-1 {
height: 222rpx;
margin: 0 32rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.p-image {
width: 164rpx;
height: 164rpx;
border-radius: 4rpx;
}
.group-2 {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-left: 20rpx;
align-items: center;
flex: 1;
}
.g-t1 {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
}
.g-t2 {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 36rpx;
}
.g-t3 {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 34rpx;
margin-left: 20rpx;
margin-top: 10rpx;
}
.g-line {
width: 626rpx;
height: 1px;
background: #F1F1F1;
margin: 0 auto;
}
.g-info-wrapper {
width: 626rpx;
display: flex;
flex-direction: column;
margin: 0 auto;
}
.g-row {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 24rpx;
}
.i-t1 {
width: 120rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 36rpx;
flex-shrink: 0;
}
.i-t2 {
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 36rpx;
flex-wrap: wrap;
word-break: break-all;
}
.order-info-wrapper {
width: 690rpx;
min-height: 240rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin: 0 auto;
margin-top: 20rpx;
display: flex;
flex-direction: column;
}
.order-top {
height: 88rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.order-t1 {
width: 8rpx;
height: 20rpx;
background: #437CFD;
margin-left: 32rpx;
}
.order-t2 {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
margin-left: 20rpx;
}
.thumb-wrapper {
width: 626rpx;
display: flex;
flex-direction: row;
margin: 20rpx auto;
flex-wrap: wrap;
}
.thumb-item {
width: 160rpx;
height: 160rpx;
border-radius: 8rpx;
margin-right: 20rpx;
margin-bottom: 15rpx;
}
.info-desc {
width: 628rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 36rpx;
word-break: break-all;
margin: 0 auto;
margin-top: 20rpx;
margin-bottom: 40rpx;
}
.log-wrapper {
width: 630rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin: 0 auto;
padding: 30rpx;
margin-top: 30rpx;
display: flex;
flex-direction: column;
}
.log-item {
display: flex;
flex-direction: row;
}
.log-point-wrapper {
display: flex;
flex-direction: column;
align-items: center;
width: 60rpx;
}
.log-point {
width: 20rpx;
height: 20rpx;
background: #D8D8D8;
border-radius: 10rpx;
}
.log-line {
flex: 1;
width: 1px;
background: #D8D8D8;
}
.log-info-wrapper {
display: flex;
flex-direction: column;
margin-bottom: 40rpx;
}
.log-name {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 34rpx;
word-break: break-all;
}
.log-time {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 34rpx;
margin-top: 6rpx;
}
.bottom-opt-wrapper {
width: 750rpx;
height: calc(110rpx + env(safe-area-inset-bottom));
position: fixed;
left: 0;
bottom: 0;
z-index: 2;
background-color: white;
}
.opt-wrapper {
height: 110rpx;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 30rpx;
}
.cp-1 {
width: 148rpx;
height: 60rpx;
background: #437CFD;
border-radius: 34rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 60rpx;
text-align: center;
margin-left: 20rpx;
}
.djs {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #437CFD;
line-height: 36rpx;
}
.cp-2 {
width: 148rpx;
height: 60rpx;
background: #F1F1F1;
border-radius: 34rpx;
margin-left: 20rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #828282;
line-height: 60rpx;
text-align: center;
}
.price {
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FF5A47;
line-height: 42rpx;
margin-right: 30rpx;
}
.process-last {
width: 30rpx;
height: 30rpx;
}
.gujia {
width: 160rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 34px;
border: 1px solid #437CFD;
margin-left: 20rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #437CFD;
line-height: 60rpx;
text-align: center;
}
.overlay {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.4);
z-index: 99;
display: flex;
justify-content: center;
}
.overlay-wrapper {
width: 600rpx;
height: 368rpx;
background: #FFFFFF;
border-radius: 24rpx;
margin-top: 300rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.overlay-title {
width: 100%;
height: 124rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 124rpx;
text-align: center;
}
.overlay-input-wrapper {
width: 408rpx;
height: 92rpx;
background: #EEEEEE;
border-radius: 8rpx;
display: flex;
flex-direction: row;
}
.overlay-input {
flex: 1;
height: 100%;
padding: 0 20rpx;
}
.yuan {
width: 92rpx;
height: 92rpx;
background: #E2E2E2;
border-radius: 0px 8rpx 8rpx 0px;
text-align: center;
line-height: 92rpx;
}
.overlay-line {
width: 598rpx;
height: 1px;
background-color: #F1F1F1;
}
.overlay-btns {
width: 100%;
height: 96rpx;
display: flex;
flex-direction: row;
}
.overlay-btn {
flex: 1;
height: 96rpx;
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 96rpx;
text-align: center;
}
\ No newline at end of file
const { ApiOrderList, ApiOrderPay,ApiOrderCancel,ApiFinishOrder } = require("../../http/api")
const { wxPost, wxGet } = require("../../http/network")
const { showToast } = require("../../utils/common")
// pages/order/order-list.js
var page = 1
Page({
/**
* 页面的初始数据
*/
data: {
orderStatus: 0,
triggered: false,
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
page = 1
let orderStatus = options.orderStatus
this.setData({
orderStatus
})
this.getData(true)
},
bindscrolltolower(e){
if(!this.canLoadMore)return
if (this._freshing) return
this._freshing = true
this.getData(false)
},
statusChange(e){
let index = e.currentTarget.dataset.index
this.setData({
orderStatus: index,
list: null
})
this.getData(true)
},
getData(refresh){
if (refresh) {
page = 1
}else{
page+=1
}
let that = this
wxPost(ApiOrderList, {
"page": page,
"orderStatus": this.data.orderStatus
}).then(res => {
var list = this.data.list
if (refresh) {
list = res.data.list
} else {
list = list.concat(res.data.list)
}
this.setData({
list
})
this.canLoadMore = res.data.hasNextPage
}).catch(()=>{
}).finally(()=>{
that.setData({
triggered: false,
})
that._freshing = false
})
},
onPulling(e) {
console.log('onPulling:', e)
},
onRefresh() {
if (this._freshing) return
this._freshing = true
this.setData({
triggered: true,
})
this.getData(true)
},
onRestore(e) {
console.log('onRestore:', e)
},
onAbort(e) {
console.log('onAbort', e)
},
itemClickAction(e){
let id = e.currentTarget.dataset.id
wx.navigateTo({
url: './order-detail?id='+id,
})
},
cancelAction(e) {
let id = e.detail.orderId
let that = this
wx.showModal({
title: "温馨提示",
content: "确认取消订单?",
cancelColor: "#3E3E3E",
confirmColor: "#437CFD",
success(e) {
if (e.confirm) {
that.cancelWork(id)
}
}
})
},
cancelWork(id){
wxPost(ApiOrderCancel,{"id":id}).then(res=>{
showToast("取消成功")
this.getData(true)
})
},
payAction(e){
let orderId = e.detail.orderId
wx.showLoading({
title: '请求中',
})
wxGet(ApiOrderPay + orderId).then(res=>{
wx.hideLoading()
this.payWork(res.data.payParam)
})
},
payWork(payParam){
let that = this
wx.requestPayment({
nonceStr: payParam.nonceStr,
package: payParam.package,
paySign: payParam.paySign,
signType: payParam.signType,
timeStamp: payParam.timeStamp,
success(e){
that.getData(true)
},
fail(e){
}
})
},
serviceAction(){
wx.switchTab({
url: '/pages/service/service',
})
},
finishAction(e){
let id = e.detail.orderId
let that = this
wx.showModal({
title: "温馨提示",
content: "确认完成该订单?",
cancelColor: "#3E3E3E",
confirmColor: "#437CFD",
success(e) {
if (e.confirm) {
that.finishWork(id)
}
}
})
},
finishWork(id){
wx.showLoading({
title: '请求中',
})
wxPost(ApiFinishOrder,{"id":id}).then(res=>{
wx.hideLoading()
showToast("操作成功")
this.getData(true)
})
}
})
\ No newline at end of file
{
"usingComponents": {
"order-item": "/components/order-item/order-item",
"empty-view":"/components/empty-view/empty-view"
},
"navigationBarTitleText": "我的订单"
}
\ No newline at end of file
<!--pages/order/order-list.wxml-->
<view class="tab-wrapper">
<view class="tab-item" bindtap="statusChange" data-index="0">
<view class="tab-text">全部</view>
<view class="bottom-line" wx:if="{{orderStatus == 0}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="1">
<view class="tab-text">待受理</view>
<view class="bottom-line" wx:if="{{orderStatus == 1}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="3">
<view class="tab-text">待支付</view>
<view class="bottom-line" wx:if="{{orderStatus == 3}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="4">
<view class="tab-text">待派单</view>
<view class="bottom-line" wx:if="{{orderStatus == 4}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="5">
<view class="tab-text">服务中</view>
<view class="bottom-line" wx:if="{{orderStatus == 5}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="6">
<view class="tab-text">已完成</view>
<view class="bottom-line" wx:if="{{orderStatus == 6}}" />
</view>
</view>
<empty-view imageName="/assets/order/order-empty.png" wx:if="{{list.length == 0}}">
</empty-view>
<scroll-view wx:else scroll-y class="sc-list" refresher-enabled="{{true}}" refresher-threshold="{{100}}" refresher-default-style="black" refresher-triggered="{{triggered}}" bindrefresherpulling="onPulling" bindrefresherrefresh="onRefresh" bindrefresherrestore="onRestore" bindrefresherabort="onAbort" bindscrolltolower="bindscrolltolower">
<order-item wx:for="{{list}}" wx:key="*this" item-data="{{item}}" bindtap="itemClickAction" data-id="{{item.id}}" bind:payAction="payAction" bind:cancelAction="cancelAction" bind:finishAction="finishAction" bind:serviceAction="serviceAction"></order-item>
</scroll-view>
/* pages/order/order-list.wxss */
.tab-wrapper {
width: 750rpx;
height: 110rpx;
background: #FFFFFF;
display: flex;
flex-direction: row;
}
.tab-item {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.tab-text {
height: 106rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 106rpx;
}
.bottom-line {
width: 50rpx;
height: 4rpx;
background: #437CFD;
border-radius: 2rpx;
}
.sc-list{
width: 100%;
height: calc(100vh - 120rpx);
padding-top: 10rpx;
}
\ No newline at end of file
// pages/order/order-result.js
Page({
/**
* 页面的初始数据
*/
data: {
data: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
let data = JSON.parse(decodeURIComponent(options.data))
this.setData({
data
})
},
backHome(){
wx.switchTab({
url: '/pages/home/home',
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "预约结果"
}
\ No newline at end of file
<!--pages/order/order-result.wxml-->
<view class="content-wrapper">
<image src="/assets/order/order-success.png" class="order-success"/>
<view class="success-text">预约成功</view>
<view class="project-item">
<view class="project-text">预约人姓名:</view>
<view class="project-text text-black">{{data.name}}</view>
</view>
<view class="project-item">
<view class="project-text">手机号码:</view>
<view class="project-text text-black">{{data.phone}}</view>
</view>
<view class="project-item">
<view class="project-text">服务类型:</view>
<view class="project-text text-black">{{data.serviceName}}</view>
</view>
<view class="project-item">
<view class="project-text">数 量:</view>
<view class="project-text text-black">{{data.num}}</view>
</view>
</view>
<view style="flex: 1;"/>
<view class="back-btn" bindtap="backHome">返回首页</view>
/* pages/order/order-result.wxss */
page{
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
}
.content-wrapper {
width: 750rpx;
height: 700rpx;
background: #FFFFFF;
display: flex;
flex-direction: column;
align-items: center;
}
.order-success {
width: 220rpx;
height: 220rpx;
margin-top: 30rpx;
}
.success-text {
height: 50rpx;
font-size: 36rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 50rpx;
}
.project-item {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
margin-top: 40rpx;
}
.project-text {
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #828282;
line-height: 42rpx;
margin-left: 30rpx;
}
.text-black {
color: #3E3E3E;
margin-right: 30rpx;
}
.back-btn{
width: 690rpx;
height: 88rpx;
background: #437CFD;
border-radius: 44rpx;
text-align: center;
line-height: 88rpx;
font-size: 32rpx;
color: white;
margin-bottom: calc(26rpx + env(safe-area-inset-bottom));
}
\ No newline at end of file
const { ApiDefAddrInfo, ApiOrder } = require("../../http/api");
const { wxUpload, wxGet, wxPost } = require("../../http/network");
const { showToast } = require("../../utils/common");
// pages/order/order-service.js
Page({
/**
* 页面的初始数据
*/
data: {
serviceInfo: null,
expectArrivalTime: "",
num: 1,
urls: [],
visible: false,
read: false,
demandDesc: "",
addressId: 0,
addrData: null,
tips: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.picker = this.selectComponent("#picker")
let infoStr = decodeURIComponent(options.info)
this.setData({
serviceInfo: JSON.parse(infoStr)
})
this.getAddrDef()
},
getAddrDef(){
let that = this
wxGet(ApiDefAddrInfo).then(res=>{
if(res.data.id){
that.setData({
addressId: res.data.id,
addrData: res.data,
tips: res.data.tips
})
}
})
},
timeOpen() {
this.picker.showDialog();
},
confirm(e) {
this.setData({
expectArrivalTime: e.detail.selectDate
})
},
subtractAction(){
if(this.data.num == 1)return
this.setData({
num: this.data.num - 1
})
},
addAction(){
this.setData({
num: this.data.num + 1
})
},
chooseImage(){
this.setData({
visible: true
})
},
dismissChoose(){
this.setData({
visible: false
})
},
takePhoto(){
let that = this
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['camera'],
camera: 'back',
success(res) {
let path = res.tempFiles[0].tempFilePath
that.uploadFileAction(path)
}
})
this.dismissChoose()
},
openPhoto(){
let that = this
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album'],
camera: 'back',
success(res) {
let path = res.tempFiles[0].tempFilePath
that.uploadFileAction(path)
}
})
this.dismissChoose()
},
uploadFileAction(path){
wx.showLoading({
title: '上传中',
})
let that = this
wxUpload(path,"IMG").then(res=>{
showToast("上传成功")
let urls = that.data.urls
urls.push(res.data.urls[0])
that.setData({
urls
})
}).finally(()=>{
wx.hideLoading()
})
},
deleteAction(e){
let index = e.currentTarget.dataset.index
console.log(index)
let urls = this.data.urls
urls.splice(index,1)
this.setData({
urls
})
},
readAction(){
let read = this.data.read
this.setData({
read: !read
})
},
descChange(e){
this.setData({
demandDesc: e.detail.value
})
},
changeAddr(){
let that = this
wx.navigateTo({
url: '../address/index?path=order',
events:{
getBackData:res=>{
that.setData({
addrData: res,
addressId: res.id
})
}
}
})
},
orderSubmit(){
if(this.data.addressId == 0){
showToast("请选择服务地址")
return
}
if(this.data.expectArrivalTime == ""){
showToast("请选择上门时间")
return
}
if(this.data.urls.length == 0){
showToast("请上传图片")
return
}
if(this.data.demandDesc.length == 0){
showToast("请输入需求说明")
return
}
if(!this.data.read){
showToast("请勾选我已阅读协议")
return
}
let date = this.data.expectArrivalTime
let param = {
addressId: this.data.addressId,
demandDesc: this.data.demandDesc,
expectArrivalTime: date,
num: this.data.num,
readAgreement: true,
subclassId: this.data.serviceInfo.id,
urls: this.data.urls
}
wx.showLoading()
let that = this
wxPost(ApiOrder,param).then(res=>{
wx.hideLoading()
wx.showToast({
icon: "none",
title: "预约成功",
success(){
let data = {
name: that.data.addrData.name,
phone: that.data.addrData.phone,
serviceName: that.data.serviceInfo.serviceName,
num: that.data.num
}
wx.navigateTo({
url: './order-result?data=' + encodeURIComponent(JSON.stringify(data)),
})
}
})
}).catch(()=>{
wx.hideLoading()
})
},
agreementAction(){
wx.navigateTo({
url: '../service/service-agreement',
})
}
})
\ No newline at end of file
{
"usingComponents": {
"t-popup": "tdesign-miniprogram/popup/popup",
"date-picker": "/components/date-picker/date-picker"
},
"navigationBarTitleText": "预约服务"
}
\ No newline at end of file
<!--pages/order/order-service.wxml-->
<view class="flex-column">
<view class="select-address flex-column" bindtap="changeAddr">
<view style="flex: 1;" />
<view class="select-address-top">
<view class="vbig-name">{{addressId == 0 ? '服务地址' : '姓名:' + addrData.name}}</view>
<view class="address-phone">{{addrData.phone}}</view>
</view>
<view class="select-address-center">
<view class="address-info">{{addressId == 0 ? '请选择服务地址及联系人' : addrData.namePath + addrData.address}}</view>
<image class="address-arrow" src="/assets/mine/urban-arrow-gray.png" />
</view>
<view style="flex: 1;" />
<image src="/assets/address/address-split.png" class="address-split" />
</view>
<view class="time-wrapper" bindtap="timeOpen">
<view class="vbig-name">{{expectArrivalTime.length == 0 ? '期望上门时间' : expectArrivalTime}}</view>
<image class="address-arrow" src="/assets/mine/urban-arrow-gray.png" />
</view>
<view class="service-wrapper">
<view class="vbig-name tp-h">服务详情</view>
<view class="service-info">
<image class="service-icon" mode="aspectFill" src="{{serviceInfo.img}}" />
<view class="service-dt">
<view class="vbig-name" style="margin: 0;">{{serviceInfo.serviceName}}</view>
<view class="service-dt-desc">{{serviceInfo.description}}</view>
</view>
</view>
</view>
<view class="time-wrapper">
<view class="vbig-name">数量</view>
<view class="flex-1" />
<image class="image-opt" src="/assets/order/order-sup.png" bindtap="subtractAction"/>
<view class="num">{{num}}</view>
<image class="image-opt" style="margin-right: 30rpx;" src="/assets/order/order-add.png" bindtap="addAction"/>
</view>
<view class="project-wrapper">
<view class="vbig-name" style="margin-top: 30rpx;">需求说明</view>
<view class="thumb-wrapper">
<view class="upload-image-wrapper" wx:for="{{urls}}" wx:key="*this">
<image class="upload-image" src="{{item}}"/>
<image class="upload-del" src="/assets/order/upload-del.png" bindtap="deleteAction" data-index="{{index}}"/>
</view>
<image bindtap="chooseImage" class="thubm-item" wx:if="{{urls.length < 8}}" src="/assets/order/add-thumb.png" wx:key="*this"/>
</view>
<view class="desc-wrapper">
<textarea placeholder="您的需求,请在此填写~" class="desc-textarea" bindinput="descChange"></textarea>
</view>
</view>
<view class="agreement-wrapper">
<image class="agreement-icon" src="{{read ? '/assets/order/agreement-selected.png' : '/assets/order/agreement-unselected.png'}}" bindtap="readAction"/>
<view class="agreement-text" bindtap="readAction">我已阅读</view>
<view class="agreement-text" style="color: #437CFD;" bindtap="agreementAction">《家政服务协议》</view>
</view>
<rich-text class="node-class" nodes="{{tips}}"></rich-text>
<view class="bmt">
<view class="bmt-order" bindtap="orderSubmit">立即预约</view>
</view>
</view>
<t-popup visible="{{visible}}" placement="bottom">
<view slot="content" class="pop-wrapper">
<view class="pop-top">
<view class="top-text">上传图片</view>
</view>
<view class="pop-center">
<view class="top-text" style="margin-top: 24rpx;">照片拍摄完整,师傅才能更好的了解需求</view>
<view style="flex: 1;" />
<view class="image-tip-wrapper">
<view class="tip-item">
<image class="tip-image" src="/assets/order/tip-1.png" />
<view class="tip-text">全景图</view>
</view>
<view class="tip-item">
<image class="tip-image" src="/assets/order/tip-2.png" />
<view class="tip-text">局部图</view>
</view>
<view class="tip-item">
<image class="tip-image" src="/assets/order/tip-3.png" />
<view class="tip-text">侧面图</view>
</view>
</view>
</view>
<view class="pop-line" />
<view class="pop-action-text" bindtap="takePhoto">拍摄照片</view>
<view class="pop-action-text" bindtap="openPhoto">从相册选择照片</view>
<view class="pop-line" style="margin:0" />
<view class="pop-action-text" style="border: none;" bindtap="dismissChoose">取消</view>
</view>
</t-popup>
<date-picker id="picker" range="8" step="40" bindconfirm="confirm"></date-picker>
/* pages/order/order-service.wxss */
page {
padding-bottom: env(safe-area-inset-bottom);
}
.select-address {
width: 750rpx;
height: 166rpx;
background: #FFFFFF;
justify-content: center;
}
.select-address-top {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.select-address-center {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-top: 8rpx;
}
.vbig-name {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
margin-left: 30rpx;
}
.address-phone {
height: 44rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 44rpx;
margin-right: 30rpx;
}
.address-arrow {
width: 22rpx;
height: 22rpx;
margin-right: 30rpx;
}
.address-info {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #828282;
line-height: 40rpx;
margin-left: 30rpx;
}
.address-split {
width: 100%;
height: 10rpx;
}
.time-wrapper {
width: 750rpx;
height: 120rpx;
background: #FFFFFF;
box-shadow: inset 0px -1px 0px 0px #F1F1F1;
margin: 20rpx 0;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.service-wrapper {
width: 750rpx;
height: 328rpx;
background: #FFFFFF;
box-shadow: inset 0px -1px 0px 0px #F1F1F1;
display: flex;
flex-direction: column;
}
.tp-h {
height: 112rpx;
line-height: 112rpx;
}
.service-info {
display: flex;
flex-direction: row;
}
.service-icon {
width: 240rpx;
height: 180rpx;
margin-left: 30rpx;
}
.service-dt {
display: flex;
flex-direction: column;
margin-left: 34rpx;
justify-content: center;
}
.service-dt-desc {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #828282;
line-height: 34rpx;
margin-top: 14rpx;
}
.image-opt {
width: 40rpx;
height: 40rpx;
}
.num {
width: 100rpx;
text-align: center;
}
.project-wrapper {
width: 750rpx;
min-height: 676rpx;
background: #FFFFFF;
box-shadow: inset 0px -1px 0px 0px #F1F1F1;
display: flex;
flex-direction: column;
}
.thumb-wrapper {
margin: 0 30rpx;
display: flex;
flex-direction: row;
margin-top: 30rpx;
flex-wrap: wrap;
}
.thubm-item {
width: 156rpx;
height: 156rpx;
margin-bottom: 20rpx;
}
.upload-image-wrapper{
width: 172rpx;
height: 172rpx;
margin-bottom: 20rpx;
position: relative;
}
.upload-image{
width: 156rpx;
height: 156rpx;
position: absolute;
left: 0;
top: 0;
}
.upload-del{
width: 36rpx;
height: 36rpx;
position: absolute;
right: 2rpx;
top: -14rpx;
z-index: 10;
}
.desc-wrapper {
width: 690rpx;
height: 326rpx;
background: #F7F7F7;
border-radius: 16rpx;
border: 2rpx solid #EEEEEE;
margin: 0 auto;
margin-top: 20rpx;
margin-bottom: 20rpx;
}
.node-class{
padding: 30rpx;
}
.desc-textarea {
margin: 24rpx 30rpx;
font-size: 28rpx;
}
.agreement-wrapper {
display: flex;
flex-direction: row;
margin-top: 30rpx;
margin-left: 30rpx;
height: 34rpx;
align-items: center;
}
.agreement-icon {
width: 30rpx;
height: 30rpx;
margin-right: 20rpx;
}
.agreement-text {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 34rpx;
}
.bmt {
width: 750rpx;
height: 128rpx;
background: #FFFFFF;
margin-top: 40rpx;
display: flex;
justify-content: flex-end;
align-items: center;
}
.bmt-order {
width: 320rpx;
height: 88rpx;
background: #437CFD;
border-radius: 44rpx;
text-align: center;
line-height: 88rpx;
color: white;
margin-right: 30rpx;
}
.pop-wrapper {
width: 750rpx;
height: 814rpx;
background: #FFFFFF;
border-radius: 24rpx 24rpx 0px 0px;
display: flex;
flex-direction: column;
padding-bottom: env(safe-area-inset-bottom);
}
.pop-top {
width: 100%;
height: 160rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.top-text {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
text-align: center;
width: 100%;
}
.top-close {
width: 32rpx;
height: 32rpx;
margin-right: 30rpx;
}
.pop-hb {
width: 32rpx;
height: 32rpx;
margin-left: 30rpx;
}
.pop-center {
width: 690rpx;
height: 286rpx;
background: rgba(231, 231, 231, 0.7);
border-radius: 10rpx;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
}
.image-tip-wrapper {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 100%;
}
.tip-item {
width: 174rpx;
height: 190rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.tip-image {
width: 174rpx;
height: 102rpx;
}
.tip-text {
height: 88rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 88rpx;
}
.pop-line {
width: 750rpx;
height: 16rpx;
background: #F8F8F8;
margin-top: 30rpx;
}
.pop-action-text {
width: 750rpx;
height: 102rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 102rpx;
text-align: center;
border-bottom: 1px solid #F1F1F1;
}
\ No newline at end of file
const { ApiOrderValuator, ApiRevaluator } = require("../../http/api")
const { wxPost } = require("../../http/network")
const { showToast } = require("../../utils/common")
// pages/process/choose.js
Page({
/**
* 页面的初始数据
*/
data: {
valuator: null,
expectArrivalTime: null,
remark: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.picker = this.selectComponent("#picker")
this.id = options.id
this.fix = options.fix
},
chooseAction(){
let that = this
wx.navigateTo({
url: './user-list?type=1',
events:{
infoBack:function(e){
that.setData({
valuator: e
})
}
}
})
},
chooseTime(){
this.picker.showDialog();
},
confirm(e) {
this.setData({
expectArrivalTime: e.detail.selectDate
})
},
remarkInput(e){
this.setData({
remark: e.detail.value
})
},
submitAction(){
if(this.data.valuator == null){
showToast("请选择估价员")
return
}
if(this.data.expectArrivalTime == null){
showToast("请选择上门时间")
return
}
let that = this
let date = this.data.expectArrivalTime
let url = ApiOrderValuator
if(this.fix){
url = ApiRevaluator
}
wxPost(url,{
expectArrivalTime: date,
hostId: this.data.valuator.id,
id: this.id,
remark: this.data.remark
}).then(res=>{
wx.showToast({
icon: 'none',
title: '提交成功',
success(){
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
wx.navigateBack()
}
})
})
}
})
\ No newline at end of file
{
"usingComponents": {
"date-picker": "/components/date-picker/date-picker"
},
"navigationBarTitleText": "现场估价"
}
\ No newline at end of file
<!--pages/process/choose.wxml-->
<view class="flex-column column-center">
<view class="g-1 row" bindtap="chooseAction">
<view class="g-text">选择估价员</view>
<view class="flex-1" />
<view class="g-name">{{valuator ? valuator.name : '请选择'}}</view>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png" />
</view>
<view class="g-1 row" bindtap="chooseTime">
<view class="g-text">选择上门时间</view>
<view class="flex-1" />
<view class="g-name">{{expectArrivalTime ? expectArrivalTime : '请选择'}}</view>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png" />
</view>
<view class="remark-wrapper">
<textarea class="t-area" placeholder="请输入备注信息" bindinput="remarkInput" />
</view>
</view>
<view class="submit-text" bindtap="submitAction">提交</view>
<date-picker id="picker" range="8" step="40" bindconfirm="confirm"></date-picker>
\ No newline at end of file
/* pages/process/choose.wxss */
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.g-1 {
width: 690rpx;
height: 120rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin-top: 20rpx;
}
.arrow {
width: 24rpx;
height: 24rpx;
margin-right: 30rpx;
}
.g-text {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
margin-left: 30rpx;
}
.g-name {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-right: 15rpx;
}
.remark-wrapper {
width: 690rpx;
height: 220rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
.t-area {
width: 650rpx;
height: 180rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
}
.submit-text {
width: 690rpx;
height: 88rpx;
background: var(--primary-color);
border-radius: 44rpx;
text-align: center;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
line-height: 88rpx;
position: absolute;
left: 30rpx;
bottom: 60rpx;
}
\ No newline at end of file
const { ApiDispatch } = require("../../http/api")
const { wxPost } = require("../../http/network")
// pages/process/dispatch.js
Page({
/**
* 页面的初始数据
*/
data: {
valuator: null,
remark: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.id = options.id
},
chooseAction(){
let that = this
wx.navigateTo({
url: './user-list?type=2',
events:{
infoBack:function(e){
that.setData({
valuator: e
})
}
}
})
},
remarkInput(e){
this.setData({
remark: e.detail.value
})
},
submitAction(){
if(this.data.valuator == null){
showToast("请选择维修员")
return
}
let that = this
wxPost(ApiDispatch,{
hostId: this.data.valuator.id,
id: this.id,
remark: this.data.remark
}).then(res=>{
wx.showToast({
icon: 'none',
title: '提交成功',
success(){
let eventChannel = that.getOpenerEventChannel()
eventChannel.emit("updateData")
wx.navigateBack()
}
})
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "派单"
}
\ No newline at end of file
<!--pages/process/dispatch.wxml-->
<view class="flex-column column-center">
<view class="g-1 row" bindtap="chooseAction">
<view class="g-text">选择维修员</view>
<view class="flex-1"/>
<view class="g-name">{{valuator ? valuator.name : '请选择'}}</view>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png"/>
</view>
<view class="remark-wrapper">
<textarea class="t-area" placeholder="请输入备注信息" bindinput="remarkInput"/>
</view>
</view>
<view class="submit-text" bindtap="submitAction">提交</view>
/* pages/process/dispatch.wxss */
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.g-1 {
width: 690rpx;
height: 120rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin-top: 20rpx;
}
.arrow {
width: 24rpx;
height: 24rpx;
margin-right: 30rpx;
}
.g-text {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
margin-left: 30rpx;
}
.g-name {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-right: 15rpx;
}
.remark-wrapper {
width: 690rpx;
height: 220rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
.t-area {
width: 650rpx;
height: 180rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
}
.submit-text {
width: 690rpx;
height: 88rpx;
background: var(--primary-color);
border-radius: 44rpx;
text-align: center;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
line-height: 88rpx;
position: absolute;
left: 30rpx;
bottom: 60rpx;
}
\ No newline at end of file
const { ApiValuator, ApiWorker } = require("../../http/api")
const { wxGet } = require("../../http/network")
const { showToast } = require("../../utils/common")
// pages/process/user-list.js
Page({
/**
* 页面的初始数据
*/
data: {
name: "",
list: [],
selected: -1
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
//1 估价 2派单
this.type = options.type
if(this.type == 1){
wx.setNavigationBarTitle({
title: '选择估价员',
})
this.getValuatorList()
}
if(this.type == 2){
wx.setNavigationBarTitle({
title: '选择维修员',
})
this.getWorkList()
}
},
getValuatorList(){
wxGet(ApiValuator,{name:this.data.name}).then(res=>{
this.setData({
list: res.data
})
})
},
getWorkList(){
wxGet(ApiWorker,{name:this.data.name}).then(res=>{
this.setData({
list: res.data
})
})
},
chooseAction(e){
let index = e.currentTarget.dataset.index
this.setData({
selected: index
})
},
submitAction(){
if(this.data.selected == -1){
if(this.type == 1){
showToast("请选择估价员")
}
if(this.type == 2){
showToast("请选择维修员")
}
return
}
let info = this.data.list[this.data.selected]
let eventChannel = this.getOpenerEventChannel()
eventChannel.emit("infoBack",info)
wx.navigateBack()
},
nameInputChange(e){
this.getValuatorList()
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "人员列表"
}
\ No newline at end of file
<!--pages/process/user-list.wxml-->
<view class="header">
<view class="input-wrapper">
<image class="search" src="/assets/main/urban-search.png" />
<input class="search-input" placeholder="请输入关键字搜索人员" placeholder-style="color:#9B9B9B" model:value="{{name}}" bindinput="nameInputChange"/>
</view>
</view>
<scroll-view class="sc-list">
<view class="user-item" wx:for="{{list}}" wx:key="*this" bindtap="chooseAction" data-index="{{index}}">
<view class="user-info-wrapper">
<view class="flex-column flex-1">
<view class="info-text">姓名:{{item.name}}</view>
<view class="info-text">电话:{{item.phone}}</view>
</view>
<image class="check" src="{{selected == index ? '/assets/order/agreement-selected.png' : '/assets/order/agreement-unselected.png'}}"/>
</view>
<view class="time-wrapper" wx:if="{{item.assignTime.length > 0}}">
<view class="time-content">
<view class="time-item">已派时间:2021.07.30 09:00</view>
</view>
</view>
</view>
</scroll-view>
<view class="submit-text" bindtap="submitAction">确认</view>
/* pages/process/user-list.wxss */
.header {
width: 750rpx;
height: 110rpx;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
.input-wrapper {
width: 690rpx;
height: 70rpx;
background: #F7F7F7;
border-radius: 35rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.search {
width: 32rpx;
height: 32rpx;
margin-left: 30rpx;
}
.search-input {
margin-left: 10rpx;
height: 70rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3e3e3e;
line-height: 70rpx;
flex: 1;
}
.sc-list {
width: 100%;
height: calc(100vh - 70rpx);
}
.user-item {
width: 690rpx;
min-height: 156rpx;
background: #FFFFFF;
border-radius: 16rpx;
margin: 0 auto;
margin-top: 20rpx;
display: flex;
flex-direction: column;
}
.user-info-wrapper {
width: 690rpx;
height: 156rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.check {
width: 32rpx;
height: 33rpx;
margin-right: 32rpx;
}
.info-text {
height: 52rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 52rpx;
margin-left: 32rpx;
}
.time-wrapper {
display: flex;
flex-direction: column;
width: 626rpx;
border-top: 1px solid #F1F1F1;
margin: 0 auto;
}
.time-content {
width: 626rpx;
background: #F5F5F5;
border-radius: 4rpx;
margin-top: 20rpx;
margin-bottom: 30rpx;
padding: 10rpx 0;
}
.time-item {
height: 40rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
margin-left: 20rpx;
margin-top: 10rpx;
}
.submit-text {
width: 690rpx;
height: 88rpx;
background: var(--primary-color);
border-radius: 44rpx;
text-align: center;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
line-height: 88rpx;
position: absolute;
left: 30rpx;
bottom: 60rpx;
}
\ No newline at end of file
// pages/search/index.js
import api, { ApiSearch } from '../../http/api'
import {
wxGet
} from '../../http/network'
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
list: null,
keywordList: [],
keyword: ''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let keywordList = wx.getStorageSync('keywordList')
this.setData({
keywordList
})
},
// 开始搜索
bindconfirm(){
let keyword = this.data.keyword
keyword = keyword.replace(/(\s*$)/g,"")
if(keyword.length == 0){
wx.showToast({
icon: 'none',
title: '请输入关键词',
})
return
}
let that = this
let keywordList = this.data.keywordList
if(keywordList == ''){
keywordList = []
}
let index = keywordList.indexOf(keyword);
if(index != -1){
keywordList.splice(index ,1)
}
keywordList.unshift(keyword)
this.setData({
keywordList
})
wx.setStorageSync('keywordList', keywordList)
wxGet(ApiSearch,{"keyWord":keyword}).then((res)=>{
that.setData({
list: res.data
})
})
},
// 清空记录
clearAction(){
wx.removeStorageSync('keywordList')
this.setData({
keywordList: []
})
},
historyItemClick(e){
console.log(e)
let name = e.currentTarget.dataset.name
this.setData({
keyword: name
})
this.bindconfirm()
},
itemClick(e){
let id = e.currentTarget.dataset.id
app.globalData.cateId = id
wx.switchTab({
url: '/pages/service/service',
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "搜索"
}
\ No newline at end of file
<!--pages/search/index.wxml-->
<view class="container">
<view class="search">
<image class="search-icon" src="/assets/main/urban-search.png"/>
<input class="search-input" placeholder="请输入服务名称搜索" confirm-type="search" bindconfirm="bindconfirm" model:value="{{keyword}}" focus="{{true}}"/>
</view>
<view class="recent-wrapper" wx:if="{{keywordList.length > 0}}">
<view class="recent-top">
<text class="recent-top-left">最近搜索</text>
<text class="recent-top-right" bindtap="clearAction">清空</text>
</view>
<view class="recent-content">
<view class="recent-item" bindtap="historyItemClick" wx:for="{{keywordList}}" data-name="{{item}}" wx:key="index">{{item}}</view>
</view>
</view>
<view class="search-result">
<view class="cate-item" wx:for="{{list}}" wx:key="index" data-id="{{item.id}}" bindtap="itemClick">{{item.serviceName}}</view>
</view>
<image class="empty" src="/assets/project/empty.png" wx:if="{{list.length == 0}}"/>
</view>
\ No newline at end of file
/* pages/search/index.wxss */
page{
background: white;
}
.search {
width: 690rpx;
height: 80rpx;
background: #FFFFFF;
border-radius: 40rpx;
border: 2rpx solid #E6E6E6;
margin: auto;
margin-top: 10rpx;
display: flex;
align-items: center;
}
.search-icon {
width: 32rpx;
height: 32rpx;
margin-right: 5rpx;
margin-left: 30rpx;
}
.search-input {
color: #3E3E3E;
font-size: 28rpx;
margin-left: 20rpx;
flex: 1;
height: 100%;
}
.recent-wrapper {
width: 690rpx;
margin: auto;
margin-top: 40rpx;
}
.recent-top {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.recent-top-left {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #8F8F8F;
line-height: 36rpx;
}
.recent-top-right {
height: 36rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 36rpx;
}
.recent-content {
display: flex;
margin-top: 30rpx;
flex-wrap: wrap;
}
.recent-item {
height: 54rpx;
background: #F8F8F8;
border-radius: 27rpx;
padding: 0 26rpx;
color: #3E3E3E;
font-size: 24rpx;
text-align: center;
line-height: 54rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
}
.search-result{
width: 690rpx;
margin: auto;
}
.cate-item{
width: 690rpx;
height: 100rpx;
border-bottom: 1px #E6E6E6 solid;
line-height: 100rpx;
color: #3E3E3E;
font-size: 28rpx;
}
\ No newline at end of file
const { ApiOrderAgreement } = require("../../http/api")
const { wxGet } = require("../../http/network")
// pages/service/service-agreement.js
Page({
/**
* 页面的初始数据
*/
data: {
html: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wxGet(ApiOrderAgreement).then(res=>{
this.setData({
html: res.msg
})
})
},
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "家政服务协议"
}
\ No newline at end of file
<!--pages/service/service-agreement.wxml-->
<rich-text nodes="{{html}}"></rich-text>
/* pages/service/service-agreement.wxss */
page{
background: white;
padding: 5%;
width: 90%;
}
\ No newline at end of file
const { ApiServiceDetail } = require("../../http/api")
const { wxGet } = require("../../http/network")
const { jumpPage } = require("../../utils/common")
// pages/service/service-detail.js
Page({
/**
* 页面的初始数据
*/
data: {
id: 0,
data: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
let id = options.id
this.setData({
id
})
let serviceName = options.serviceName
wx.setNavigationBarTitle({
title: serviceName,
})
this.getData()
},
getData(){
wxGet(ApiServiceDetail + this.data.id).then(res=>{
this.setData({
data: res.data
})
})
},
orderAction:jumpPage(function(e){
let info = {
serviceName: this.data.data.serviceName,
description: this.data.data.description,
img: this.data.data.img,
id: this.data.data.id
}
wx.navigateTo({
url: '../order/order-service?info=' + encodeURIComponent(JSON.stringify(info)),
})
},true)
})
\ No newline at end of file
{
"usingComponents": {}
}
\ No newline at end of file
<!--pages/service/service-detail.wxml-->
<view class="content-wrapper">
<image class="thumb-img" src="{{data.detailImg}}" mode="aspectFill"/>
<view class="name-info">
<view class="name">{{data.serviceName}}</view>
<view class="subtitle">{{data.description}}</view>
</view>
<rich-text class="rich-1" nodes="{{data.textDescription}}" />
<view class="content-bottom">
<button class="kf-wrapper" open-type="contact">
<image class="kf-icon" src="/assets/service/urban-kf.png"/>
<view class="kf-text">客服</view>
</button>
<view class="sub" bindtap="orderAction">立即预约</view>
</view>
</view>
/* pages/service/service-detail.wxss */
.content-wrapper {
display: flex;
flex-direction: column;
background: #F8F8F8;
width: 100vw;
}
.name-info {
width: 100%;
height: 156rpx;
display: flex;
flex-direction: column;
background: white;
justify-content: center;
}
.name {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
margin-left: 30rpx;
}
.subtitle {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #828282;
line-height: 34rpx;
margin-left: 30rpx;
}
.thumb-img {
width: 750rpx;
height: 360rpx;
}
.rich-1 {
flex: 1;
padding-bottom: calc(128rpx + env(safe-area-inset-bottom));
margin-top: 20rpx;
}
.content-bottom {
width: 750rpx;
height: 128rpx;
bottom: 0;
position: fixed;
background: #FFFFFF;
padding-bottom: env(safe-area-inset-bottom);
display: flex;
flex-direction: row;
justify-content: space-between;
}
.kf-wrapper {
width: 128rpx;
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
margin-top: 22rpx;
background: white;
padding: 0;
}
.kf-wrapper::after {
border: 0;
}
.kf-icon {
width: 48rpx;
height: 48rpx;
}
.kf-text {
height: 36rpx;
font-size: 26rpx;
font-family: PingFang-SC-Medium, PingFang-SC;
font-weight: 500;
color: #3E3E3E;
line-height: 36rpx;
}
.sub {
width: 320rpx;
height: 88rpx;
background: #437CFD;
border-radius: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 88rpx;
margin-top: 22rpx;
margin-right: 20rpx;
text-align: center;
}
\ No newline at end of file
// pages/service/service.js
import { wxGet } from '../../http/network'
import { ApiService } from '../../http/api'
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
list: [],
selected: 0,
children: []
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.id = app.globalData.cateId
this.getData()
},
onShow(e){
this.id = app.globalData.cateId
if(this.data.list.length > 0 && this.id > 0){
this.changeDefault()
}
},
getData(){
wxGet(ApiService).then(res=>{
this.setData({
list: res.data,
children: res.data[0].children
})
if(this.id){
this.changeDefault()
}
})
},
changeDefault(){
let list = this.data.list
for(let i=0;i<list.length;i++){
let data = list[i]
if(data.id == this.id){
this.setData({
selected: i,
children: data.children
})
app.globalData.cateId = 0
break
}
}
},
leftClickAction(e){
let index = e.currentTarget.dataset.index
this.setData({
selected: index,
children: this.data.list[index].children
})
},
rightClickAction(e){
let index = e.currentTarget.dataset.index
let id = this.data.children[index].id
let serviceName = this.data.children[index].serviceName
wx.navigateTo({
url: `../service/service-detail?id=${id}&serviceName=${serviceName}`
})
},
searchAction(){
wx.navigateTo({
url: '/pages/search/index',
})
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "全部服务"
}
\ No newline at end of file
<!--pages/service/service.wxml-->
<view class="flex-column column-center main">
<view class="search-wrapper" bindtap="searchAction">
<image class="search-icon" src="/assets/main/urban-search.png" />
<view class="search-text">搜索您需要的服务</view>
</view>
<view class="flex-1">
<scroll-view class="sc-left" enable-flex scroll-y>
<view class="cate-left-item {{index == selected ? 'item-selected' : ''}}" wx:for="{{list}}" wx:key="*this" data-index="{{index}}" bindtap="leftClickAction">{{item.serviceName}}</view>
</scroll-view>
<scroll-view class="sc-right" enable-flex scroll-y>
<view class="cate-right-item" wx:for="{{children}}" wx:key="*this" bindtap="rightClickAction" data-index="{{index}}">
<image class="cate-image" src="{{item.img}}" mode="aspectFill"/>
<view class="child-name">{{item.serviceName}}</view>
</view>
</scroll-view>
</view>
</view>
\ No newline at end of file
/* pages/service/service.wxss */
page {
background: white;
}
.main {
width: 100%;
height: 100vh;
}
.search-wrapper {
width: 690rpx;
height: 72rpx;
background: #F2F6F7;
border-radius: 36rpx;
margin-top: 20rpx;
display: flex;
flex-direction: row;
align-items: center;
}
.flex-1 {
width: 100%;
flex: 1;
margin-top: 20rpx;
display: flex;
flex-direction: row;
}
.sc-left {
width: 170rpx;
background: #F7FBFC;
height: 100%;
}
.sc-right {
flex: 1;
background: white;
height: 100%;
}
.search-icon {
width: 34rpx;
height: 34rpx;
margin-left: 20rpx;
}
.search-text {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
margin-left: 15rpx;
}
.cate-left-item {
height: 126rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #8B8B8B;
line-height: 126rpx;
text-align: center;
}
.item-selected {
background: white;
}
.cate-right-item {
width: 152rpx;
height: 192rpx;
background: #FFFFFF;
border: 1px solid #ECECEC;
display: inline-block;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0 14rpx 60rpx 20rpx;
}
.cate-image {
width: 136rpx;
height: 136rpx;
margin-left: 8rpx;
}
.child-name {
height: 34rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #8B8B8B;
line-height: 34rpx;
text-align: center;
}
\ No newline at end of file
// pages/workbench/index.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
\ No newline at end of file
{
"usingComponents": {}
}
\ No newline at end of file
<!--pages/workbench/index.wxml-->
<text>pages/workbench/index.wxml</text>
/* pages/workbench/index.wxss */
\ No newline at end of file
const {
ApiManagerOrderList, ApiOrderCancel, ApiFinishOrder
} = require("../../http/api")
const {
wxPost
} = require("../../http/network")
const { showToast } = require("../../utils/common")
var page = 1
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
orderStatus: 0,
triggered: false,
date: null,
keyWord: '',
roleType: app.globalData.roleType
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
page = 1
this.getData(true)
},
bindscrolltolower(e) {
if(!this.canLoadMore)return
if (this._freshing) return
this._freshing = true
this.getData(false)
},
statusChange(e) {
let index = e.currentTarget.dataset.index
this.setData({
orderStatus: index,
list: null
})
this.getData(true)
},
getData(refresh) {
if (refresh) {
page = 1
}else{
page += 1
}
let that = this
wxPost(ApiManagerOrderList, {
"page": page,
"orderStatus": this.data.orderStatus,
"keyWord": this.data.keyWord,
"month": this.data.date,
"size": 10
}).then(res => {
var list = this.data.list
if (refresh) {
list = res.data.list
} else {
list = list.concat(res.data.list)
}
this.setData({
list
})
this.canLoadMore = res.data.hasNextPage
}).catch(() => {
}).finally(() => {
that.setData({
triggered: false,
})
that._freshing = false
})
},
onPulling(e) {
console.log('onPulling:', e)
},
onRefresh() {
console.log("onRefresh")
if (this._freshing) return
this._freshing = true
this.setData({
triggered: true,
})
this.getData(true)
},
onRestore(e) {
console.log('onRestore:', e)
},
onAbort(e) {
console.log('onAbort', e)
},
itemClickAction(e) {
let id = e.currentTarget.dataset.id
let that = this
wx.navigateTo({
url: '../order/order-detail?admin=1&id=' + id,
events: {
updateData: function (e) {
that.getData(true)
}
}
})
},
dateChange(e) {
let date = e.detail.value
this.setData({
date
})
this.getData(true)
},
keywordChange(e) {
this.getData(true)
},
dealAction(e) {
let id = e.detail.id
let that = this
wx.navigateTo({
url: '../order/order-detail?admin=1&id=' + id,
events: {
updateData: function (e) {
that.getData(true)
}
}
})
},
cancelAction(e) {
let id = e.detail.id
let that = this
wx.showModal({
title: "温馨提示",
content: "确认取消订单?",
cancelColor: "#3E3E3E",
confirmColor: "#437CFD",
success(e) {
if (e.confirm) {
that.cancelWork(id)
}
}
})
},
cancelWork(id){
wxPost(ApiOrderCancel,{"id":id}).then(res=>{
showToast("取消成功")
this.getData(true)
})
},
finishAction(e){
let id = e.detail.id
let that = this
wx.showModal({
title: "温馨提示",
content: "确认完成该订单?",
cancelColor: "#3E3E3E",
confirmColor: "#437CFD",
success(e) {
if (e.confirm) {
that.finishWork(id)
}
}
})
},
finishWork(id){
wx.showLoading({
title: '请求中',
})
wxPost(ApiFinishOrder,{"id":id}).then(res=>{
showToast("操作成功")
this.getData(true)
})
},
dispatchAction(e){
let id = e.detail.id
wx.navigateTo({
url: '/pages/process/dispatch?id=' + id,
events: {
updateData: function (e) {
that.getData(true)
}
}
})
}
})
\ No newline at end of file
{
"usingComponents": {
"manager-order-item": "/components/order-item/manager-order-item",
"empty-view":"/components/empty-view/empty-view"
}
}
\ No newline at end of file
<!--pages/workbench/order-list.wxml-->
<view class="header">
<view class="search">
<image class="search-icon" src="/assets/main/urban-search.png" />
<input class="search-input" bindconfirm="searchAction" placeholder="请输入服务名称搜索" bindinput="keywordChange" model:value="{{keyWord}}" />
</view>
<picker class="picker" mode="date" fields="month" bindchange="dateChange">
<view class="month">
<text class="month-text">{{date ? date : '月份'}}</text>
<image class="arrow" src="/assets/mine/urban-arrow-gray.png" />
</view>
</picker>
</view>
<view class="tab-wrapper">
<view class="tab-item" bindtap="statusChange" data-index="0">
<view class="tab-text">全部</view>
<view class="bottom-line" wx:if="{{orderStatus == 0}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="1">
<view class="tab-text">待受理</view>
<view class="bottom-line" wx:if="{{orderStatus == 1}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="3">
<view class="tab-text">待支付</view>
<view class="bottom-line" wx:if="{{orderStatus == 3}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="4">
<view class="tab-text">待派单</view>
<view class="bottom-line" wx:if="{{orderStatus == 4}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="5">
<view class="tab-text">服务中</view>
<view class="bottom-line" wx:if="{{orderStatus == 5}}" />
</view>
<view class="tab-item" bindtap="statusChange" data-index="6">
<view class="tab-text">已完成</view>
<view class="bottom-line" wx:if="{{orderStatus == 6}}" />
</view>
</view>
<empty-view imageName="/assets/order/order-empty.png" wx:if="{{list.length == 0}}">
</empty-view>
<scroll-view wx:else scroll-y class="sc-list" refresher-enabled="{{true}}" refresher-threshold="{{100}}" refresher-default-style="black" refresher-triggered="{{triggered}}" bindrefresherpulling="onPulling" bindrefresherrefresh="onRefresh" bindrefresherrestore="onRestore" bindrefresherabort="onAbort" bindscrolltolower="bindscrolltolower">
<manager-order-item wx:for="{{list}}" wx:key="index" item="{{item}}" roleType="{{roleType}}" bindtap="itemClickAction" data-id="{{item.id}}" bind:dealAction="dealAction" bind:cancelAction="cancelAction" bind:finishAction="finishAction" bind:dispatchAction="dispatchAction"></manager-order-item>
</scroll-view>
\ No newline at end of file
/* pages/workbench/order-list.wxss */
.tab-wrapper {
width: 750rpx;
height: 110rpx;
background: #FFFFFF;
display: flex;
flex-direction: row;
}
.tab-item {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.tab-text {
height: 106rpx;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 106rpx;
}
.bottom-line {
width: 50rpx;
height: 4rpx;
background: #437CFD;
border-radius: 2rpx;
}
.sc-list{
width: 100%;
height: calc(100vh - 120rpx - 96rpx);
padding-top: 10rpx;
}
.header {
width: 100%;
height: 96rpx;
background: white;
display: flex;
flex-direction: row;
align-items: center;
}
.search {
width: 520rpx;
height: 76rpx;
background: #F7F7F7;
border-radius: 38rpx;
display: flex;
align-items: center;
margin-left: 30rpx;
}
.search-icon {
width: 32rpx;
height: 32rpx;
margin-right: 5rpx;
margin-left: 40rpx;
}
.search-input {
color: #3E3E3E;
font-size: 28rpx;
margin-left: 20rpx;
}
.picker{
flex: 1;
}
.month {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
.month-text {
height: 42rpx;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 42rpx;
}
.arrow {
width: 20rpx;
height: 20rpx;
margin-left: 10rpx;
}
\ No newline at end of file
{
"description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"urlCheck": false,
"scopeDataCheck": false,
"coverView": true,
"es6": true,
"postcss": true,
"compileHotReLoad": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"newFeature": true,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"useIsolateContext": true,
"nodeModules": true,
"enhance": false,
"useCompilerModule": true,
"userConfirmedUseCompilerModuleSwitch": false,
"showShadowRootInWxmlPanel": true,
"lazyloadPlaceholderEnable": false,
"useMultiFrameRuntime": true,
"packNpmManually": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"useStaticServer": true,
"showES6CompileOption": false,
"checkInvalidKey": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"disableUseStrict": false,
"useCompilerPlugins": false,
"minifyWXML": true
},
"compileType": "miniprogram",
"libVersion": "2.11.3",
"appid": "wx2c8a98f02c1a4258",
"projectname": "TDesign",
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}
\ No newline at end of file
{
"projectname": "urban-craftsman",
"setting": {
"compileHotReLoad": true
},
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"condition": {
"miniprogram": {
"list": [
{
"name": "",
"pathName": "pages/address/add-address",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/address/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/order/order-detail",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/mine/change-phone",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/process/user-list",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/workbench/order-list",
"query": "",
"launchMode": "default",
"scene": null
}
]
}
},
"libVersion": "2.25.0"
}
\ No newline at end of file
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [
{
"action": "allow",
"page": "*"
}
]
}
<template name="address-item">
<view class="address-item-wrapper">
<view data-index="{{index}}" bindtap="chooseAction">
<view class="name-wrapper">
<view class="address-item-username">姓名:{{name}}</view>
<view class="address-item-phone">{{phone}}</view>
</view>
<view class="address-item-adwp">
<view class="adwp-text shrink">服务地址:</view>
<view class="adwp-text">{{namePath + address}}</view>
</view>
</view>
<view class="line"></view>
<view class="address-item-bottom">
<view class="address-opt" data-id="{{id}}" bindtap="defaultAction">
<image class="opt-icon" src="{{def ? '/assets/address/address-selected.png' : '/assets/address/address-unselected.png'}}"/>
<view class="opt-text">默认地址</view>
</view>
<view style="flex: 1;" />
<view class="address-opt" bindtap="modifyAction" data-id="{{id}}">
<image class="opt-icon" src="/assets/address/address-edit.png"/>
<view class="opt-text">编辑</view>
</view>
<view style="width: 48rpx;" />
<view class="address-opt" bindtap="deleteAction" data-id="{{id}}">
<image class="opt-icon" src="/assets/address/address-delete.png"/>
<view class="opt-text">删除</view>
</view>
</view>
</view>
</template>
\ No newline at end of file
.address-item-wrapper {
display: flex;
flex-direction: column;
margin: 0 30rpx;
margin-top: 20rpx;
background: #FFFFFF;
border-radius: 16rpx;
padding: 0 30rpx;
}
.name-wrapper {
height: 44rpx;
margin: 30rpx 0;
display: flex;
flex-direction: row;
}
.address-item-username {
height: 44rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3E3E3E;
line-height: 44rpx;
flex: 1;
}
.address-item-phone {
height: 44rpx;
font-size: 22rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 44rpx;
text-align: right;
}
.address-item-adwp {
min-height: 40rpx;
display: flex;
flex-direction: row;
}
.adwp-text {
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #9F9F9F;
line-height: 40rpx;
}
.shrink {
flex-shrink: 0;
}
.line {
width: 622rpx;
height: 1px;
position: relative;
border: none;
margin-top: 40rpx;
}
.line::after {
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 1px;
transform: scaleY(0.5);
-webkit-transform: scaleY(0.5);
-ms-transform: scaleY(0.5);
background: #F1F1F1;
}
.address-item-bottom {
height: 88rpx;
display: flex;
flex-direction: row;
}
.address-opt {
display: flex;
flex-direction: row;
align-items: center;
}
.opt-icon {
width: 28rpx;
height: 28rpx;
}
.opt-text {
height: 40rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 40rpx;
margin-left: 8rpx;
}
\ No newline at end of file
var isLogin = false
export function loginStatus(login) {
isLogin = login
}
export function jumpPage(fn, needLogin = false) {
return function (e) {
if (isLogin) {
fn.call(this, e)
} else {
wx.navigateTo({
url: '/pages/auth/login',
})
}
}
}
/**
* 函数节流
* @param fn 需要进行节流操作的事件函数
* @param interval 间隔时间
* @returns {Function}
*/
export function throttle(fn, interval) {
let enterTime = 0; //触发的时间
let gapTime = interval || 500; //间隔时间,如果interval不传,则默认500ms
return function () {
let context = this;
let backTime = new Date(); //第一次函数return即触发的时间
if (backTime - enterTime > gapTime) {
fn.call(context, arguments[0]); //arguments[0]是事件处理函数默认事件参数event call绑定当前page对象
enterTime = backTime; //赋值给第一次触发的时间,这样就保存了第二次触发的时间
}
};
}
/**
* 函数防抖
* @param fn 需要进行防抖操作的事件函数
* @param interval 间隔时间
* @returns {Function}
*/
export function debounce(fn, interval) {
let timer;
let gapTime = interval || 1000; //间隔时间,如果interval不传,则默认1000ms
return function () {
clearTimeout(timer);
let context = this;
let args = arguments[0]; //保存此处的arguments,因为setTimeout是全局的,arguments无法在回调函数中获取,此处为闭包。
timer = setTimeout(function () {
fn.call(context, args); //args是事件处理函数默认事件参数event call绑定当前page对象
}, gapTime);
};
}
export function showToast(title){
wx.showToast({
icon: 'none',
title: title
})
}
export function timeConvert(seconds){
// 秒
let second = parseInt(seconds)
// 分
let minute = 0
if (second > 60) {
minute = parseInt(second / 60)
second = parseInt(second % 60)
}
let result = '' + parseInt(second) + '秒'
if (minute > 0) {
result = '' + parseInt(minute) + '分' + result
}
return result
}
\ No newline at end of file
/* eslint-disable */
const gulpError = `gulpErrorPlaceHolder`;
export default gulpError;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment