init
This commit is contained in:
11
project-wl-kuaidiyuan-uniapp-vue3/pages/api/common.js
Normal file
11
project-wl-kuaidiyuan-uniapp-vue3/pages/api/common.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import {
|
||||
request
|
||||
} from "../../utils/request.js"
|
||||
|
||||
// 获取省市区
|
||||
export const getProvinces = (params) =>
|
||||
request({
|
||||
url: '/areas/children',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
11
project-wl-kuaidiyuan-uniapp-vue3/pages/api/freight.js
Normal file
11
project-wl-kuaidiyuan-uniapp-vue3/pages/api/freight.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import {
|
||||
request
|
||||
} from "../../utils/request.js"
|
||||
|
||||
// 计算运费
|
||||
export const calculateFreight = (params) =>
|
||||
request({
|
||||
url: '/tasks/calculate',
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
150
project-wl-kuaidiyuan-uniapp-vue3/pages/api/index.js
Normal file
150
project-wl-kuaidiyuan-uniapp-vue3/pages/api/index.js
Normal file
@@ -0,0 +1,150 @@
|
||||
import {
|
||||
request
|
||||
} from "../../utils/request.js"
|
||||
|
||||
// 获取相关消息
|
||||
export const getHomeInfo = (params) =>
|
||||
request({
|
||||
url: '/messages/home/get',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
// 获取首页相关任务、取件、派件、今日已取、已签
|
||||
export const getHomeData = () =>
|
||||
request({
|
||||
url: '/tasks/taskStatistics',
|
||||
method: 'get'
|
||||
})
|
||||
// 获取首页取件派件列表
|
||||
export const getExpressage = (params) =>
|
||||
request({
|
||||
url: `/tasks/${params.type}/${params.state}`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
// 取件派件分页列表
|
||||
export const getDeliveryList = (params) =>
|
||||
request({
|
||||
url: '/tasks/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
// 转单
|
||||
export const transferBatch = (params) =>
|
||||
request({
|
||||
url: '/tasks/transfer/batch',
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 删除任务
|
||||
export const taskDelete = (id) =>
|
||||
request({
|
||||
url: `/tasks/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
// 批量删除
|
||||
export const taskBatchDelete = (params) =>
|
||||
request({
|
||||
url: `/tasks/batch`,
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
// 取件、派件取消
|
||||
export const taskCancel = (params) =>
|
||||
request({
|
||||
url: `/tasks/cancel`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 获取任务详情
|
||||
export const getDetail = (id) =>
|
||||
request({
|
||||
url: `/tasks/get/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
// 身份证号验证
|
||||
export const idCardCheck = (params) =>
|
||||
request({
|
||||
url: `/tasks/idCard/check`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 去取件
|
||||
export const getPickup = (params) =>
|
||||
request({
|
||||
url: `/tasks/pickup`,
|
||||
method: 'put',
|
||||
params
|
||||
})
|
||||
// 获取快递员列表
|
||||
export const getSameAgency = (params) =>
|
||||
request({
|
||||
url: `/users/sameAgency`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
// 拒收
|
||||
export const rejection = (id) =>
|
||||
request({
|
||||
url: `/tasks/reject/${id}`,
|
||||
method: 'put'
|
||||
})
|
||||
// 签收
|
||||
export const tasksSign = (params) =>
|
||||
request({
|
||||
url: `/tasks/sign`,
|
||||
method: 'put',
|
||||
params
|
||||
})
|
||||
// 获取支付二维码
|
||||
export const getQrCode = (params) =>
|
||||
request({
|
||||
url: `/pays/qrCode/get`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 是否支付成功
|
||||
export const paySucceed = (id) =>
|
||||
request({
|
||||
url: `/pays/status/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
// 获取运单轨迹
|
||||
export const getTracks = (id) =>
|
||||
request({
|
||||
url: `/tasks/tracks/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
// 搜索、首页、取件、派件
|
||||
export const getSearch = (params) =>
|
||||
request({
|
||||
url: `/tasks/search`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 最近查找
|
||||
export const getRecentSearch = () =>
|
||||
request({
|
||||
url: `/tasks/recentSearch`,
|
||||
method: 'get'
|
||||
})
|
||||
// 标记为最近查找
|
||||
export const setMarkRecent = (transportOrderId) =>
|
||||
request({
|
||||
url: `/tasks/markRecent/${transportOrderId}`,
|
||||
method: 'get'
|
||||
})
|
||||
// 清空最近查找
|
||||
export const clearRecentSearch = () =>
|
||||
request({
|
||||
url: `/tasks/recentSearch`,
|
||||
method: 'delete'
|
||||
})
|
||||
// 上报位置
|
||||
export const PositionUpload = (params) =>
|
||||
request({
|
||||
url: `/track/upload`,
|
||||
method: 'put',
|
||||
data:params,
|
||||
params
|
||||
})
|
||||
10
project-wl-kuaidiyuan-uniapp-vue3/pages/api/my.js
Normal file
10
project-wl-kuaidiyuan-uniapp-vue3/pages/api/my.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import {
|
||||
request
|
||||
} from "../../utils/request.js"
|
||||
// 作业范围
|
||||
export const getUserScope = (params) =>
|
||||
request({
|
||||
url: `/users/scope`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
42
project-wl-kuaidiyuan-uniapp-vue3/pages/api/news.js
Normal file
42
project-wl-kuaidiyuan-uniapp-vue3/pages/api/news.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
request
|
||||
} from "../../utils/request.js"
|
||||
// 公告/公告详情/系统通知列表公用接口
|
||||
export const getNewList = (type) =>
|
||||
request({
|
||||
url: `/messages/list?bussinessType=3&contentType=${type}`, //3代表快递员端接口
|
||||
method: 'get'
|
||||
})
|
||||
// 取件、派件、签收、取消列表接口
|
||||
export const getMessagesList = (params) =>
|
||||
request({
|
||||
url: `/messages/page`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
// 获取系统通知
|
||||
export const getNotice = (params) =>
|
||||
request({
|
||||
url: '/messages/notice/new/get',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
// 获取公告详情
|
||||
export const getDetail= (id) =>
|
||||
request({
|
||||
url: `messages/bulletins/get/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
// 标记已读
|
||||
export const msgRead= (id) =>
|
||||
request({
|
||||
url: `/messages/${id}`,
|
||||
method: 'put'
|
||||
})
|
||||
// 全部已读
|
||||
export const msgAllRead= (params) =>
|
||||
request({
|
||||
url: `/messages/readAll/${params}`,
|
||||
method: 'put',
|
||||
params
|
||||
})
|
||||
32
project-wl-kuaidiyuan-uniapp-vue3/pages/api/user.js
Normal file
32
project-wl-kuaidiyuan-uniapp-vue3/pages/api/user.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
request
|
||||
} from "../../utils/request.js"
|
||||
|
||||
// 手机号登录
|
||||
export const phoneLogins = (params) =>
|
||||
request({
|
||||
url: `/logins/phone`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 账号登录
|
||||
export const userLogins = (params) =>
|
||||
request({
|
||||
url: `/login/account`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 发送短信验证码
|
||||
export const getsmsCode = (params) =>
|
||||
request({
|
||||
url: `/verifyCodes/smsCode`,
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
// 获取用户信息
|
||||
export const getUserInfo = (params) =>
|
||||
request({
|
||||
url: `/users/get`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
55
project-wl-kuaidiyuan-uniapp-vue3/pages/cancel/cause.vue
Normal file
55
project-wl-kuaidiyuan-uniapp-vue3/pages/cancel/cause.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<!-- 订单取消原因选择 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="pageBox">
|
||||
<view class="boxCon concelBox">
|
||||
<view class="tabConList conCenter">
|
||||
<view
|
||||
class="item"
|
||||
v-for="(item, index) in baseData"
|
||||
:key="index"
|
||||
@click="handleClick(item)"
|
||||
>
|
||||
<view>{{ item.label }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 导入公用数据
|
||||
import { cancelData } from "@/utils/commonData.js";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const title = ref("订单取消原因"); //nav标题
|
||||
const baseData = reactive(cancelData);
|
||||
// ------定义方法------
|
||||
const handleClick = (item) => {
|
||||
let isRedistribute = false;
|
||||
if (item.value === 8) {
|
||||
isRedistribute = true;
|
||||
}
|
||||
// vuex储存数据
|
||||
store.commit("user/setReasonVal", item);
|
||||
store.commit("user/setRedistribute", isRedistribute);
|
||||
uni.redirectTo({
|
||||
url: "/pages/cancel/index",
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/cancel/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../../styles/expressage.scss" lang="scss" scoped></style>
|
||||
159
project-wl-kuaidiyuan-uniapp-vue3/pages/cancel/index.vue
Normal file
159
project-wl-kuaidiyuan-uniapp-vue3/pages/cancel/index.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<!-- 订单取消原因申请 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="pageBox">
|
||||
<view class="boxCon concelBox">
|
||||
<view class="tabConList">
|
||||
<view class="item">
|
||||
<text>寄件人:</text>
|
||||
<view>{{ detailsData.senderName }}</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text>订单号:</text>
|
||||
<view>{{ detailsData.orderId }}</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text>寄件人地址:</text>
|
||||
<view>{{ detailsData.senderAddress }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="boxCon concelBox">
|
||||
<view class="tabConList">
|
||||
<view class="item" @click="handleCause">
|
||||
<text>订单取消原因</text>
|
||||
<view class="cause">
|
||||
{{ reason }}
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<view>
|
||||
<textarea
|
||||
placeholder="订单取消原因描述:"
|
||||
:placeholder-class="placeholderClass"
|
||||
v-model="reasonDesc"
|
||||
@input="monitorInput"
|
||||
></textarea>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btnBox"
|
||||
><button
|
||||
class="btn-default uni-mini"
|
||||
@click="handleSubmit"
|
||||
:disabled="reason === '' || !reason"
|
||||
:class="reason === '' || !reason ? 'disabled' : ''"
|
||||
>
|
||||
确定
|
||||
</button></view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, nextTick } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 设置字符串的长度
|
||||
import { validateTextLength } from "@/utils/index.js";
|
||||
// 接口
|
||||
import { getDetail, taskCancel } from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const taskId = users.taskId; //用vuex获取列表页传过来的任务id
|
||||
const title = ref("订单取消原因申请"); //nav标题
|
||||
let reasonDesc = ref(""); //原因描述
|
||||
let reason = users.reasonVal.label !== "" ? users.reasonVal.label : ""; //取消原因
|
||||
const detailsData = ref({}); //详情数据
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
// 获取订单取消原因描述
|
||||
if (users.reasonDesc !== "") {
|
||||
reasonDesc.value = users.reasonDesc;
|
||||
}
|
||||
// 获取详情
|
||||
getDetails(taskId);
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取详情
|
||||
const getDetails = async (id) => {
|
||||
await getDetail(id).then((res) => {
|
||||
detailsData.value = res.data;
|
||||
});
|
||||
};
|
||||
// 订单取消原因描述控制在100
|
||||
const monitorInput = () => {
|
||||
nextTick(() => {
|
||||
let leng = validateTextLength(reasonDesc.value);
|
||||
if (leng > 100) {
|
||||
reasonDesc.value = reasonDesc.value.substring(0, 100);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 提交原因申请
|
||||
const handleSubmit = async () => {
|
||||
if (reason !== "") {
|
||||
// 网络慢的时候添加按钮loading
|
||||
let times =
|
||||
setTimeout(()=>{
|
||||
uni.showLoading({
|
||||
title: 'loading',
|
||||
});
|
||||
},500)
|
||||
const params = {
|
||||
id: taskId,
|
||||
reason: users.reasonVal.value,
|
||||
reasonDesc: reasonDesc.value,
|
||||
};
|
||||
await taskCancel(params).then((res) => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
if (res.code === 200) {
|
||||
// 操作成功后清除loading
|
||||
setTimeout(function () {
|
||||
uni.hideLoading();
|
||||
}, 500);
|
||||
clearTimeout(times)
|
||||
goBack();
|
||||
return uni.showToast({
|
||||
title: "申请成功!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return uni.showToast({
|
||||
title: "请选择取消原因!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 取消订单原因选择
|
||||
const handleCause = () => {
|
||||
// 由于要跳转到取消原因页面,跳转后订单原因描述数据会自动销毁,所以先用vuex存起来
|
||||
store.commit("user/setReasonDesc", reasonDesc.value);
|
||||
// 任务id
|
||||
uni.navigateTo({
|
||||
url: "/pages/cancel/cause",
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../../styles/expressage.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<view v-if="tabIndex === 1">
|
||||
<view v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<!-- 列表内容 -->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<view class="checkbox" v-if="isAdmin">
|
||||
<view class="checkRadio"><radio :value="String(index)" :class="item.selected === true ? 'active' : ''" :checked="item.selected" @click="checkbox(index)" /></view>
|
||||
</view>
|
||||
<view class="boxBg" :class="isAdmin ? 'adminActive' : ''">
|
||||
<view class="tabList">
|
||||
<view class="item" @click="handleDetails($event, item)">
|
||||
<view class="titInfo">运单号:{{ item.transportOrderId }}</view>
|
||||
<view class="address">收件人:{{ item.name }}</view>
|
||||
<view class="address">派件地址:{{ item.address }}</view>
|
||||
<view class="address">签收时间:{{ item.taskTime }}</view>
|
||||
<view class="time" v-if="item.amount > 0 && item.status === 2">运费:{{ item.amount }}元</view>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="item.status === 2 && item.paymentStatus === 1 && item.paymentMethod === 2 && item.signStatus !== 2"
|
||||
>
|
||||
<button class="uni-btn btn-default">去收款</button>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 上拉 -->
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 空页面 -->
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, watch, nextTick } from 'vue';
|
||||
import { onReachBottom } from '@dcloudio/uni-app';
|
||||
import { getTimeDate } from '@/utils/index.js';
|
||||
import { useStore } from 'vuex';
|
||||
//接口
|
||||
import { getDeliveryList, getSearch } from '@/pages/api/index.js';
|
||||
// 下拉提示
|
||||
import ReachBottom from '@/components/reach-bottom/index.vue';
|
||||
//空页面
|
||||
import EmptyPage from '@/components/uni-empty-page/index.vue';
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 当前高度
|
||||
// 是否触发管理按钮
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// // 搜索分页
|
||||
searchInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
let itemData = ref([]);//列表数据
|
||||
let reload = ref(false);//数据加载
|
||||
let pages = ref(0);//总页数
|
||||
let pageNum = ref(1);//当前页
|
||||
let selected = reactive(new Map());
|
||||
const emptyData = ref('暂无数据');//空页面提示
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
orderDistance: null,
|
||||
orderTime: null,
|
||||
filterOverTime: null,
|
||||
dateTime: getTimeDate(new Date()).veryDayDate,
|
||||
taskStatus: 5
|
||||
});
|
||||
let searchPage = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
if (pageNum.value >= pages.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = 'loading';
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
if (props.searchInfo.keyword) {
|
||||
getSearchList();
|
||||
} else {
|
||||
getList();
|
||||
}
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
// 计算是否全选或者单选
|
||||
watch(users, (newValue, oldValue) => {
|
||||
if (users.selectTaskData.size > 0) {
|
||||
for (let [key, value] of users.selectTaskData) {
|
||||
itemData.value.forEach(element => {
|
||||
if (value === element.id) {
|
||||
element.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
itemData.value.forEach(element => {
|
||||
element.selected = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// ------生命周期------
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
// 是否触发了搜索清空
|
||||
if (users.isSearchClear) {
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setSearchClear', false);
|
||||
}
|
||||
page = {
|
||||
...page,
|
||||
page: pageNum.value,
|
||||
orderDistance: users.orderDistance,
|
||||
orderTime: users.orderTime,
|
||||
filterOverTime: users.filterOverTime
|
||||
};
|
||||
await getDeliveryList(page).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 触发tab切换
|
||||
// 如果触发了tab切换或者触发了搜索清空
|
||||
if (users.istabChange || users.isSearchClear) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索数据
|
||||
const getSearchList = async () => {
|
||||
reload.value = true;
|
||||
let valNum = 0;
|
||||
if (!users.isInput) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
searchPage = {
|
||||
...searchPage,
|
||||
keyword: props.searchInfo.keyword,
|
||||
status: props.searchInfo.status,
|
||||
taskType: props.searchInfo.taskType,
|
||||
page: valNum ? 1 : pageNum.value
|
||||
};
|
||||
// 后端接口调用
|
||||
await getSearch(searchPage).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
if (users.istabChange || !users.isInput) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 有搜索数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemData.value.length > 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const getSelected = array => {
|
||||
selected.value = array;
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = index => {
|
||||
emit('checkbox', index);
|
||||
};
|
||||
// 已签收详情
|
||||
const handleDetails = (e, item) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit('user/setTaskId', item.id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit('user/setTaskType', 2);
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit('user/setTaskStatus', 5);
|
||||
store.commit('user/setNewType', null);
|
||||
if (item.status === 2 && item.paymentStatus === 1 && item.paymentMethod === 2 && item.signStatus !== 2) {
|
||||
// 未付款进入付款二维码页面
|
||||
store.commit('user/setIsDelivery', true);
|
||||
store.commit('user/setPayData', {});
|
||||
uni.redirectTo({
|
||||
url: '/pages/pay/scanPay'
|
||||
});
|
||||
} else {
|
||||
// 进入详情页
|
||||
uni.redirectTo({
|
||||
url: '/pages/details/waybill'
|
||||
});
|
||||
}
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
getList,
|
||||
getSearchList
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<view v-if="tabIndex === 0">
|
||||
<view v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<!-- 列表内容 -->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<view class="checkbox" v-if="isAdmin">
|
||||
<view class="checkRadio"><radio :value="String(index)" :class="item.selected === true ? 'active' : ''" :checked="item.selected" @click="checkbox(index)" /></view>
|
||||
</view>
|
||||
|
||||
<view class="boxBg" :class="isAdmin ? 'adminActive' : ''">
|
||||
<view class="tabList">
|
||||
<view class="item" @click.stop="handleDetails($event, item.id)">
|
||||
<view class="titInfo">
|
||||
<view>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
{{ item.phone }}
|
||||
<icon class="phone" @click.stop="handlePhone($event, item.phone)"></icon>
|
||||
<icon class="note" @click.stop="handleNote"></icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="address">{{ item.distance }}公里</view>
|
||||
<view class="time">运单号:{{ item.transportOrderId }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 上拉 -->
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 空页面 -->
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
<!-- 拨打电话弹层 -->
|
||||
<Phone ref="phone" :phoneData="phoneData"></Phone>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { onReachBottom } from '@dcloudio/uni-app';
|
||||
import { getTimeDate } from '@/utils/index.js';
|
||||
import { useStore } from 'vuex';
|
||||
//接口
|
||||
import { getDeliveryList, getSearch } from '@/pages/api/index.js';
|
||||
// 下拉提示
|
||||
import ReachBottom from '@/components/reach-bottom/index.vue';
|
||||
//空页面
|
||||
import EmptyPage from '@/components/uni-empty-page/index.vue';
|
||||
import Phone from '@/components/uni-phone/index.vue';
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 当前触发的tab值
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 是否触发管理按钮
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// // 搜索分页
|
||||
searchInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
const phone = ref();
|
||||
let itemData = ref([]);//列表数据
|
||||
let reload = ref(false);//数据加载
|
||||
let pages = ref(0); //总页数
|
||||
let pageNum = users.isFiltrate ? 1 : ref(1); //存放当前页
|
||||
let selected = reactive(new Map());
|
||||
const emptyData = ref('暂无数据');//空页面提示
|
||||
const phoneData = ref('');
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
orderDistance: null,
|
||||
orderTime: null,
|
||||
filterOverTime: null,
|
||||
dateTime: getTimeDate(new Date()).veryDayDate,
|
||||
taskStatus: 4
|
||||
});
|
||||
let searchPage = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
store.commit('user/setIsInput', true); //是否在文本框里输入了文字
|
||||
if (pageNum.value >= Number(pages.value)) {
|
||||
loadMore.value.status = 'noMore';
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = 'loading';
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
if (props.searchInfo.keyword) {
|
||||
getSearchList();
|
||||
} else {
|
||||
getList();
|
||||
}
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
|
||||
// ------生命周期------
|
||||
// 计算是否全选或者单选
|
||||
watch(users, (newValue, oldValue) => {
|
||||
if (users.selectTaskData.size > 0) {
|
||||
for (let [key, value] of users.selectTaskData) {
|
||||
itemData.value.forEach(element => {
|
||||
if (value === element.id) {
|
||||
element.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
itemData.value.forEach(element => {
|
||||
element.selected = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
//判断是否进行了距离、时间、超时任务筛选,如果是,当前页设为第一页,上拉的数值设为1,便于第二次上拉
|
||||
let valNum = 0;
|
||||
if (users.isFiltrate || users.isSearchClear) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
// 如果触发了距离、时间、超时筛选
|
||||
if (users.isFiltrate) {
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
// 是否触发了搜索清空
|
||||
if (users.isSearchClear) {
|
||||
store.commit('user/setSearchClear', false);
|
||||
}
|
||||
}
|
||||
page = {
|
||||
...page,
|
||||
page: valNum ? 1 : pageNum.value,
|
||||
orderDistance: users.orderDistance,
|
||||
orderTime: users.orderTime,
|
||||
filterOverTime: users.filterOverTime
|
||||
};
|
||||
|
||||
await getDeliveryList(page).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
|
||||
if (users.deliveryData.length === 0 || users.isFiltrate) {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 触发tab切换
|
||||
// 如果触发了tab切换或者触发了搜索清空
|
||||
if (users.istabChange || users.isSearchClear) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索数据
|
||||
const getSearchList = async () => {
|
||||
reload.value = true;
|
||||
let valNum = 0;
|
||||
if (!users.isInput) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
searchPage = {
|
||||
...searchPage,
|
||||
keyword: props.searchInfo.keyword,
|
||||
status: props.searchInfo.status,
|
||||
taskType: props.searchInfo.taskType,
|
||||
page: valNum ? 1 : pageNum.value
|
||||
};
|
||||
// 后端接口调用
|
||||
await getSearch(searchPage).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
if (users.istabChange || !users.isInput) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 有搜索数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemData.value.length > 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取多选或者单选的数据
|
||||
const getSelected = array => {
|
||||
selected.value = array;
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = index => {
|
||||
emit('checkbox', index);
|
||||
};
|
||||
// 去派件详情
|
||||
const handleDetails = (e, id) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit('user/setTaskId', id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit('user/setTaskType', 2);
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit('user/setTaskStatus', 4);
|
||||
store.commit('user/setNewType', null);
|
||||
// 进入详情页
|
||||
uni.redirectTo({
|
||||
url: '/pages/details/waybill'
|
||||
});
|
||||
};
|
||||
// 拨打电话弹层
|
||||
const handlePhone = (e, val) => {
|
||||
e.stopPropagation();
|
||||
phoneData.value = val;
|
||||
phone.value.dialogOpen();
|
||||
};
|
||||
// 发短信
|
||||
const handleNote = () => {
|
||||
uni.showToast({
|
||||
title: '程序员哥哥正在实现中',
|
||||
duration: 1000,
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({ getList, getSearchList });
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<!-- 待派件 -->
|
||||
<DealParcel ref="dealparcel" :tabIndex="tabIndex" :isAdmin="isAdmin" @checkbox="checkbox" @getSelected="getSelected" :searchInfo="searchInfo"></DealParcel>
|
||||
<!-- end -->
|
||||
<!-- 已签收 -->
|
||||
<AlreadyParcel ref="already" :tabIndex="tabIndex" :isAdmin="isAdmin" @checkbox="checkbox" :searchInfo="searchInfo"></AlreadyParcel>
|
||||
<!-- end -->
|
||||
<!-- 提示窗示例 -->
|
||||
<UniPopup ref="popup" :tipInfo="tipInfo" @handleClick="handleClick"></UniPopup>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, watch } from 'vue';
|
||||
import { getTimeDate } from '@/utils/index.js';
|
||||
import { useStore } from 'vuex';
|
||||
//接口
|
||||
import { getDeliveryList, taskDelete } from '@/pages/api/index.js';
|
||||
// 导入组件
|
||||
// 待派件
|
||||
import DealParcel from './components/dealParcel.vue';
|
||||
// 已签收
|
||||
import AlreadyParcel from './components/alreadyParcel.vue';
|
||||
// 弹层
|
||||
import UniPopup from '@/components/uni-popup/index.vue';
|
||||
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// tab切换数据
|
||||
tabBars: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 是否触发管理按钮
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 获取当前筛选的距离升序还是降序
|
||||
orderDistance: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 获取当前筛选的时间升序还是降序
|
||||
orderTime: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 获取当前筛选超时
|
||||
filterOverTime: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const store = useStore(); //设置、获取储存的数据
|
||||
const users = store.state.user;
|
||||
let popup = ref();
|
||||
let dealparcel = ref();
|
||||
let already = ref();
|
||||
let cancel = ref();
|
||||
const tipInfo = ref('确定要删除吗?');
|
||||
let taskId = ref('');
|
||||
let scrollH = ref(0); //滚动高度
|
||||
let searchInfo = reactive({
|
||||
keyword:null,
|
||||
status:null,
|
||||
taskType:null
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
// 获取屏幕信息
|
||||
uni.getSystemInfo({
|
||||
success: res => {
|
||||
scrollH.value = res.windowHeight;
|
||||
}
|
||||
});
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取初始值
|
||||
const init = () => {
|
||||
};
|
||||
// 获取已经选的任务
|
||||
const getSelected=(array)=>{
|
||||
emit('getSelected',array)
|
||||
}
|
||||
// 获取待派件列表方法
|
||||
const dealPList =()=>{
|
||||
dealparcel.value.getList()
|
||||
}
|
||||
// 搜索待派件列表方法
|
||||
const dealSearchList = () => {
|
||||
dealparcel.value.getSearchList();
|
||||
};
|
||||
// 获取已签收列表方法
|
||||
const alreadList =()=>{
|
||||
already.value.getList()
|
||||
}
|
||||
// 搜索已签收列表方法
|
||||
const alreadSearchList = () => {
|
||||
already.value.getSearchList();
|
||||
};
|
||||
// 确认删除
|
||||
const handleClick = async () => {
|
||||
await taskDelete(taskId.value)
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
dealparcel.value.getList()
|
||||
return uni.showToast({
|
||||
title: '删除成功!',
|
||||
duration: 1000,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
//左右滑动tab切换
|
||||
const onChangeSwiperTab = e => {
|
||||
emit('onChangeSwiperTab', e);
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = index => {
|
||||
emit('checkbox', index);
|
||||
};
|
||||
// 删除弹层id
|
||||
const handleOpen = id => {
|
||||
popup.value.dialogOpen();
|
||||
taskId.value = id;
|
||||
};
|
||||
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
dealPList,
|
||||
dealSearchList,
|
||||
alreadList,
|
||||
alreadSearchList,
|
||||
searchInfo
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,7 @@
|
||||
.expressage {
|
||||
.tabScroll {
|
||||
.scroll-row-item {
|
||||
margin-right: 80rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
240
project-wl-kuaidiyuan-uniapp-vue3/pages/delivery/index.vue
Normal file
240
project-wl-kuaidiyuan-uniapp-vue3/pages/delivery/index.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<!-- 派件页面 -->
|
||||
<template>
|
||||
<!-- 搜索nav -->
|
||||
<SearchPage
|
||||
@handleSearch="handleSearch"
|
||||
ref="search"
|
||||
@clearSearchData="clearSearchData"
|
||||
></SearchPage>
|
||||
<!-- end -->
|
||||
<view>
|
||||
<!-- tab切换 -->
|
||||
<UniTab
|
||||
:tabBars="tabBars"
|
||||
ref="tab"
|
||||
@getTabIndex="getTabIndex"
|
||||
class="pickupTab"
|
||||
></UniTab>
|
||||
<!-- end -->
|
||||
<!-- 筛选 -->
|
||||
<ListFiltrate
|
||||
v-if="tabIndex === 0"
|
||||
@getList="getList"
|
||||
class="pickupFilrate"
|
||||
></ListFiltrate>
|
||||
<!-- end -->
|
||||
<!-- 取件状态列表 -->
|
||||
<view
|
||||
:class="tabIndex === 0 ? 'pickupBoxTop' : 'pickupTop'"
|
||||
style="padding: 0 0 200rpx 0"
|
||||
>
|
||||
<TabList
|
||||
:tabBars="tabBars"
|
||||
:tabIndex="tabIndex"
|
||||
:isAdmin="isAdmin"
|
||||
@onChangeSwiperTab="onChangeSwiperTab"
|
||||
@checkbox="checkbox"
|
||||
ref="list"
|
||||
></TabList>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- 底部管理 单选\转单\打印\删除 -->
|
||||
<!-- 派件后期会加功能,所以这块代码先不删除 -->
|
||||
<ExpressageFoot
|
||||
ref="expressageFoot"
|
||||
@getAdmin="getAdmin"
|
||||
:isAdmin="isAdmin"
|
||||
:isDelivery="isDelivery"
|
||||
:selected="selected"
|
||||
:tabIndex="tabIndex"
|
||||
@allSelect="allSelect"
|
||||
@handleClick="handleClick"
|
||||
></ExpressageFoot>
|
||||
<!-- end -->
|
||||
<!-- footer -->
|
||||
<UniFooter :pagePath="'pages/delivery/index'"></UniFooter>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// 基本数据
|
||||
import { PickUpData } from "@/utils/commonData.js";
|
||||
// 接口api
|
||||
import { taskBatchDelete } from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 导航
|
||||
// 搜索组件
|
||||
import SearchPage from "@/components/uni-search/index.vue";
|
||||
// 底部导航
|
||||
import UniFooter from "@/components/uni-footer/index.vue";
|
||||
// tab切换
|
||||
import UniTab from "@/components/uni-tab/index.vue";
|
||||
// 筛选
|
||||
import ListFiltrate from "@/components/uni-list-filtrate/index.vue";
|
||||
// 底部管理全选组件
|
||||
import ExpressageFoot from "@/components/uni-expressage-foot/index.vue";
|
||||
// list
|
||||
import TabList from "./components/list.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore();
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
const tab = ref();
|
||||
const list = ref();
|
||||
const search = ref(); //定义搜索ref
|
||||
const expressageFoot = ref();
|
||||
const tabBars = PickUpData;
|
||||
let tabIndex = ref(0); //当前tab
|
||||
let isDelivery = ref(true);
|
||||
let isAdmin = ref(false); //是否触发管理按钮
|
||||
// 存储已选内容, 因为这个列表是增删很频繁的,所以选用map而不是数组,key对应的是数据的下标。至于value存放什么,完全由自己定
|
||||
let selected = reactive(new Map());
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
if (users.tabIndex) {
|
||||
tabIndex.value = users.tabIndex;
|
||||
}
|
||||
if (users.tabIndex === 0) {
|
||||
list.value.dealPList();
|
||||
} else {
|
||||
list.value.alreadList();
|
||||
}
|
||||
});
|
||||
|
||||
// ------定义方法------
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
list.value.searchInfo.taskType = 2;
|
||||
list.value.searchInfo.keyword = search.value.searchVal;
|
||||
store.commit("user/setIsInput", false); //是否在文本框里输入了文字,默认false
|
||||
store.commit("user/setDeliveryData", []);
|
||||
if (tabIndex.value === 0) {
|
||||
list.value.searchInfo.status = 1;
|
||||
list.value.dealSearchList();
|
||||
} else {
|
||||
list.value.searchInfo.status = 2;
|
||||
list.value.alreadSearchList();
|
||||
}
|
||||
};
|
||||
// 批量删除
|
||||
const handleClick = async () => {
|
||||
const ids = [];
|
||||
// 要批量删除的id
|
||||
for (const [key, value] of selected) {
|
||||
ids.push(value);
|
||||
}
|
||||
|
||||
await taskBatchDelete({ idList: ids }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
list.value.alreadList();
|
||||
// 存储列表数据
|
||||
store.commit("user/setDeliveryData", []);
|
||||
// 总页数清空
|
||||
store.commit("user/setPages", 0);
|
||||
store.commit("user/setSelectTaskData", new Map());
|
||||
selected.clear();
|
||||
// expressageFoot.value.isAdmin = false
|
||||
isAdmin.value = false;
|
||||
return uni.showToast({
|
||||
title: "删除成功!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 清除搜索
|
||||
const clearSearchData = () => {
|
||||
store.commit("user/setIsInput", true);
|
||||
store.commit("user/setDeliveryData", []); //清空列表数据
|
||||
store.commit("user/setSearchText", ""); //清空搜索框内容
|
||||
store.commit("user/setSearchClear", true); //是否清空搜索框
|
||||
list.value.searchInfo.keyword = ""; //清空搜索框内容
|
||||
// 总页数清空
|
||||
store.commit("user/setPages", 0);
|
||||
if (tabIndex.value === 0) {
|
||||
list.value.dealPList();
|
||||
} else {
|
||||
list.value.alreadList();
|
||||
}
|
||||
};
|
||||
// 获取tab切换当前的index
|
||||
const getTabIndex = (index) => {
|
||||
tabIndex.value = index;
|
||||
|
||||
// 存储列表数据
|
||||
store.commit("user/setDeliveryData", []);
|
||||
// 总页数清空
|
||||
store.commit("user/setPages", 0);
|
||||
store.commit("user/setSelectTaskData", new Map());
|
||||
store.commit("user/setFilterOverTime", null);
|
||||
store.commit("user/setIsFiltrate", false);
|
||||
search.value.searchVal = "";
|
||||
store.commit("user/setSearchText", ""); //清空搜索框内容
|
||||
store.commit("user/setSearchClear", true); //是否清空搜索框
|
||||
selected.clear();
|
||||
// 修改底部管理按钮状态
|
||||
isAdmin.value = false;
|
||||
// 根据不同的tab值切更新 取件数据
|
||||
if (index === 0) {
|
||||
list.value.dealPList();
|
||||
} else {
|
||||
list.value.alreadList();
|
||||
}
|
||||
};
|
||||
// 触发选项卡事件
|
||||
const onChangeSwiperTab = (e) => {
|
||||
tab.value.changeTab(e.detail.current);
|
||||
};
|
||||
// 获取foot底部组件的管理按钮触发值,向列表页传递,全选,单选用
|
||||
const getAdmin = (val) => {
|
||||
isAdmin.value = val;
|
||||
};
|
||||
// 给筛选组件传递,刷新列表
|
||||
const getList = () => {
|
||||
list.value.dealPList();
|
||||
};
|
||||
// 全选与反选事件
|
||||
const allSelect = () => {
|
||||
// 已经全选情况下,就是反选,全选就说明长度一样
|
||||
let itemData = users.deliveryData;
|
||||
if (selected.size === itemData.length) {
|
||||
selected.clear(); // 全部清除
|
||||
itemData.forEach((element) => {
|
||||
element.selected = false; // 全部不选,就行了
|
||||
});
|
||||
}
|
||||
// 还未全选的状态下
|
||||
else {
|
||||
itemData.forEach((element, index) => {
|
||||
// 因为可能存在部分已经选择了,所以得先判断是否已存在,不存在才需要添加
|
||||
if (!selected.has(index)) {
|
||||
selected.set(index, element.id); // key是对应的下标index,而value是可以自定义的
|
||||
element.selected = true; // 设为选中
|
||||
}
|
||||
});
|
||||
}
|
||||
emit("getSelected", selected);
|
||||
store.commit("user/setSelectTaskData", selected);
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = (index) => {
|
||||
// 选中的状态下再次点击,即为取消选中
|
||||
let itemData = users.deliveryData;
|
||||
if (itemData[index].selected) {
|
||||
itemData[index].selected = false;
|
||||
selected.delete(index); // 然后删除对应key即可
|
||||
}
|
||||
// 未选中状态下点击
|
||||
else {
|
||||
itemData[index].selected = true;
|
||||
selected.set(index, itemData[index].id);
|
||||
}
|
||||
store.commit("user/setSelectTaskData", selected);
|
||||
};
|
||||
</script>
|
||||
<style src="../../styles/expressage.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<!--取派地址-->
|
||||
<template>
|
||||
<view class="boxBg">
|
||||
<view class="addressCon">
|
||||
<view class="item">
|
||||
<view class="sendIcon">{{ taskType === 1 ? "取" : "派" }}</view>
|
||||
<view class="addressInfo">
|
||||
<view
|
||||
><text class="name">{{ detailsData.senderName }}</text
|
||||
>{{ detailsData.senderPhone }}</view
|
||||
>
|
||||
<view>{{ detailsData.senderAddress }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="receiveIcon">{{ taskType === 1 ? "派" : "收" }}</view>
|
||||
<view class="addressInfo">
|
||||
<view
|
||||
><text class="name">{{ detailsData.receiverName }}</text
|
||||
>{{ detailsData.receiverPhone }}</view
|
||||
>
|
||||
<view>{{ detailsData.receiverAddress }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
detailsData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user; //vuex获取、储存数据
|
||||
let taskType = users.taskType;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<!--身份证验证-->
|
||||
<template>
|
||||
<view class="boxBg">
|
||||
<view class="tit">
|
||||
<text v-if="detailsData.idCardNoVerify === 0 && !flag">
|
||||
身份验证(未验证)
|
||||
<icon class="iconTip"></icon>
|
||||
</text>
|
||||
<text v-else-if="detailsData.idCardNoVerify === 1 || flag">
|
||||
身份验证(验证通过)
|
||||
<!-- TODO 先保留-->
|
||||
<!-- <icon class="iconTip"></icon> -->
|
||||
</text>
|
||||
<text v-else>
|
||||
身份验证(验证未通过)
|
||||
<icon class="iconTip"></icon>
|
||||
</text>
|
||||
</view>
|
||||
<view class="identityBox" v-if="detailsData.idCardNoVerify !== 1 && !flag">
|
||||
<view>
|
||||
<uni-forms ref="customForm">
|
||||
<uni-forms-item name="name"
|
||||
><uni-easyinput
|
||||
class="item"
|
||||
v-model="name"
|
||||
placeholder="请输入真实姓名"
|
||||
/></uni-forms-item>
|
||||
<uni-forms-item name="idCard"
|
||||
><uni-easyinput
|
||||
class="item"
|
||||
v-model="idCard"
|
||||
placeholder="请输入身份证号码"
|
||||
@blur="handleIdcard"
|
||||
/></uni-forms-item>
|
||||
</uni-forms>
|
||||
<button class="uni-btn concelBtn" @click="handleCheck">验证</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="identitySuccee" v-else>
|
||||
<view class="text" v-if="name !== ''">{{ name }}</view>
|
||||
<view class="text">{{
|
||||
idCard !== "" ? idCard : detailsData.idCardNo
|
||||
}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 验证
|
||||
import { validateIdentityCard } from "@/utils/validate";
|
||||
// 接口
|
||||
import { idCardCheck } from "@/pages/api/index.js";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
detailsData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const customForm = ref();
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
// 表单数据
|
||||
let idCard = ref(""); //身份证号
|
||||
let name = ref(""); //身份证号
|
||||
let isValidate = ref(false); //输入身份证是否验证成功
|
||||
let flag = ref(null); //是否校验成功
|
||||
// ------定义方法------
|
||||
onMounted(() => {
|
||||
if (users.cardData) {
|
||||
name.value = users.cardData.name;
|
||||
name.idCard = users.cardData.idCard;
|
||||
flag.value = true;
|
||||
}
|
||||
});
|
||||
// 身份校验
|
||||
const handleIdcard = () => {
|
||||
const validate = validateIdentityCard(idCard.value);
|
||||
if (validate) {
|
||||
isValidate.value = true;
|
||||
} else {
|
||||
return uni.showToast({
|
||||
title: validate,
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 验证身份号
|
||||
const handleCheck = async () => {
|
||||
const params = {
|
||||
name: name.value,
|
||||
idCard: idCard.value,
|
||||
};
|
||||
store.commit("user/setCardData", params);
|
||||
await idCardCheck(params)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
flag.value = res.data.flag;
|
||||
return uni.showToast({
|
||||
title: "验证成功",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
// 暴漏给父组件
|
||||
defineExpose({
|
||||
customForm,
|
||||
idCard,
|
||||
name,
|
||||
isValidate,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<view class="uniPopup detailPopup">
|
||||
<uni-popup ref="popup" type="bottom">
|
||||
<view class="tit">
|
||||
<text>{{
|
||||
type === 1
|
||||
? "物品名称"
|
||||
: type === 2
|
||||
? "付款方式"
|
||||
: type === 3
|
||||
? "备注"
|
||||
: "签收人"
|
||||
}}</text>
|
||||
<icon @click="dialogClose">关闭</icon>
|
||||
</view>
|
||||
<view class="popupContent">
|
||||
<!-- 物品名称 -->
|
||||
<view v-if="type === 1">
|
||||
<view class="goodBox">
|
||||
<view
|
||||
v-for="(item, index) in GoodsData"
|
||||
:key="index"
|
||||
class="item"
|
||||
:class="index === isActive ? 'active' : ''"
|
||||
@click="handleActive(index, item)"
|
||||
>
|
||||
<text>{{ item.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="isShowGoodInfo" class="other">
|
||||
<textarea
|
||||
v-model="otherData"
|
||||
placeholder="请输入物品信息"
|
||||
@input="monitorInput"
|
||||
:maxlength="goodMaxLength"
|
||||
></textarea>
|
||||
<text class="numText" :class="goodNumVal === 0 ? 'tip' : ''"
|
||||
>{{ goodNumVal }}/10</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 付款方式 -->
|
||||
<view v-else-if="type === 2">
|
||||
<view
|
||||
class="typeItem"
|
||||
v-for="(item, index) in PayMethodData"
|
||||
:key="index"
|
||||
@click="checkbox(index)"
|
||||
>
|
||||
<text>{{ item.label }}</text>
|
||||
<view class="checkRadio"
|
||||
><radio
|
||||
:value="String(index)"
|
||||
:class="index === current ? 'active' : ''"
|
||||
:checked="index === current"
|
||||
/></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 备注 -->
|
||||
<view v-else-if="type === 3" class="remark">
|
||||
<textarea
|
||||
v-model="remark"
|
||||
placeholder="补充说明"
|
||||
@input="textInput"
|
||||
:maxlength="remarkMaxLength"
|
||||
></textarea>
|
||||
<text class="numText" :class="remarkNumVal === 0 ? 'tip' : ''"
|
||||
>{{ remarkNumVal }}/30</text
|
||||
>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 签收人 -->
|
||||
<view v-else>
|
||||
<view
|
||||
class="typeItem"
|
||||
v-for="(item, index) in SignData"
|
||||
:key="index"
|
||||
@click="checkbox(index)"
|
||||
>
|
||||
<text>{{ item.label }}</text>
|
||||
<view class="checkRadio"
|
||||
><radio
|
||||
:value="String(index)"
|
||||
:class="index === current ? 'active' : ''"
|
||||
:checked="index === current"
|
||||
/></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<view class="btnBox"
|
||||
><button class="btn-default uni-mini" @click="handleSubmit">
|
||||
确定
|
||||
</button></view
|
||||
>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick, watch } from "vue";
|
||||
import { validateTextLength } from "@/utils/index.js";
|
||||
// 基本数据
|
||||
import { PayMethodData, GoodsData, SignData } from "@/utils/commonData.js";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
detailsData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
watch(props, (newValue, olcValue) => {
|
||||
if (newValue !== undefined) {
|
||||
remark.value = newValue.detailsData.remark;
|
||||
if (newValue.type === 2) {
|
||||
if (newValue.detailsData.paymentMethod === 1) {
|
||||
current.value = 0;
|
||||
} else {
|
||||
current.value = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
// 定义ref 获取子组件方法或者值
|
||||
const popup = ref();
|
||||
const emit = defineEmits(); //子组件向父组件事件传递
|
||||
let current = ref(0); //当前触发付款方式的值
|
||||
let isActive = ref(0); //当前触发物品名称的值
|
||||
let otherData = ref(""); //自定义其他物品信息
|
||||
let goodNumVal = ref(0); //其他自定义的字节数控制值
|
||||
let remarkNumVal = ref(0); //备注字节数控制值
|
||||
let remark = ref(""); //备注
|
||||
let goodMaxLength = ref(10);
|
||||
let remarkMaxLength = ref(30);
|
||||
let isShowGoodInfo = ref(false); //控制其他文本域的显示/隐藏
|
||||
// ------定义方法------
|
||||
// 确定
|
||||
const handleSubmit = () => {
|
||||
// type=1 物品名称 type=2 付款方式 type=3 备注
|
||||
if (props.type === 1) {
|
||||
let val = null;
|
||||
if (isShowGoodInfo.value) {
|
||||
if (otherData.value === "") {
|
||||
return uni.showToast({
|
||||
title: "请输入物品信息",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
val = otherData.value;
|
||||
} else {
|
||||
val = GoodsData[isActive.value].label;
|
||||
}
|
||||
emit("getGoodType", val);
|
||||
} else if (props.type === 2) {
|
||||
emit("getPayMethod", PayMethodData[current.value].label);
|
||||
} else if (props.type === 3) {
|
||||
emit("getRemark", remark.value);
|
||||
} else {
|
||||
emit("getSignType", SignData[current.value].value);
|
||||
}
|
||||
dialogClose();
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = (index) => {
|
||||
current.value = index;
|
||||
};
|
||||
// 选择物品
|
||||
const handleActive = (index, item) => {
|
||||
if (item.label === "其他") {
|
||||
isShowGoodInfo.value = true;
|
||||
} else {
|
||||
isShowGoodInfo.value = false;
|
||||
}
|
||||
isActive.value = index;
|
||||
};
|
||||
// 打开弹层
|
||||
const dialogOpen = () => {
|
||||
popup.value.open();
|
||||
};
|
||||
// 关闭弹层
|
||||
const dialogClose = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
// 其他自定义的名称控制10个字符
|
||||
const monitorInput = () => {
|
||||
nextTick(() => {
|
||||
let leng = validateTextLength(otherData.value);
|
||||
if (leng >= 10) {
|
||||
goodMaxLength.value = leng;
|
||||
} else {
|
||||
goodMaxLength.value = 20;
|
||||
}
|
||||
goodNumVal.value = Math.floor(leng);
|
||||
});
|
||||
};
|
||||
// 备注控制50个字符
|
||||
const textInput = () => {
|
||||
nextTick(() => {
|
||||
let leng = validateTextLength(remark.value);
|
||||
if (leng >= 30) {
|
||||
remarkMaxLength.value = leng;
|
||||
} else {
|
||||
remarkMaxLength.value = 60;
|
||||
}
|
||||
remarkNumVal.value = Math.floor(leng);
|
||||
});
|
||||
};
|
||||
// 向父组件暴露方法
|
||||
defineExpose({
|
||||
dialogOpen,
|
||||
current,
|
||||
});
|
||||
</script>
|
||||
667
project-wl-kuaidiyuan-uniapp-vue3/pages/details/index.scss
Normal file
667
project-wl-kuaidiyuan-uniapp-vue3/pages/details/index.scss
Normal file
@@ -0,0 +1,667 @@
|
||||
body,
|
||||
uni-page-body,
|
||||
uni-page-head,
|
||||
.uni-page-head {
|
||||
background-color: var(--neutral-color-background) !important;
|
||||
}
|
||||
.detailBox {
|
||||
padding-bottom: 186rpx;
|
||||
.boxBg {
|
||||
margin-top: 32rpx;
|
||||
padding: 28rpx 26rpx;
|
||||
|
||||
}
|
||||
::v-deep .tit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > text {
|
||||
flex: 1;
|
||||
color: var(--neutral-color-font);
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.copy {
|
||||
background: url(@/static/icon20.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 24rpx;
|
||||
height: 30rpx;
|
||||
margin-left: 14rpx;
|
||||
}
|
||||
.goodsSelect {
|
||||
text-align: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.iconTip {
|
||||
background: var(--essential-color-red);
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.textInfo {
|
||||
color: var(--neutral-color-main);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
width: 400rpx;
|
||||
// padding-right: 20rpx;
|
||||
vertical-align: middle;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.freight {
|
||||
display: flex;
|
||||
border-top: 1px solid var(--neutral-color-background);
|
||||
padding: 36rpx 0 12rpx;
|
||||
margin-top: 16rpx;
|
||||
view {
|
||||
&:first-child {
|
||||
flex: 1;
|
||||
text {
|
||||
font-size: var(--font-size-12);
|
||||
color: var(--neutral-color-font);
|
||||
padding-left: 10rpx;
|
||||
text {
|
||||
color: var(--essential-color-red);
|
||||
}
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
text-align: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
::v-deep uni-input {
|
||||
width: 120rpx;
|
||||
font-size: var(--font-size-14);
|
||||
color: var(--neutral-color-main);
|
||||
height: 30rpx;
|
||||
line-height: 30rpx;
|
||||
min-height: 30rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btnBox {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 10rpx;
|
||||
.btn-default {
|
||||
box-shadow: 0 7px 12px 0 rgba(239, 79, 63, 0.41);
|
||||
}
|
||||
}
|
||||
::v-deep .identityBox {
|
||||
padding: 8rpx 0 0;
|
||||
margin-top: 28rpx;
|
||||
border-top: 1px solid var(--neutral-color-background);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > view {
|
||||
&:first-child {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.concelBtn {
|
||||
line-height: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 30rpx;
|
||||
margin-top: 40rpx !important;
|
||||
}
|
||||
.uni-forms {
|
||||
flex: 1;
|
||||
.is-input-border {
|
||||
border: 0 none !important;
|
||||
}
|
||||
.uni-easyinput__content-input {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.uni-easyinput__placeholder-class {
|
||||
font-size: var(--font-size-14);
|
||||
}
|
||||
.uni-forms-item__inner {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
}
|
||||
::v-deep .identitySuccee {
|
||||
padding: 20rpx 0;
|
||||
line-height: 60rpx;
|
||||
}
|
||||
:deep(.pickupBox){
|
||||
padding-bottom: 0;
|
||||
.addressCon{
|
||||
.item{
|
||||
padding: 10rpx 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .addressCon {
|
||||
.item {
|
||||
display: flex;
|
||||
padding: 16rpx 0;
|
||||
.name {
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .goodsCon {
|
||||
.item {
|
||||
&:first-child {
|
||||
padding-top: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 弹层
|
||||
::v-deep .detailPopup {
|
||||
.uni-popup__wrapper {
|
||||
background: var(--neutral-color-white) !important;
|
||||
border-radius: 32rpx 32rpx 0 0 !important;
|
||||
.btn-default {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
}
|
||||
.tit {
|
||||
height: 120rpx;
|
||||
line-height: 120rpx;
|
||||
display: flex;
|
||||
padding: 0 44rpx;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
text {
|
||||
flex: 1;
|
||||
}
|
||||
icon {
|
||||
text-align: right;
|
||||
background: url(@/static/icon21.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.typeItem {
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
display: flex;
|
||||
padding: 0 44rpx;
|
||||
align-items: center;
|
||||
height: 116rpx;
|
||||
line-height: 116rpx;
|
||||
text {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.goodBox {
|
||||
padding: 0 32rpx 0 4rpx;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-content: flex-start;
|
||||
.item {
|
||||
box-sizing: border-box;
|
||||
|
||||
flex: 0 0 29.3%;
|
||||
margin-top: 40rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
background: var(--neutral-color-background);
|
||||
border-radius: 20rpx;
|
||||
margin-left: 28rpx;
|
||||
}
|
||||
.active {
|
||||
border: 1px solid #ef4f3f;
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
background: var(--neutral-color-white);
|
||||
}
|
||||
}
|
||||
}
|
||||
.other {
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
padding: 28rpx 30rpx;
|
||||
margin: 40rpx 30rpx 0;
|
||||
background: var(--neutral-color-background);
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
.uni-textarea-textarea {
|
||||
height: 40rpx;
|
||||
}
|
||||
.numText {
|
||||
position: absolute;
|
||||
top: 28rpx;
|
||||
right: 24rpx;
|
||||
color: var(--neutral-color-font);
|
||||
.tip {
|
||||
color: #bdbdbd;
|
||||
}
|
||||
}
|
||||
}
|
||||
.remark {
|
||||
// height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
padding: 28rpx 30rpx;
|
||||
margin: 40rpx 30rpx 0;
|
||||
background: var(--neutral-color-background);
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
// .uni-textarea-textarea{
|
||||
// height: 40rpx;
|
||||
// }
|
||||
.numText {
|
||||
position: absolute;
|
||||
bottom: 28rpx;
|
||||
right: 24rpx;
|
||||
color: var(--neutral-color-font);
|
||||
.tip {
|
||||
color: #bdbdbd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 运单详情
|
||||
.wayCon {
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 80rpx;
|
||||
height: 80rpx;
|
||||
color: var(--neutral-color-font);
|
||||
text {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
color: var(--neutral-color-main);
|
||||
}
|
||||
}
|
||||
}
|
||||
.remark {
|
||||
border-top: 1px solid var(--neutral-color-background);
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
padding: 30rpx 0;
|
||||
margin: 20rpx 0;
|
||||
.item {
|
||||
text-align: left;
|
||||
display: inherit;
|
||||
height: auto;
|
||||
line-height: 40rpx;
|
||||
&:last-child {
|
||||
padding: 20rpx 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .content {
|
||||
uni-cover-view {
|
||||
overflow: initial;
|
||||
}
|
||||
}
|
||||
.scroll-Y {
|
||||
height: 300rpx;
|
||||
}
|
||||
.bottmBox {
|
||||
background: var(--neutral-color-white);
|
||||
border-radius: 10px;
|
||||
position: fixed;
|
||||
top: 190rpx;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
padding-top: 40rpx;
|
||||
.orderList {
|
||||
padding: 0 32rpx 40rpx;
|
||||
margin: 0 30rpx;
|
||||
height: calc(82vh - 20rpx);
|
||||
// height: 400px;
|
||||
overflow-y: scroll;
|
||||
.fontPostion {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
}
|
||||
& > .uni-cover-view {
|
||||
|
||||
uni-cover-view {
|
||||
// &:nth-child(1) {
|
||||
// .logistics-orderInfo-right {
|
||||
// margin-left: 12rpx;
|
||||
// }
|
||||
// }
|
||||
// &:nth-child(2) {
|
||||
// .logistics-orderInfo-right {
|
||||
// margin-left: 10rpx;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
.item {
|
||||
position: relative;
|
||||
padding-bottom: 60rpx;
|
||||
border-left: 1px dotted #ccc;
|
||||
&:last-child {
|
||||
border: 0 none;
|
||||
padding: 0;
|
||||
}
|
||||
.iconBg {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
background: var(--neutral-color-font);
|
||||
line-height: 52rpx;
|
||||
color: var(--neutral-color-white);
|
||||
text-align: center;
|
||||
padding: 10rpx 0 0 0rpx;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
left: -26rpx;
|
||||
icon {
|
||||
width: 30rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
&.harvest {
|
||||
background: var(--essential-color-red);
|
||||
}
|
||||
.pickUp {
|
||||
background: url(@/static/icon24.png) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
.transport {
|
||||
background: url(@/static/icon25.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 37rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
}
|
||||
.rtext {
|
||||
padding-left: 48rpx;
|
||||
line-height: 34rpx;
|
||||
font-size: var(--font-size-12);
|
||||
.tit {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-16);
|
||||
line-height: 44rpx;
|
||||
}
|
||||
.time {
|
||||
color: var(--neutral-color-font);
|
||||
padding: 2rpx 0 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ::v-deep .logistics-orderInfo {
|
||||
// &.logistics-orderInfo-item.active {
|
||||
// .logistics-orderInfo-left {
|
||||
// .iconBg {
|
||||
// background-color: #e63e32 !important;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// &.logistics-orderInfo-item {
|
||||
// & > .uni-cover-view {
|
||||
// // display: flex;
|
||||
// // padding-bottom: 60rpx;
|
||||
// }
|
||||
|
||||
// .logistics-orderInfo-left {
|
||||
// float: left;
|
||||
// // text-align: center;
|
||||
// // .gray.circle {
|
||||
// // background-color: #818181;
|
||||
// // }
|
||||
// .logistics-orderInfo-item.active {
|
||||
// .logistics-orderInfo-left {
|
||||
// .circle {
|
||||
// background-color: #e63e32 !important;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .circle {
|
||||
// position: relative;
|
||||
// // background-color: #818181;
|
||||
// right: 20rpx;
|
||||
// width: 52rpx;
|
||||
// height: 52rpx;
|
||||
// line-height: 52rpx;
|
||||
// font-size: 24rpx;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// color: #818181;
|
||||
// image {
|
||||
// width: 40rpx;
|
||||
// height: 40rpx;
|
||||
// }
|
||||
// .uni-cover-view {
|
||||
// width: 52rpx;
|
||||
// // height: 52rpx;
|
||||
// // line-height: 52rpx;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// text-align: center;
|
||||
// }
|
||||
// }
|
||||
// .point {
|
||||
// width: 10rpx;
|
||||
// height: 10rpx;
|
||||
// border-radius: 5rpx;
|
||||
// background-color: #818181;
|
||||
// margin-right: 40rpx;
|
||||
// }
|
||||
// .line {
|
||||
// min-height:11vh;
|
||||
// width: 2rpx;
|
||||
// background: #dfdfdf;
|
||||
// border-left: 0.5rpx dashed #dfdfdf;
|
||||
// position: relative;
|
||||
// left: 4rpx;
|
||||
// }
|
||||
// .line.short {
|
||||
// height: 120rpx;
|
||||
// }
|
||||
// .iconBg {
|
||||
// width: 52rpx;
|
||||
// height: 52rpx;
|
||||
// background: var(--neutral-color-font);
|
||||
// line-height: 52rpx;
|
||||
// color: var(--neutral-color-white);
|
||||
// text-align: center;
|
||||
// box-sizing: border-box;
|
||||
// border-radius: 50%;
|
||||
// // display: flex;
|
||||
// // align-items: center;
|
||||
// // justify-content: center;
|
||||
// uni-cover-image {
|
||||
// width: 26rpx;
|
||||
// height: 26rpx;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// display: flex;
|
||||
// padding-left: 12rpx;
|
||||
// margin-left: 6rpx;
|
||||
// img{
|
||||
// width: 30rpx;
|
||||
// height: 20rpx;
|
||||
// }
|
||||
// }
|
||||
// &.harvest {
|
||||
// background: var(--essential-color-red);
|
||||
// }
|
||||
// .pickUp {
|
||||
// background: url(@/static/icon24.png) no-repeat;
|
||||
// background-size: contain;
|
||||
// }
|
||||
// .transport {
|
||||
// background: url(@/static/icon25.png) no-repeat;
|
||||
// background-size: contain;
|
||||
// width: 37rpx;
|
||||
// height: 28rpx;
|
||||
// }
|
||||
// .delivery {
|
||||
// background: url(@/static/paisong.png) no-repeat;
|
||||
// background-size: contain;
|
||||
// width: 37rpx;
|
||||
// height: 28rpx;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .logistics-orderInfo-right {
|
||||
// .status {
|
||||
// font-size: 32rpx;
|
||||
// color: #2a2929;
|
||||
// font-weight: bold;
|
||||
// margin-bottom: 6rpx;
|
||||
// }
|
||||
// .time {
|
||||
// margin-bottom: 6rpx;
|
||||
// }
|
||||
// .time,
|
||||
// .desc {
|
||||
// font-size: 24rpx;
|
||||
// color: #818181;
|
||||
// }
|
||||
// .desc {
|
||||
// float: left;
|
||||
// white-space: normal;
|
||||
// line-height: normal;
|
||||
// line-height: 34rpx;
|
||||
// min-height: 120rpx;
|
||||
// }
|
||||
// .desc.active {
|
||||
// // font-weight: bold;
|
||||
// color: #2a2929;
|
||||
// min-height: 160rpx;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .up {
|
||||
// animation: upAmimat 500ms infinite;
|
||||
// }
|
||||
// .down {
|
||||
// animation: downAmimat 500ms infinite;
|
||||
// }
|
||||
// @keyframes upAmimat {
|
||||
// from {
|
||||
// top: 200px;
|
||||
// }
|
||||
// to {
|
||||
// top: 200px;
|
||||
// }
|
||||
// }
|
||||
// @keyframes downAmimat {
|
||||
// from {
|
||||
// bottom: 0px;
|
||||
// }
|
||||
// to {
|
||||
// bottom: 0px;
|
||||
// }
|
||||
// }
|
||||
|
||||
::v-deep .logistics-orderInfo{
|
||||
&.logistics-orderInfo-item.active{
|
||||
.red{
|
||||
// font-weight: bold;
|
||||
color:#E63E32!important;
|
||||
|
||||
}
|
||||
.logistics-orderInfo-left{
|
||||
.circle{
|
||||
background-color:#E63E32!important;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
&.logistics-orderInfo-item{
|
||||
|
||||
display: flex;
|
||||
.logistics-orderInfo-left{
|
||||
// text-align: center;
|
||||
.circle{
|
||||
background-color:#818181 ;
|
||||
}
|
||||
.circle{
|
||||
position: relative;
|
||||
right: 20rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
text-align: center;
|
||||
line-height: 52rpx;
|
||||
border-radius: 50%;
|
||||
font-size: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
image{
|
||||
// width:30rpx ;
|
||||
// height:20rpx ;
|
||||
}
|
||||
.ys{
|
||||
background: url(@/static/yunshuzhong.png) no-repeat;
|
||||
background-size: contain;
|
||||
width:36rpx ;
|
||||
height:28rpx ;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
.ps{
|
||||
background: url(@/static/paisong.png) no-repeat;
|
||||
background-size: contain;
|
||||
width:34rpx ;
|
||||
height:32rpx ;
|
||||
margin-left:2rpx;
|
||||
}
|
||||
}
|
||||
.point{
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-radius: 50%;
|
||||
background-color:#818181 ;
|
||||
margin-right: 40rpx;
|
||||
}
|
||||
.line{
|
||||
height: 154rpx;
|
||||
width: 2rpx;
|
||||
border-left: 2rpx dashed #DFDFDF;
|
||||
position: relative;
|
||||
left: 4rpx;
|
||||
}
|
||||
.line.short{
|
||||
height:120rpx ;
|
||||
}
|
||||
|
||||
}
|
||||
.logistics-orderInfo-right{
|
||||
.status{
|
||||
font-size: 32rpx;
|
||||
color:#2A2929 ;
|
||||
font-weight: bold;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
.time{
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
.time,.desc{
|
||||
font-size: 24rpx;
|
||||
color:#818181 ;
|
||||
}
|
||||
// .desc .red{
|
||||
// // font-weight: bold;
|
||||
// color:#E63E32!important;
|
||||
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
385
project-wl-kuaidiyuan-uniapp-vue3/pages/details/index.vue
Normal file
385
project-wl-kuaidiyuan-uniapp-vue3/pages/details/index.vue
Normal file
@@ -0,0 +1,385 @@
|
||||
<!-- 去取件详情页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="detailBox">
|
||||
<!-- 订单号 -->
|
||||
<view class="boxBg">
|
||||
<view class="tit">
|
||||
<text>
|
||||
<text>订单号:SD{{ detailsData.orderId }}</text>
|
||||
|
||||
<icon @click="handleCopy" class="copy"></icon>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 取件信息 -->
|
||||
<Address :detailsData="detailsData" class="pickupBox"></Address>
|
||||
<!-- end -->
|
||||
<!-- 物品信息 -->
|
||||
<view class="boxBg">
|
||||
<view class="tit">
|
||||
<text>物品名称</text>
|
||||
<view class="goodsSelect" @click="handleGoods" v-if="!isPickUp || (users.paymentMethod === 2 && !isCollect)">
|
||||
<text class="textInfo">{{ detailsData.goodsType }}</text>
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
<view class="goodsSelect" v-else>
|
||||
<text class="textInfo">{{ detailsData.goodsType }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 计算物品快递费 -->
|
||||
<view class="boxBg">
|
||||
<GoodsInfo ref="goods" :detailsData="detailsData" @getFreight="getFreight"></GoodsInfo>
|
||||
<view class="freight">
|
||||
<view>
|
||||
总计金额
|
||||
<text>
|
||||
<text>*</text>
|
||||
基础运费+增值服务费
|
||||
</text>
|
||||
</view>
|
||||
<view>
|
||||
<view v-if="!isPickUp || (users.paymentMethod === 2 && !isCollect)">
|
||||
<input v-if="isFreigthEdit" type="number" v-model="freight" @blur="handleAmount" />
|
||||
<text @click="handleFreight" v-else>{{ detailsData.freight }}</text>
|
||||
<text>元</text>
|
||||
</view>
|
||||
<view v-else>
|
||||
<text>{{ users.payData.tradingAmount }}</text>
|
||||
<text>元</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 付款方式 -->
|
||||
<view class="boxBg">
|
||||
<view class="tit">
|
||||
<text>付款方式</text>
|
||||
<view class="goodsSelect" @click="handlePayMethod" v-if="!isPickUp || (users.paymentMethod === 2 && !isCollect)">
|
||||
<text class="textInfo">{{ detailsData.paymentMethod === 1 ? '寄付' : '到付' }}</text>
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
<view class="goodsSelect" v-else>
|
||||
<text class="textInfo">{{ detailsData.paymentMethod === 1 ? '寄付' : '到付' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 备注 -->
|
||||
<view class="boxBg">
|
||||
<view class="tit">
|
||||
<text>备注</text>
|
||||
<view class="goodsSelect" @click="handleRemark" v-if="!isPickUp || (users.paymentMethod === 2 && !isCollect)">
|
||||
<text class="textInfo">{{ detailsData.remark }}</text>
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
<view class="goodsSelect" v-else>
|
||||
<text class="textInfo">{{ detailsData.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 身份验证(未验证) -->
|
||||
<Authentication ref="card" :detailsData="detailsData"></Authentication>
|
||||
<!-- end -->
|
||||
<view class="btnBox">
|
||||
<button v-if="isPickUp && users.paymentMethod === 1" class="btn-default uni-mini" @click="handleReceipt">去收款</button>
|
||||
<button v-if="isCollect && isPickUp && users.paymentMethod === 2" class="btn-default uni-mini btn-forbid">已取件</button>
|
||||
<button v-if="!isPickUp || (users.paymentMethod === 2 && !isCollect)" class="btn-default uni-mini" @click="handleSubmit">去取件</button>
|
||||
</view>
|
||||
<!-- 物品名称、付款选择、备注弹层 -->
|
||||
<Uppop ref="method" @getGoodType="getGoodType" @getPayMethod="getPayMethod" @getRemark="getRemark" :detailsData="detailsData" :type="type"></Uppop>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, watch, nextTick } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
// 接口
|
||||
import { getDetail, getPickup } from '@/pages/api/index.js';
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from '@/components/uni-nav/index.vue';
|
||||
// 地址
|
||||
import Address from './components/address.vue';
|
||||
// 物品信息
|
||||
import GoodsInfo from '@/components/uni-goods/index.vue';
|
||||
// 身份认证
|
||||
import Authentication from './components/authentication.vue';
|
||||
// 付款方式先择、物品名称弹层
|
||||
import Uppop from './components/uppop.vue';
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
// 定义ref 获取子组件方法或者值
|
||||
const goods = ref(); //
|
||||
const card = ref(); //
|
||||
const method = ref(); //
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
// 获取列表页传过来的id 有两种方法
|
||||
// 第一种
|
||||
// const pages = getCurrentPages(); //获取加载的页面,获取当前页面路由信息uniapp 做安卓不支持 vue-router
|
||||
// const currentPage = pages[pages.length - 1]; //获取当前页面的对象
|
||||
// 第二种 用vuexs
|
||||
const taskId = store.state.user.taskId; //用vuex获取列表页传过来的任务id
|
||||
const title = ref('去取件'); //nav标题
|
||||
let type = ref(1); //物品名称和付款方式公用一个弹层,根据不同type值来做判断 物品:1,付款方式:2,备注:3
|
||||
const detailsData = ref({}); //详情数据
|
||||
let isFreigthEdit = ref(false);
|
||||
let freight = ref(0); //金额
|
||||
let isPickUp = ref(false); //是否去取件
|
||||
let isCollect = ref(false); //到付的情况下,是否触发去取件后到,显示按钮为已取件
|
||||
const stopClick = ref(true); //防止连续提交
|
||||
// 监听修改金额数值,小数点后保留一位
|
||||
watch(freight, (newValue, oldValue) => {
|
||||
const val = Number(newValue);
|
||||
// 最大输入99999,最小输入1
|
||||
nextTick(() => {
|
||||
if (val < 99999 && val > 1) {
|
||||
freight.value = parseInt(val * 100) / 100;
|
||||
}
|
||||
if (val > 99999) {
|
||||
freight.value = 99999;
|
||||
}
|
||||
});
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
getDetails(taskId);
|
||||
//
|
||||
if (users.isPickUp) {
|
||||
isPickUp.value = true;
|
||||
} else {
|
||||
isPickUp.value = false;
|
||||
}
|
||||
//
|
||||
if (users.isCollect) {
|
||||
isCollect.value = true;
|
||||
} else {
|
||||
isCollect.value = false;
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取详情
|
||||
const getDetails = async id => {
|
||||
await getDetail(id).then(res => {
|
||||
detailsData.value = res.data;
|
||||
freight.value = detailsData.value.freight;
|
||||
if (users.paymentMethod) {
|
||||
if (users.paymentMethod === 1) {
|
||||
detailsData.value.paymentMethod = 1;
|
||||
} else {
|
||||
detailsData.value.paymentMethod = 2;
|
||||
}
|
||||
}
|
||||
goods.value.weight = Number(detailsData.value.weight);
|
||||
goods.value.volume = Number(detailsData.value.volume);
|
||||
// 设置当前是到付还是寄付
|
||||
store.commit('user/setPaymentMethod', detailsData.value.paymentMethod);
|
||||
store.commit('user/setDetailsData', res.data);
|
||||
});
|
||||
};
|
||||
|
||||
// 去取件
|
||||
const handleSubmit = async () => {
|
||||
if (stopClick.value) {
|
||||
stopClick.value = false;
|
||||
// 表单校验
|
||||
const cards = card.value;
|
||||
const good = goods.value;
|
||||
// 未验证的身份证需要做校验
|
||||
if (!cards.isValidate && detailsData.value.idCardNoVerify !== 1) {
|
||||
stopClick.value = true;
|
||||
return uni.showToast({
|
||||
title: '请输入正确的身份证',
|
||||
duration: 1000,
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// 网络慢的时候添加按钮loading
|
||||
let times =
|
||||
setTimeout(()=>{
|
||||
uni.showLoading({
|
||||
title: 'loading',
|
||||
});
|
||||
},500)
|
||||
const details = detailsData.value;
|
||||
|
||||
// 要提交给后端的参数
|
||||
if (freight.value !== 0) {
|
||||
details.freight = freight.value;
|
||||
}
|
||||
const params = {
|
||||
amount: good.freightData ? good.freightData : Number(details.freight), //总额
|
||||
id: taskId, //任务id
|
||||
goodName: details.goodsType, //物品名称
|
||||
idCard: details.idCardNoVerify === 1 ? null : cards.idCard, //身份证号
|
||||
name: details.idCardNoVerify === 1 ? null : cards.name, //真实姓名
|
||||
payMethod: details.paymentMethod, //付款方式
|
||||
remark: details.remark, //备注
|
||||
volume: Number(good.volume), //体积
|
||||
weight: good.weight //重量
|
||||
};
|
||||
// 存储信息,二维码支付页面要用
|
||||
const payData = {
|
||||
memo: details.remark,
|
||||
productOrderNo: details.orderId,
|
||||
tradingAmount: params.amount
|
||||
};
|
||||
store.commit('user/setPayData', payData);
|
||||
|
||||
await getPickup(params)
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
// 操作成功后清除loading
|
||||
setTimeout(function () {
|
||||
uni.hideLoading();
|
||||
}, 500);
|
||||
clearTimeout(times)
|
||||
// TODO先保留次代码,后期需求可能有变更
|
||||
// // const type = details.paymentMethod;
|
||||
// // 跳转到取件成功页
|
||||
// uni.redirectTo({
|
||||
// url: '/pages/pay/index?type=' + type
|
||||
// });
|
||||
// store.commit('user/setIsPickUp', true);
|
||||
}
|
||||
setTimeout(()=>{
|
||||
stopClick.value = true;
|
||||
},3000)
|
||||
|
||||
})
|
||||
.catch(err => {
|
||||
return uni.showToast({
|
||||
title: err.msg,
|
||||
duration: 1000,
|
||||
icon: 'none'
|
||||
});
|
||||
});
|
||||
const type = details.paymentMethod;
|
||||
|
||||
// // 跳转到取件成功页
|
||||
uni.redirectTo({
|
||||
url: '/pages/pay/index?type=' + type
|
||||
});
|
||||
store.commit('user/setIsPickUp', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
// 复制订单号
|
||||
const handleCopy = () => {
|
||||
uni.setClipboardData({
|
||||
data: detailsData.value.orderId, // 要保存的内容
|
||||
success: function() {
|
||||
uni.showToast({
|
||||
title: '复制成功',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 是否修改总计金额
|
||||
const handleFreight = () => {
|
||||
isFreigthEdit.value = true;
|
||||
};
|
||||
// 获取运费金额
|
||||
const getFreight = val => {
|
||||
detailsData.value.freight = val;
|
||||
freight.value = detailsData.value.freight;
|
||||
};
|
||||
// 输入金额是否小于1
|
||||
const handleAmount = () => {
|
||||
nextTick(() => {
|
||||
if (freight.value < 1) {
|
||||
freight.value = 1;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 物品
|
||||
// 获取物品名称,获取子组件传的值
|
||||
const getGoodType = val => {
|
||||
detailsData.value.goodsType = val;
|
||||
};
|
||||
// 物品名称
|
||||
const handleGoods = () => {
|
||||
type.value = 1;
|
||||
handleOpen();
|
||||
};
|
||||
// 付款方式
|
||||
// 获取付款方式,获取子组件传的值
|
||||
const getPayMethod = val => {
|
||||
if (val === '寄付') {
|
||||
detailsData.value.paymentMethod = 1;
|
||||
} else {
|
||||
detailsData.value.paymentMethod = 2;
|
||||
}
|
||||
store.commit('user/setPaymentMethod', detailsData.value.paymentMethod);
|
||||
};
|
||||
// 付款方式选择
|
||||
const handlePayMethod = () => {
|
||||
type.value = 2;
|
||||
handleOpen();
|
||||
};
|
||||
// 备注
|
||||
// 获取备注内容,获取子组件传的值
|
||||
const getRemark = val => {
|
||||
detailsData.value.remark = val;
|
||||
};
|
||||
// 打开弹层写备注
|
||||
const handleRemark = () => {
|
||||
if (users.isBack !== 'collect') {
|
||||
type.value = 3;
|
||||
handleOpen();
|
||||
}
|
||||
};
|
||||
// 打开弹层
|
||||
const handleOpen = () => {
|
||||
method.value.dialogOpen();
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
store.commit('user/setPaymentMethod', null);
|
||||
store.commit('user/setCardData', null);
|
||||
store.commit('user/setIsPickUp', false);
|
||||
store.commit('user/setIsCollect', false);
|
||||
if (users.newType === 301) {
|
||||
uni.redirectTo({
|
||||
url: '/pages/news/system?title=取件相关&type=301'
|
||||
});
|
||||
} else if (users.detailType === 1) {
|
||||
// 如果是从历史取派的取件列表进入的,返回的时候进入到历史取派列表
|
||||
store.commit('user/setTabIndex', 0);
|
||||
uni.redirectTo({
|
||||
url: '/pages/history/index'
|
||||
});
|
||||
} else if (users.isSearch) {
|
||||
store.commit('user/setIsSearch', false);
|
||||
uni.redirectTo({
|
||||
url: '/pages/search/index'
|
||||
});
|
||||
} else {
|
||||
store.commit('user/setTabIndex', 0);
|
||||
uni.redirectTo({
|
||||
url: '/pages/pickup/index'
|
||||
});
|
||||
}
|
||||
};
|
||||
// 去收款
|
||||
const handleReceipt = () => {
|
||||
store.commit('user/setPayData', {});
|
||||
uni.redirectTo({
|
||||
url: '/pages/pay/scanPay'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
183
project-wl-kuaidiyuan-uniapp-vue3/pages/details/orderMap.vue
Normal file
183
project-wl-kuaidiyuan-uniapp-vue3/pages/details/orderMap.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<!-- 订单跟踪详情页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="content">
|
||||
<view class="bottmBox">
|
||||
<view class="orderList">
|
||||
<view
|
||||
class="logistics-orderInfo logistics-orderInfo-item"
|
||||
:class="[index === 0 ? 'active' : '']"
|
||||
:key="index"
|
||||
v-for="(item, index) in markers.value"
|
||||
>
|
||||
<view class="logistics-orderInfo-left">
|
||||
<view
|
||||
class="circle gray"
|
||||
v-if="['已拒收', '已签收', '已取件'].includes(item.status)"
|
||||
>
|
||||
{{
|
||||
item.status === "已拒收"
|
||||
? "拒"
|
||||
: item.status === "已签收"
|
||||
? "签"
|
||||
: "取"
|
||||
}}
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="circle gray"
|
||||
v-else-if="
|
||||
(index === 0 && ['运送中', '派送中'].includes(item.status)) ||
|
||||
(index > 0 && markers.value[index - 1].status !== '运送中')
|
||||
"
|
||||
>
|
||||
<image :class="item.status === '派送中' ? 'ys' : 'ps'"></image>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="point"
|
||||
v-else-if="
|
||||
index > 0 && markers.value[index - 1].status === '运送中'
|
||||
"
|
||||
></view>
|
||||
|
||||
<view
|
||||
class="line"
|
||||
v-if="!(index === markers.value.length - 1)"
|
||||
:class="item.status === '运送中' ? 'short' : ''"
|
||||
></view>
|
||||
</view>
|
||||
<view class="logistics-orderInfo-right">
|
||||
<view
|
||||
class="status"
|
||||
v-if="
|
||||
!(
|
||||
index > 0 &&
|
||||
markers.value[index - 1].status === '运送中' &&
|
||||
item.status === '运送中'
|
||||
)
|
||||
"
|
||||
>{{ item.status }}</view
|
||||
>
|
||||
<view class="time">{{ item.created }}</view>
|
||||
<view class="desc" v-html="strInit(item.info)"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- TODO此处代码保留 -->
|
||||
<!-- <map class="mapBox" :latitude="latitude" :longitude="longitude" scale="6">
|
||||
<cover-view class="bottmBox" v-if="markers.value">
|
||||
<cover-view class="orderList" scroll-top='0'>
|
||||
<cover-view class="logistics-orderInfo logistics-orderInfo-item" :class="[index===0?'active':'']" :key="index"
|
||||
v-for='(item,index) in markers.value'>
|
||||
<cover-view class="logistics-orderInfo-left">
|
||||
<cover-view class="circle" v-if="['已拒收','已签收','已取件'].includes(item.status)">
|
||||
<cover-view class="iconBg" ><cover-view class="fontPostion">{{item.status==='已拒收'?'拒':item.status==='已签收'?'签':'取'}}</cover-view></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="circle"
|
||||
v-else-if="index ===0 &&['运送中','派送中'].includes(item.status) || index>0 && markers.value[index-1].status !=='运送中'">
|
||||
<cover-view class="iconBg" ><cover-image :src="item.status==='派送中'?'../../static/yunshuzhong.png':'../../static/paisong.png'"></cover-image></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="point" v-else-if="index>0 && markers.value[index-1].status==='运送中'"></cover-view>
|
||||
|
||||
<cover-view class="line" v-if='!(index === markers.value.length - 1)'
|
||||
:class="item.status==='运送中'?'short':''"></cover-view>
|
||||
</cover-view>
|
||||
<cover-view class="logistics-orderInfo-right">
|
||||
<cover-view class="status"
|
||||
v-if='!(index>0 && markers.value[index-1].status==="运送中" &&item.status==="运送中")'>
|
||||
{{item.status}}
|
||||
</cover-view>
|
||||
<cover-view class="time">{{item.created}}</cover-view>
|
||||
<cover-view class="desc"
|
||||
:class="index === 0|| item.status === 23010?'active':''"
|
||||
>{{item.info}}
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
</map> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 导入接口
|
||||
import { getTracks } from "@/pages/api/index.js";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user; //vuex获取、储存数据
|
||||
const title = ref("订单跟踪"); //nav标题
|
||||
const latitude = ref(39.91667); //维度
|
||||
const longitude = ref(116.41667); //经度
|
||||
// 起始位置
|
||||
const markers = reactive([]);
|
||||
// 路线点
|
||||
const polyline = reactive([
|
||||
// 第一条线
|
||||
{
|
||||
// 每个点的经纬度
|
||||
points: [
|
||||
{ longitude: 116.41667, latitude: 39.91667 },
|
||||
{ longitude: 118.78333, latitude: 32.05 },
|
||||
],
|
||||
// 路线颜色
|
||||
color: "#EF4F3F",
|
||||
// 线条宽度
|
||||
width: 12,
|
||||
},
|
||||
]);
|
||||
// ------生命周期------
|
||||
// ------定义方法------
|
||||
onMounted(() => {
|
||||
getTrack();
|
||||
});
|
||||
|
||||
//将后端传来的字符串中的数字变为红色
|
||||
const strInit = (value) => {
|
||||
let strText = value;
|
||||
let replaceText = [];
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
replaceText.push("" + i);
|
||||
}
|
||||
// 后面
|
||||
const str = value.split("【")[1];
|
||||
// 转换成html形式解析
|
||||
for (let i = 0; i < replaceText.length; i++) {
|
||||
var replaceString = `<span class='red'>` + replaceText[i] + `</span>`;
|
||||
strText = strText.replace(RegExp(replaceText[i], "g"), replaceString);
|
||||
}
|
||||
|
||||
// 这里再把这个红色替换成你想要的颜色
|
||||
// 由于在循环体里面数字会被替换,所以用了一个单词(red)来当成初始色
|
||||
strText = strText.replace(RegExp("red", "g"), "red");
|
||||
return strText;
|
||||
};
|
||||
// 获取运单轨迹
|
||||
const getTrack = async () => {
|
||||
await getTracks(users.detailsData.transportOrderId).then((res) => {
|
||||
if (res.code === 200) {
|
||||
markers.value = res.data.reverse();
|
||||
polyline[0].points = res.data.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
<style></style>
|
||||
450
project-wl-kuaidiyuan-uniapp-vue3/pages/details/waybill.vue
Normal file
450
project-wl-kuaidiyuan-uniapp-vue3/pages/details/waybill.vue
Normal file
@@ -0,0 +1,450 @@
|
||||
<!-- 已取件、已签收、已取消详情页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="detailBox">
|
||||
<!-- 运单号 -->
|
||||
<view class="boxBg">
|
||||
<view class="tit">
|
||||
<text>
|
||||
<!-- 当状态是去派送4\签收5的时候显示运单号 -->
|
||||
<text v-if="taskStatus === 4 || taskStatus === 5">运单号:{{ detailsData.transportOrderId }}</text>
|
||||
<text v-else>订单号:SD{{ detailsData.orderId }}</text>
|
||||
<!-- end -->
|
||||
<icon @click="handleCopy" class="copy"></icon>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 取件信息 -->
|
||||
<Address :detailsData="detailsData" class="pickupBox"></Address>
|
||||
<!-- end -->
|
||||
<!-- 物品信息 -->
|
||||
<view class="boxBg">
|
||||
<view class="wayCon">
|
||||
<view class="item">
|
||||
物品名称
|
||||
<text>{{ detailsData.goodsType }}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
物品重量
|
||||
<text>{{ detailsData.weight }}kg</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
物品体积
|
||||
<text>{{ detailsData.volume }}m³</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
总计金额
|
||||
<text>{{ detailsData.freight }}元</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="wayCon remark">
|
||||
<view class="item">备注</view>
|
||||
<view class="item">
|
||||
<text>{{ detailsData.remark ? detailsData.remark : '暂无' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="wayCon">
|
||||
<view class="item">
|
||||
付款方式
|
||||
<text>{{ detailsData.paymentMethod === 1 ? '寄付' : '到付' }}</text>
|
||||
</view>
|
||||
<!-- 当状态是已签收5,显示签收人 -->
|
||||
<view class="item" v-if="taskStatus === 5">
|
||||
签收人
|
||||
<text>{{ detailsData.paymentMethod === 1 ? '本人' : '代收' }}</text>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 当状态是去派件4的时候显示签收人选择、拒收、签收按钮 -->
|
||||
<view class="boxBg" v-if="detailsData.taskType === 2 && detailsData.status === 1">
|
||||
<view class="tit">
|
||||
<text>签收人</text>
|
||||
<view class="goodsSelect" v-if="(isSign && detailsData.paymentMethod == 1) || (isPickUp && detailsData.paymentMethod === 2)">
|
||||
<text class="textInfo">{{ detailsData.signRecipient === 1 ? '本人' : '代收' }}</text>
|
||||
</view>
|
||||
<view class="goodsSelect" @click="handleSignOpen" v-else>
|
||||
<text class="textInfo">{{ detailsData.signRecipient === 1 ? '本人' : '代收' }}</text>
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- {{detailsData.status}}--{{users.isNew}}--{{taskStatus}} -->
|
||||
<!-- <view
|
||||
class="btnBox subBtnBox"
|
||||
v-if="(detailsData.status===1&&!users.isNew)||(taskStatus === 4&&!users.isNew) || (taskStatus === 0 && users.taskType === 2) || (users.detailType === 2 && taskStatus === 4) || (detailsData.status===1&&users.detailType === 2 && taskStatus === 6)"
|
||||
>
|
||||
<button v-if="(!isSign && !isPickUp) || (isSign && !isPickUp && detailsData.paymentMethod === 2)" class="btn-default uni-sub-btn" @click="handleRejection(detailsData.id)">
|
||||
拒收
|
||||
</button>
|
||||
<button v-if="!isPickUp" class="btn-default" @click="handleSign(detailsData.id)">签收</button>
|
||||
<button v-if="isPickUp && detailsData.paymentMethod === 2" class="btn-default uni-mini" @click="handleReceipt">去收款</button>
|
||||
<button v-if="isSign && detailsData.paymentMethod == 1" class="btn-default uni-mini btn-forbid">已签收</button>
|
||||
</view> -->
|
||||
<!-- end -->
|
||||
<!-- 当状态是已取件2或者已签收5显示跟踪按钮 ||(taskStatus === 6&&users.taskType===2)-->
|
||||
<!-- <view class="btnBox" v-if="(detailsData.status===2&&users.isNew)||(taskStatus === 2&&users.isNew) || taskStatus === 5 || (users.detailType === 2 && taskStatus === 6 &&users.isNew) || (users.detailType === 1 && taskStatus === 6)">
|
||||
<button class="btn-default uni-mini" @click="handleOrder">订单跟踪</button>
|
||||
</view> -->
|
||||
<!-- end -->
|
||||
<!-- 付款方式paymentMethod:1寄付,2到付 -->
|
||||
<!-- 付款状态paymentStatus:1未付,2已付 -->
|
||||
<!-- 签收状态signStatus:1为已签收,2为拒收 -->
|
||||
<!-- 任务类型taskType:1为取件任务,2为派件任务 -->
|
||||
<!-- 任务状态status:1未取派,2完成,3取消 未派件的情况下显示的按钮 -->
|
||||
<!-- 派件 -->
|
||||
<view v-if="detailsData.taskType === 2">
|
||||
<!-- 未派件未签收-->
|
||||
<view class="btnBox subBtnBox" v-if="detailsData.status === 1">
|
||||
<button class="btn-default uni-sub-btn" v-if="detailsData.signStatus !== 1" @click="handleRejection(detailsData.id)">拒收</button>
|
||||
<button class="btn-default" v-if="detailsData.signStatus !== 1" @click="handleSign(detailsData.id)">签收</button>
|
||||
</view>
|
||||
<!-- end -->
|
||||
|
||||
<!-- 已经派件未付款或者已经签收 -->
|
||||
|
||||
<view class="btnBox subBtnBox" v-else>
|
||||
<!-- 签收后未付款,isPickUp代表未收款进入收款页,返回时候的显示去收款按钮 -->
|
||||
<!-- 已签收到的订单付但是未付款 应该显示去收款-->
|
||||
<button
|
||||
v-if="isPickUp && detailsData.paymentStatus === 1 && detailsData.paymentMethod === 2 && detailsData.signStatus === 1"
|
||||
class="btn-default uni-mini"
|
||||
@click="handleReceipt"
|
||||
>
|
||||
去收款
|
||||
</button>
|
||||
<!-- 签收状态是已签收,显示已签收按钮 -->
|
||||
<!-- isSign代表已经点击了签收,进入到了派件成功页,返回的时候要显示已经签收 -->
|
||||
<button v-if="isSign && detailsData.signStatus === 1" class="btn-default uni-mini btn-forbid">已签收</button>
|
||||
<!-- 当状态是已签收显示跟踪按钮-->
|
||||
<!-- 已派件 -->
|
||||
|
||||
<view v-if="detailsData.status === 2" class="btnBox">
|
||||
<!-- 未付款、从消息签收提醒 -->
|
||||
<button
|
||||
v-if="
|
||||
(!isPickUp && !isSign && detailsData.paymentMethod === 1) ||
|
||||
users.isNew ||
|
||||
(!isPickUp && !isSign && detailsData.paymentMethod === 2 && detailsData.paymentStatus === 1) ||
|
||||
(!isPickUp && !isSign && detailsData.paymentMethod === 2 && detailsData.paymentStatus === 2 && detailsData.signStatus == 1)
|
||||
"
|
||||
class="btn-default uni-mini"
|
||||
@click="handleOrder"
|
||||
>
|
||||
订单跟踪
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- end -->
|
||||
</view>
|
||||
|
||||
<!-- 取件 -->
|
||||
<view v-else>
|
||||
<!-- 当状态是已取件显示跟踪按钮-->
|
||||
|
||||
<view class="btnBox" v-if="detailsData.status === 2"><button class="btn-default uni-mini" @click="handleOrder">订单跟踪</button></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- 物品名称、付款选择、备注弹层 -->
|
||||
<Uppop ref="sign" @getSignType="getSignType" :type="type"></Uppop>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
// 接口
|
||||
import { getDetail, rejection, tasksSign, PositionUpload } from '@/pages/api/index.js';
|
||||
import { positionUploadHandle } from '@/utils/index.js';
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from '@/components/uni-nav/index.vue';
|
||||
// 地址
|
||||
import Address from './components/address.vue';
|
||||
// 付款方式先择、物品名称弹层
|
||||
import Uppop from './components/uppop.vue';
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user; //vuex获取、储存数据
|
||||
const taskStatus = users.taskStatus; //获取列表页传过来的取件类型 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const sign = ref(); // 定义ref 获取子组件方法或者值
|
||||
const taskId = users.taskId;
|
||||
const title = users.taskStatus === 4 || (taskStatus === 0 && users.taskType === 2) ? '去派件' : '运单详情'; //nav标题
|
||||
let detailsData = ref({}); //详情数据
|
||||
let type = ref(0); //物品名称、付款方式、签收人公用一个弹层,根据不同type值来做判断 物品:1,付款方式:2,备注:3,签收人:4
|
||||
|
||||
let isPickUp = ref(false); //是否去签收
|
||||
let isCollect = ref(false); //到付的情况下,是否触发去取件后到,显示按钮为已取件
|
||||
let isSign = ref(false); //是否已签收
|
||||
const stopClick = ref(false); //防止连续提交
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
getDetails(taskId);
|
||||
if (users.isPickUp) {
|
||||
isPickUp.value = true;
|
||||
} else {
|
||||
isPickUp.value = false;
|
||||
}
|
||||
//
|
||||
if (users.isSign) {
|
||||
isSign.value = true;
|
||||
} else {
|
||||
isSign.value = false;
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取详情
|
||||
const getDetails = async id => {
|
||||
await getDetail(id).then(res => {
|
||||
detailsData.value = res.data;
|
||||
// 设置当前是到付还是寄付
|
||||
store.commit('user/setPaymentMethod', detailsData.value.paymentMethod);
|
||||
store.commit('user/setDetailsData', res.data);
|
||||
});
|
||||
};
|
||||
// 拒收
|
||||
const handleRejection = async id => {
|
||||
if (stopClick.value) {
|
||||
return;
|
||||
}
|
||||
stopClick.value = true;
|
||||
// 网络慢的时候添加按钮loading
|
||||
let times =
|
||||
setTimeout(()=>{
|
||||
uni.showLoading({
|
||||
title: 'loading',
|
||||
});
|
||||
},500)
|
||||
await rejection(id)
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
// 拒收之后上报位置
|
||||
positionUploadHandle(true);
|
||||
// 操作成功后清除loading
|
||||
setTimeout(function () {
|
||||
uni.hideLoading();
|
||||
}, 500);
|
||||
clearTimeout(times)
|
||||
let timeId = setTimeout(() => {
|
||||
// 如果是从全部派送进入到详情,拒收后要跳转到全部取派的 全部派件tab值为1
|
||||
if (taskStatus === 6 && users.detailType === 2) {
|
||||
store.commit('user/setTabIndex', 1);
|
||||
uni.redirectTo({
|
||||
url: '/pages/history/index'
|
||||
});
|
||||
} else {
|
||||
// 如果是派件列表tab是0
|
||||
store.commit('user/setTabIndex', 0);
|
||||
uni.redirectTo({
|
||||
url: '/pages/delivery/index'
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
uni.showToast({
|
||||
title: '用户拒收',
|
||||
icon: 'none',
|
||||
duration: '1000'
|
||||
});
|
||||
}
|
||||
stopClick.value = false;
|
||||
})
|
||||
.catch(err => {
|
||||
uni.showToast({
|
||||
title: err.msg,
|
||||
icon: 'none',
|
||||
duration: '1000'
|
||||
});
|
||||
});
|
||||
};
|
||||
// 签收
|
||||
const handleSign = async id => {
|
||||
if (stopClick.value) {
|
||||
return;
|
||||
}
|
||||
stopClick.value = true;
|
||||
// 网络慢的时候添加按钮loading
|
||||
let times =
|
||||
setTimeout(()=>{
|
||||
uni.showLoading({
|
||||
title: 'loading',
|
||||
});
|
||||
},500)
|
||||
const params = {
|
||||
id: id,
|
||||
signRecipient: detailsData.value.signRecipient
|
||||
};
|
||||
// 跳转到签收成功页
|
||||
await tasksSign(params).then(res => {
|
||||
if (res.code === 200) {
|
||||
// 签收之后上报位置
|
||||
positionUploadHandle(true);
|
||||
// 操作成功后清除loading
|
||||
setTimeout(function () {
|
||||
uni.hideLoading();
|
||||
}, 500);
|
||||
clearTimeout(times)
|
||||
const type = detailsData.value.paymentMethod; //获取付款类型,根据付款类型来判断是否要进入付款页面
|
||||
|
||||
// 跳转到签收成功页
|
||||
uni.redirectTo({
|
||||
url: '/pages/pay/index?type=' + type
|
||||
});
|
||||
store.commit('user/setIsPickUp', true);
|
||||
store.commit('user/setIsDelivery', true); //因为取件和派件用的是一个公用页面,所以用isDelivery来判断是不是从派件进到签收成功页面的
|
||||
}
|
||||
stopClick.value = false;
|
||||
});
|
||||
};
|
||||
// 复制订单号
|
||||
const handleCopy = () => {
|
||||
uni.setClipboardData({
|
||||
data: detailsData.value.orderId, // 要保存的内容
|
||||
success: function() {
|
||||
uni.showToast({
|
||||
title: '复制成功',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取签收人名称,获取子组件传的值
|
||||
const getSignType = val => {
|
||||
detailsData.value.signRecipient = val;
|
||||
};
|
||||
// 签收人
|
||||
const handleSignOpen = () => {
|
||||
type.value = 4;
|
||||
sign.value.dialogOpen();
|
||||
};
|
||||
// 订单追踪
|
||||
const handleOrder = () => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/details/orderMap'
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
store.commit('user/setIsPickUp', false);
|
||||
store.commit('user/setIsSign', false);
|
||||
store.commit('user/setIsDelivery', false);
|
||||
// 根据不同的状态跳转到不同的页面
|
||||
// 待取件、已取件、已取消
|
||||
if (taskStatus === 1 || taskStatus === 2 || taskStatus === 3) {
|
||||
if (taskStatus === 1) {
|
||||
// 待取件
|
||||
store.commit('user/setTabIndex', 0);
|
||||
} else if (taskStatus === 2) {
|
||||
// 已取件
|
||||
store.commit('user/setTabIndex', 1);
|
||||
} else {
|
||||
// 已取消
|
||||
store.commit('user/setTabIndex', 2);
|
||||
}
|
||||
// 如果是从搜索列表进来的,返回的时候要返回到搜索列表
|
||||
if (users.isSearch) {
|
||||
store.commit('user/setIsSearch', false);
|
||||
uni.redirectTo({
|
||||
url: '/pages/search/index'
|
||||
});
|
||||
} else {
|
||||
// 如果是从待取件、已取件、已取消列表进来的,返回的时候要返回相对应的tab页
|
||||
uni.redirectTo({
|
||||
url: '/pages/pickup/index'
|
||||
});
|
||||
}
|
||||
} else if ((taskStatus === 5 && users.newType !== 302 && !users.isNew) || (taskStatus === 4 && users.detailType !== 2 && users.newType !== 304)) {
|
||||
if (taskStatus === 4) {
|
||||
store.commit('user/setTabIndex', 0);
|
||||
} else {
|
||||
store.commit('user/setTabIndex', 1);
|
||||
}
|
||||
if (users.isSearch) {
|
||||
store.commit('user/setIsSearch', false);
|
||||
uni.redirectTo({
|
||||
url: '/pages/search/index'
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: '/pages/delivery/index'
|
||||
});
|
||||
}
|
||||
} else if (
|
||||
((taskStatus === 6 || taskStatus === 4) && users.detailType === 2) ||
|
||||
(users.detailType === 1 && users.newType !== 302) ||
|
||||
(taskStatus === 6 && users.detailType === 1)
|
||||
) {
|
||||
// 从历史记录派件进入到详情,返回的时候返回历史记录
|
||||
if (taskStatus === 6 && users.detailType === 1) {
|
||||
store.commit('user/setTabIndex', 0);
|
||||
}
|
||||
if (taskStatus === 6 && users.detailType === 2) {
|
||||
store.commit('user/setTabIndex', 1);
|
||||
}
|
||||
uni.redirectTo({
|
||||
url: '/pages/history/index'
|
||||
});
|
||||
// 从派件列表进入详情页
|
||||
if (taskStatus === 4 && users.detailType === 2) {
|
||||
store.commit('user/setTabIndex', 1);
|
||||
if (users.isSearch) {
|
||||
store.commit('user/setIsSearch', false);
|
||||
uni.redirectTo({
|
||||
url: '/pages/search/index'
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: '/pages/history/index'
|
||||
});
|
||||
}
|
||||
}
|
||||
if (taskStatus === 4 && users.detailType === 1) {
|
||||
store.commit('user/setTabIndex', 0);
|
||||
uni.redirectTo({
|
||||
url: '/pages/delivery/index'
|
||||
});
|
||||
}
|
||||
} else if (users.newType === 301) {
|
||||
// 跳转到消息寄件相关
|
||||
uni.redirectTo({
|
||||
url: '/pages/news/system?title=取件相关&type=301'
|
||||
});
|
||||
} else if (users.newType === 302) {
|
||||
// 跳转到消息寄件相关
|
||||
uni.redirectTo({
|
||||
url: '/pages/news/system?title=签收提醒&type=302'
|
||||
});
|
||||
} else if (users.newType === 303) {
|
||||
// 跳转到消息快件取消
|
||||
uni.redirectTo({
|
||||
url: '/pages/news/system?title=快件取消&type=303'
|
||||
});
|
||||
} else if (users.newType === 304) {
|
||||
// 跳转到消息派件相关
|
||||
uni.redirectTo({
|
||||
url: '/pages/news/system?title=派件相关&type=304'
|
||||
});
|
||||
} else {
|
||||
store.commit('user/setTabIndex', 0);
|
||||
uni.redirectTo({
|
||||
url: '/pages/delivery/index'
|
||||
});
|
||||
}
|
||||
store.commit('user/setIsNew', false);
|
||||
};
|
||||
// 去收款
|
||||
const handleReceipt = () => {
|
||||
store.commit('user/setPayData', {});
|
||||
uni.redirectTo({
|
||||
url: '/pages/pay/scanPay'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,76 @@
|
||||
<!--收寄地址-->
|
||||
<template>
|
||||
<view class="boxBg">
|
||||
<view class="addressCon">
|
||||
<view class="item" @click="handleDate(1)">
|
||||
<view class="sendIcon">寄</view>
|
||||
<view class="address">
|
||||
<view :class="mailCity.province ? 'active' : ''">
|
||||
<view v-if="!mailCity.province">请选择寄件城市</view>
|
||||
<view v-else>
|
||||
<text>{{ mailCity.province }}</text>
|
||||
<text>{{ mailCity.city }}</text>
|
||||
<text>{{ mailCity.area }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
</view>
|
||||
<view class="item" @click="handleDate(2)">
|
||||
<view class="receiveIcon">收</view>
|
||||
<view class="address">
|
||||
<view :class="consigneeCity.province ? 'active' : ''">
|
||||
<view v-if="!consigneeCity.province">请选择收件城市</view>
|
||||
<view v-else>
|
||||
<text>{{ consigneeCity.province }}</text>
|
||||
<text>{{ consigneeCity.city }}</text>
|
||||
<text>{{ consigneeCity.area }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<icon class="nextIcon"></icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<CityPopup ref="city" :type="type" @getCity="getCity"></CityPopup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
// 接口pai
|
||||
// 导入组件
|
||||
// 城市弹层
|
||||
import CityPopup from "@/components/uni-address/index.vue";
|
||||
// ------定义变量------
|
||||
const city = ref(); //定义子组件ref,获取子组件方法
|
||||
const emit = defineEmits();
|
||||
let type = ref(null); //触发的寄件还是收件:type=1 寄件;type=2 收件
|
||||
let mailCity = ref({}); //寄件数据
|
||||
let consigneeCity = ref({}); //收件数据
|
||||
// ------定义方法------
|
||||
// 地址弹层弹层
|
||||
const handleDate = (val) => {
|
||||
// type代表触发的寄件还是收件:type=1 寄件;type=2 收件
|
||||
type.value = val;
|
||||
city.value.handleOpen();
|
||||
};
|
||||
// 获取区县
|
||||
const getCity = (obj) => {
|
||||
if (type.value === 1) {
|
||||
mailCity.value = obj;
|
||||
} else {
|
||||
consigneeCity.value = obj;
|
||||
}
|
||||
if (mailCity.value.areaId && consigneeCity.value.areaId) {
|
||||
emit("handleCity", true);
|
||||
}
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
mailCity,
|
||||
consigneeCity,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,290 @@
|
||||
<!--重量体积计算-->
|
||||
<template>
|
||||
<view class="boxBg">
|
||||
<view class="goodsCon">
|
||||
<view class="item">
|
||||
<text>预估重量</text>
|
||||
<view class="bg goodInfo">
|
||||
<view
|
||||
class="symbol"
|
||||
:class="isLessThan ? 'active' : ''"
|
||||
@click="handleMinus"
|
||||
>-</view
|
||||
>
|
||||
<view class="num">
|
||||
<input
|
||||
class="uni-input"
|
||||
type="number"
|
||||
maxlength="6"
|
||||
v-model="weight"
|
||||
@blur="handleSymbol"
|
||||
/>
|
||||
<text>kg</text>
|
||||
</view>
|
||||
<view
|
||||
class="symbol"
|
||||
:class="isExceed ? 'active' : ''"
|
||||
@click="handleAdd"
|
||||
>+</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text>总体积</text>
|
||||
<view class="bg goodInfo">
|
||||
<!-- 暂时去除 :class="isLessThanVolume ? 'active' : ''" -->
|
||||
<view class="symbol" @click="handleVolumeMinus">-</view>
|
||||
<view class="num">
|
||||
<input
|
||||
class="uni-input"
|
||||
type="number"
|
||||
maxlength="6"
|
||||
v-model="volume"
|
||||
@blur="handleVolume"
|
||||
/>
|
||||
<text>m³</text>
|
||||
</view>
|
||||
<!-- 暂时去除 :class="isExceedVolume ? 'active' : ''" -->
|
||||
<view class="symbol" @click="handleVolumeAdd">+</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item calculate">
|
||||
<view class="bg">
|
||||
<input
|
||||
class="uni-input"
|
||||
type="number"
|
||||
maxlength="3"
|
||||
v-model="measureLong"
|
||||
placeholder="长"
|
||||
@input="handleCalculate"
|
||||
/>
|
||||
<text :class="measureLong ? 'active' : ''">cm</text>
|
||||
</view>
|
||||
<text>*</text>
|
||||
<view class="bg">
|
||||
<input
|
||||
class="uni-input"
|
||||
type="number"
|
||||
maxlength="3"
|
||||
v-model="measureWidth"
|
||||
placeholder="宽"
|
||||
@input="handleCalculate"
|
||||
/>
|
||||
<text :class="measureWidth ? 'active' : ''">cm</text>
|
||||
</view>
|
||||
<text>*</text>
|
||||
<view class="bg">
|
||||
<input
|
||||
class="uni-input"
|
||||
type="number"
|
||||
maxlength="3"
|
||||
v-model="measureHigh"
|
||||
placeholder="高"
|
||||
@input="handleCalculate"
|
||||
/>
|
||||
<text :class="measureHigh ? 'active' : ''">cm</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, nextTick } from "vue";
|
||||
// ------定义变量------
|
||||
let weight = ref(1); //重量
|
||||
let volume = ref(0); //体积
|
||||
let measureLong = ref(null); //长
|
||||
let measureWidth = ref(null); //宽
|
||||
let measureHigh = ref(null); //高
|
||||
let isLessThan = ref(true); //判断重量是否小于0.1
|
||||
let isExceed = ref(false); //判断重量是否大于9999
|
||||
let isLessThanVolume = ref(true); //判断体积是否小于0.0001m³
|
||||
let isExceedVolume = ref(false); //判断体积是否大于99m³
|
||||
|
||||
// 暴漏给父组件
|
||||
defineExpose({
|
||||
weight,
|
||||
volume,
|
||||
measureLong,
|
||||
measureWidth,
|
||||
measureHigh,
|
||||
});
|
||||
// ------生命周期------
|
||||
// 监听重量数值,小数点后保留一位
|
||||
watch(weight, (newValue, oldValue) => {
|
||||
const val = Number(newValue);
|
||||
nextTick(() => {
|
||||
// 数值小于0.1并且大于0 数值默认为1
|
||||
if (val < 0.1 && val > 0) {
|
||||
weight.value = 1;
|
||||
}
|
||||
// 处理小数点,小数点保留1位
|
||||
if (val > 0.1) {
|
||||
weight.value = parseInt(val * 10) / 10;
|
||||
}
|
||||
// 数值小于等于1 左侧按钮置灰
|
||||
if (val <= 1) {
|
||||
isLessThan.value = true; //左侧减号置灰
|
||||
} else {
|
||||
isLessThan.value = false; //左侧减号去除置灰
|
||||
if (val >= 9999) {
|
||||
weight.value = 9999;
|
||||
isExceed.value = true; //右侧加号置灰
|
||||
} else {
|
||||
isExceed.value = false; //右侧加号去除置灰
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
// 监听长,取整
|
||||
watch(measureLong, (newValue, oldValue) => {
|
||||
const val = Number(newValue);
|
||||
nextTick(() => {
|
||||
measureLong.value = Math.floor(val);
|
||||
if (newValue <= 0) {
|
||||
measureLong.value = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
// 监听宽,取整
|
||||
watch(measureWidth, (newValue, oldValue) => {
|
||||
const val = Number(newValue);
|
||||
nextTick(() => {
|
||||
measureWidth.value = Math.floor(val);
|
||||
if (newValue <= 0) {
|
||||
measureWidth.value = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
// 监听高,取整
|
||||
watch(measureHigh, (newValue, oldValue) => {
|
||||
const val = Number(newValue);
|
||||
nextTick(() => {
|
||||
measureHigh.value = Math.floor(val);
|
||||
if (newValue <= 0) {
|
||||
measureHigh.value = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
// ------定义方法------
|
||||
//触发重量输入如果输入0,自动判断为1kg,最小可输入值为0.1kg,最大值为9999kg
|
||||
const handleSymbol = (e) => {
|
||||
const value = e.detail.value;
|
||||
if (value < 0.1) {
|
||||
weight.value = 1;
|
||||
isLessThan.value = true; //左侧减号置灰
|
||||
} else {
|
||||
if (value > 0.1 && value <= 1) {
|
||||
isLessThan.value = true;
|
||||
} else {
|
||||
isLessThan.value = false; //左侧减号去除置灰
|
||||
}
|
||||
if (value >= 9999) {
|
||||
isExceed.value = true; //右侧加号置灰
|
||||
weight.value = 9999;
|
||||
} else {
|
||||
isExceed.value = false; //右侧加号去除置灰
|
||||
}
|
||||
}
|
||||
};
|
||||
// 减重量
|
||||
const handleMinus = () => {
|
||||
// 重量减去1
|
||||
if (weight.value > 1) {
|
||||
weight.value--;
|
||||
isExceed.value = false; //右侧加号去除置灰
|
||||
weight.value = weight.value.toFixed(1);
|
||||
}
|
||||
if (weight.value <= 0) {
|
||||
weight.value = 1;
|
||||
isLessThan.value = true; //左侧减号置灰
|
||||
}
|
||||
};
|
||||
// 加重量
|
||||
const handleAdd = () => {
|
||||
// 重量加1
|
||||
if (weight.value < 9999) {
|
||||
++weight.value;
|
||||
isLessThan.value = false; //左侧减号去除置灰
|
||||
}
|
||||
if (weight.value === 9999) {
|
||||
isExceed.value = true; //右侧加号置灰
|
||||
}
|
||||
};
|
||||
|
||||
// 体积
|
||||
const handleVolume = (e) => {
|
||||
const value = Number(e.detail.value);
|
||||
if (value < 0.0001) {
|
||||
volume.value = 0;
|
||||
} else {
|
||||
if (value > 99) {
|
||||
volume.value = 99;
|
||||
return uni.showToast({
|
||||
title: "体积最大可不能超过99m³",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
// 减体积
|
||||
const handleVolumeMinus = () => {
|
||||
// 体积减去1
|
||||
if (volume.value > 1) {
|
||||
volume.value--;
|
||||
volume.value = parseInt(volume.value * 10000) / 10000;
|
||||
}
|
||||
// 体积
|
||||
if (volume.value <= 0 || volume.value === 1) {
|
||||
volume.value = 0;
|
||||
}
|
||||
};
|
||||
// 加体积
|
||||
const handleVolumeAdd = () => {
|
||||
// 体积加1
|
||||
if (volume.value < 99) {
|
||||
++volume.value;
|
||||
isLessThanVolume.value = false; //左侧减号去除置灰
|
||||
}
|
||||
if (volume.value === 99) {
|
||||
isExceedVolume.value = true; //右侧加号置灰
|
||||
}
|
||||
};
|
||||
// 计算立方米
|
||||
const handleCalculate = () => {
|
||||
const long = measureLong.value; //长
|
||||
const wide = measureWidth.value; //宽
|
||||
const height = measureHigh.value; //高
|
||||
// 长宽高都大于1才可以计算
|
||||
if (long >= 1 && wide >= 1 && height >= 1) {
|
||||
nextTick(() => {
|
||||
// 计算立方米:长/100*宽/100*高/100
|
||||
let val = (long / 100) * (wide / 100) * (height / 100);
|
||||
// 立方米必须大于0.0001
|
||||
if (val < 0.0001) {
|
||||
volume.value = 0;
|
||||
} else if (val > 99) {
|
||||
// 小数点后保留四位小数
|
||||
isExceedVolume.value = true; //右侧加号置灰
|
||||
volume.value = 99;
|
||||
return uni.showToast({
|
||||
title: "体积最大可不能超过99m³",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
} else {
|
||||
volume.value = parseInt(val * 10000) / 10000;
|
||||
// 如果体积大于1左侧减号按钮去除置灰
|
||||
if (val > 1) {
|
||||
isLessThanVolume.value = false; //左侧减号去除置灰
|
||||
} else {
|
||||
isLessThanVolume.value = true; //左侧减号置灰
|
||||
}
|
||||
isExceedVolume.value = false; //右侧加号去除置灰
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!--重量体积查询结果-->
|
||||
<template>
|
||||
<view class="boxBg result">
|
||||
<view>计费重量:{{ baseData.weight }} kg</view>
|
||||
<view>计费体积:{{ baseData.volumeValue }} m³</view>
|
||||
<view
|
||||
>首重(1.0kg){{ baseData.firstWeight }}元,续重{{
|
||||
baseData.continuousWeight
|
||||
}}元/kg</view
|
||||
>
|
||||
<view class="price"><text>¥</text>{{ baseData.freight }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
baseData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
88
project-wl-kuaidiyuan-uniapp-vue3/pages/freight/index.scss
Normal file
88
project-wl-kuaidiyuan-uniapp-vue3/pages/freight/index.scss
Normal file
@@ -0,0 +1,88 @@
|
||||
body,
|
||||
uni-page-body {
|
||||
background: var(--neutral-color-background) !important;
|
||||
}
|
||||
.freightBox {
|
||||
.boxBg {
|
||||
box-shadow: none;
|
||||
margin-top: 36rpx;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
.btnBox{
|
||||
.btn-default{
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
::v-deep .result{
|
||||
padding: 36rpx 26rpx 16rpx;
|
||||
line-height: 42rpx;
|
||||
margin-top: 0;
|
||||
position: relative;
|
||||
view{
|
||||
padding-bottom: 14rpx;
|
||||
&:nth-child(3){
|
||||
color: var(--neutral-color-font);
|
||||
font-weight: normal;
|
||||
font-size: var(--font-size-12);
|
||||
}
|
||||
}
|
||||
.price{
|
||||
position: absolute;
|
||||
right: 40rpx;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
font-size: 40rpx;
|
||||
color: var(--essential-color-red) !important;
|
||||
line-height: 42rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text{
|
||||
font-size: var(--font-size-12);
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .addressCon {
|
||||
.item {
|
||||
height: 138rpx;
|
||||
line-height: 138rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:first-child {
|
||||
.address {
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
}
|
||||
}
|
||||
.address {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&>view {
|
||||
flex: 1;
|
||||
color: var(--neutral-color-font);
|
||||
&.active {
|
||||
color: var(--neutral-color-main);
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-16);
|
||||
text{
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .goodsCon {
|
||||
padding: 8rpx 0 32rpx;
|
||||
font-size: var(--font-size-13);
|
||||
font-weight: 600;
|
||||
.item{
|
||||
& > text {
|
||||
width: 104rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
114
project-wl-kuaidiyuan-uniapp-vue3/pages/freight/index.vue
Normal file
114
project-wl-kuaidiyuan-uniapp-vue3/pages/freight/index.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<!-- 运费查询页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<view class="navHead"><UniNav :title="title" @goBack="goBack"></UniNav></view>
|
||||
<!-- end -->
|
||||
<!-- 列表 -->
|
||||
<view class="pageBox freightBox">
|
||||
<!-- 地址 -->
|
||||
<UniAddress ref="address" @handleCity="handleCity"></UniAddress>
|
||||
<!-- end -->
|
||||
<!-- 重量、体积计算 -->
|
||||
<view class="boxBg">
|
||||
<GoodsInfo ref="goods"></GoodsInfo>
|
||||
</view>
|
||||
|
||||
<!-- end -->
|
||||
<!-- 查询按钮 -->
|
||||
<view class="btnBox"
|
||||
><button
|
||||
class="btn-default"
|
||||
:class="isCityId ? '' : 'btn-forbid'"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
立即查询
|
||||
</button></view
|
||||
>
|
||||
<!-- end -->
|
||||
<!-- 查询结果 -->
|
||||
<Result :baseData="baseData.value" v-if="isShow"></Result>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
// 接口 api
|
||||
import { calculateFreight } from "@/pages/api/freight.js";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 地址选择组件
|
||||
import UniAddress from "./components/address.vue";
|
||||
// 物品信息组件
|
||||
import GoodsInfo from "@/components/uni-goods/index.vue";
|
||||
// 查询结果
|
||||
import Result from "./components/result.vue";
|
||||
// ------定义变量------
|
||||
const title = ref("运费查询");
|
||||
const isShow = ref(false);//是否显示查询结果
|
||||
let baseData = reactive({});//储存数据
|
||||
const goods = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
const address = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
const isCityId = ref(false);
|
||||
// ------定义方法------
|
||||
// 立即查询
|
||||
const handleSubmit = async () => {
|
||||
// 显示查询结果
|
||||
const senderCountyId = address.value.mailCity.areaId; // 寄件id
|
||||
const receiverCountyId = address.value.consigneeCity.areaId; // 收件id
|
||||
const goodData = goods.value;
|
||||
|
||||
if (!senderCountyId) {
|
||||
return uni.showToast({
|
||||
title: "请选择寄件城市",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
if (!receiverCountyId) {
|
||||
return uni.showToast({
|
||||
title: "请选择收件城市",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
isShow.value = true;
|
||||
let data = {
|
||||
senderCountyId: senderCountyId,
|
||||
receiverCountyId: receiverCountyId,
|
||||
volume: goodData.volume === 0 ? 1 : goodData.volume * 1000000,
|
||||
weight: goodData.weight,
|
||||
measureLong: goodData.measureLong,
|
||||
measureWidth: goodData.measureWidth,
|
||||
measureHigh: goodData.measureHigh,
|
||||
};
|
||||
const res = await calculateFreight(data);
|
||||
if (res.code === 200) {
|
||||
baseData.value = {
|
||||
volumeValue: goodData.volume,
|
||||
...res.data,
|
||||
};
|
||||
} else {
|
||||
return uni.showToast({
|
||||
title: res.msg,
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 是否选择了寄件地址和收件地址
|
||||
const handleCity = (val) => {
|
||||
isCityId.value = val;
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/index/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<view class="dateBox uniPopup">
|
||||
<view class="item">
|
||||
<!-- 由于需求改动,这块日期展示效果先不用 -->
|
||||
<!-- <view class="date" @change="handleDate">
|
||||
<icon class="dateIcon"></icon>
|
||||
<text>{{ getNow(dates) }}</text>
|
||||
<icon class="next"></icon>
|
||||
</view> -->
|
||||
<uni-datetime-picker type="date" :clear-icon="false" @change="handleDate">
|
||||
<view class="date">
|
||||
<icon class="dateIcon"></icon>
|
||||
<text>{{ dates }}</text>
|
||||
<icon class="next"></icon>
|
||||
</view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
<view class="item" :class="isTmClick ? 'red' : ''" @click="hanleDay(0)">
|
||||
<text :class="!isToday ? 'gray' : ''">明天</text>
|
||||
</view>
|
||||
<view class="item" :class="isAtClick ? 'red' : ''" @click="hanleDay(1)">
|
||||
<text :class="!isToday ? 'gray' : ''">后天</text>
|
||||
</view>
|
||||
<!-- 由于需求改动,这块日期展示效果先不用 -->
|
||||
<!-- <view class="datePopupBox">
|
||||
<uni-popup ref="popup" type="bottom" background-color="#fff">
|
||||
<view class="popup-content">
|
||||
<view class="tit">
|
||||
<view @click="handleCancel('bottom')">取消</view>
|
||||
<view>选择开始日期</view>
|
||||
<view @click="handleComplete">完成</view>
|
||||
</view>
|
||||
<view class="date-select">
|
||||
<picker-view class="picker-view" :value="defaultValue" :indicator-style="indicatorStyle" @change="bindChange">
|
||||
<picker-view-column>
|
||||
<view class="item" v-for="(item, index) in monthData.value" :key="index">
|
||||
<text @click="handleGetNow(index)">{{ getNow(item) }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, watch } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
// 获取封装好的方法
|
||||
import { getTate, getNow, getDay, afterTomorrowDay, tomorrowDay, getMonthDay } from '@/utils/index.js';
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits();
|
||||
const popup = ref(); //定义弹层ref
|
||||
let dates = ref(); //当前日期
|
||||
let isPreExceed = ref(false); //触发前一天是否超过30天
|
||||
let isNextExceed = ref(false); //触发后一天是否超过30天
|
||||
const monthData = reactive([]); //时间数组
|
||||
const indicatorStyle = ref(`height: 100rpx;`);
|
||||
let defaultValue = ref([0]); //时间默认选择为数组第一个值
|
||||
let times = ref(null); //触发的事件选择
|
||||
let dateTime = ref(null); //时间选择筛选
|
||||
// let isTomorrow = ref(false); //是否触发了明天、后台按钮,用来判断日期弹层是否要显示当前日期,如果触发了今天、后天,那么弹层显示的时候应该显示当前的日期
|
||||
// 监听触发前一天、后一天按钮,向前后者向后超过当前日期30天的日期,按钮置灰
|
||||
let isToday = ref(true); //如果是当天,明天后天可以触发
|
||||
// let dayArr = reactive(['明天', '后天']);
|
||||
let isActive = ref(null); //定义明后天的当前样式
|
||||
const isTmClick = ref(false); //触发明天
|
||||
const isAtClick = ref(false);//触发后天
|
||||
watch(dates, (newValue, oldValue) => {
|
||||
isToday.value = getNow(newValue) === getNow(new Date());
|
||||
const obj = getMonthDay(newValue);
|
||||
// 前一天按钮置灰
|
||||
if (obj.timeNow === obj.timeStar) {
|
||||
isPreExceed.value = true;
|
||||
}
|
||||
// 后一天按钮置灰
|
||||
if (obj.timeNow === obj.timeEnd) {
|
||||
isNextExceed.value = true;
|
||||
}
|
||||
// 弹层选择的时间和当前时间显示一致
|
||||
monthData.value.map((val, index) => {
|
||||
if (getTate(obj.timeNow) === val) {
|
||||
defaultValue.value = [index];
|
||||
}
|
||||
});
|
||||
// 传递当前筛选的时间
|
||||
if (users.timeData) {
|
||||
emit('getDateTime', getTate(users.timeData));
|
||||
dates.value = users.timeData;
|
||||
} else {
|
||||
emit('getDateTime', getTate(obj.timeNow));
|
||||
}
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
dates.value = getTate(new Date()); //获取当前日期
|
||||
monthData.value = getDay(); //获取当月的所有日期
|
||||
});
|
||||
// ------定义方法------
|
||||
|
||||
// 触发今天、明天
|
||||
const hanleDay = index => {
|
||||
if (isToday.value) {
|
||||
if (index === 0) {
|
||||
isAtClick.value = false
|
||||
isTmClick.value =!isTmClick.value
|
||||
store.commit('user/setTimeData', tomorrowDay());
|
||||
emit('getDateTime', getTate(tomorrowDay()));
|
||||
if (!isTmClick.value) {
|
||||
store.commit('user/setTimeData', getTate(new Date()));
|
||||
emit('getDateTime', getTate(getTate(new Date())));
|
||||
}
|
||||
// isTomorrow.value = true;
|
||||
} else {
|
||||
isTmClick.value = false
|
||||
isAtClick.value =!isAtClick.value
|
||||
store.commit('user/setTimeData', afterTomorrowDay());
|
||||
emit('getDateTime', getTate(afterTomorrowDay()));
|
||||
if (!isAtClick.value) {
|
||||
store.commit('user/setTimeData', getTate(new Date()));
|
||||
emit('getDateTime', getTate(getTate(new Date())));
|
||||
}
|
||||
// isTomorrow.value = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
// 时间弹层
|
||||
const handleDate = type => {
|
||||
times.value = type;
|
||||
handleComplete();
|
||||
// // 由于需求改动,以日历形式展现,以下先不用
|
||||
// if (isTomorrow.value) {
|
||||
// monthData.value.map((val, index) => {
|
||||
// if (getTate(new Date()) === val) {
|
||||
// defaultValue.value = [index];
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// isTomorrow.value = false;
|
||||
// popup.value.open(type);
|
||||
};
|
||||
// // 由于需求改动,以日历形式展现,以下先不用
|
||||
// // 选择时间
|
||||
// const bindChange = e => {
|
||||
// // 时间筛选
|
||||
// times.value = monthData.value[e.detail.value[0]];
|
||||
// };
|
||||
// 完成
|
||||
const handleComplete = () => {
|
||||
// 清除明后天当前样式
|
||||
isActive.value = null;
|
||||
if (times.value === dates.value) {
|
||||
isToday.value = true;
|
||||
} else {
|
||||
isToday.value = false;
|
||||
}
|
||||
if (times.value !== null) {
|
||||
dates.value = times.value;
|
||||
store.commit('user/setTimeData', times.value);
|
||||
|
||||
handleCancel();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '请选择日期',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
// // 由于需求改动,以日历形式展现,以下先不用
|
||||
// const handleGetNow = num => {
|
||||
// times.value = monthData.value[num];
|
||||
// };
|
||||
// 关闭弹层
|
||||
const handleCancel = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<!-- 列表内容 -->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<view class="boxBg">
|
||||
<view class="tabList">
|
||||
<view class="item" @click.stop="handleDetails($event, item)">
|
||||
<view v-if="item.status !== 1" class="history">
|
||||
<view class="titInfo" v-if="item.transportOrderId !== null"
|
||||
>运单号:{{ item.transportOrderId }}</view
|
||||
>
|
||||
<view class="address">收件人:{{ item.name }}</view>
|
||||
<view class="address">派件地址:{{ item.address }}</view>
|
||||
<view class="address">签收时间:{{ item.actualEndTime }}</view>
|
||||
<view class="time" v-if="item.status === 2"
|
||||
>运费:{{ item.amount }}元</view
|
||||
>
|
||||
</view>
|
||||
<view v-else class="history">
|
||||
<view class="titInfo">
|
||||
<view>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
{{ item.phone }}
|
||||
<!-- TODO拨打电话和发信息小图标,暂时保留 -->
|
||||
<!-- <icon class="phone" @click.stop="handlePhone($event, item.phone)"></icon>
|
||||
<icon class="note" @click.stop="handleNote"></icon> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="address">{{ item.distance }}公里</view>
|
||||
<view class="time" v-if="item.transportOrderId !== null"
|
||||
>运单号:{{ item.transportOrderId }}</view
|
||||
>
|
||||
</view>
|
||||
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="item.status === 1"
|
||||
><button class="uni-btn btn-default">去派件</button></text
|
||||
>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-else-if="
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 2 &&
|
||||
item.signStatus !== 2
|
||||
"
|
||||
><button class="uni-btn btn-default">去收款</button></text
|
||||
>
|
||||
<text @click.stop="handleOpen($event, item.id)" class="delete" v-else
|
||||
><button class="uni-btn concelBtn">删除</button></text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 数据
|
||||
itemData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 当前触发的tab值
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
// ------定义方法------
|
||||
|
||||
// 删除弹层
|
||||
const handleOpen = (e, id) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
emit("handleOpen", id);
|
||||
};
|
||||
// 去派件详情
|
||||
const handleDetails = (e, item) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit("user/setTaskId", item.id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit("user/setTaskType", 2);
|
||||
|
||||
store.commit("user/setDetailType", 2); //从历史订单他跳入订单详情
|
||||
|
||||
// 进入详情页
|
||||
if (item.status === 1) {
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit("user/setTaskStatus", 6);
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
} else if (
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 2 &&
|
||||
item.signStatus !== 2
|
||||
) {
|
||||
store.commit("user/setIsDelivery", true);
|
||||
store.commit("user/setTaskStatus", 6);
|
||||
// 未付款进入付款二维码页面
|
||||
store.commit("user/setPayData", {});
|
||||
uni.redirectTo({
|
||||
url: "/pages/pay/scanPay",
|
||||
});
|
||||
} else {
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit("user/setTaskStatus", 6);
|
||||
// 已经完成的进入订单详情页
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<view class="pageBox">
|
||||
<!-- tab切换 -->
|
||||
<UniTab
|
||||
:tabBars="tabBars"
|
||||
ref="tab"
|
||||
@getTabIndex="getTabIndex"
|
||||
class="historyTab"
|
||||
></UniTab>
|
||||
<!-- end -->
|
||||
<view class="homeSwiper historyboxTop">
|
||||
<view v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<!-- 取件 -->
|
||||
<view v-if="tabIndex === 0"
|
||||
><Pickup :itemData="itemData" @handleOpen="handleOpen"></Pickup
|
||||
></view>
|
||||
<!-- end -->
|
||||
<!-- 派件 -->
|
||||
<view v-else
|
||||
><Delivery :itemData="itemData" @handleOpen="handleOpen"></Delivery
|
||||
></view>
|
||||
<!-- end -->
|
||||
<!-- 上拉 -->
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
<!-- 空页面 -->
|
||||
</view>
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- 提示窗 -->
|
||||
<UniPopup
|
||||
ref="popup"
|
||||
:tipInfo="tipInfo"
|
||||
@handleClick="handleClick"
|
||||
></UniPopup>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, watch } from "vue";
|
||||
import { onReachBottom } from "@dcloudio/uni-app";
|
||||
import { useStore } from "vuex";
|
||||
import { getTimeDate} from '@/utils/index.js';
|
||||
// 基本数据
|
||||
import { HistoryTabData } from "@/utils/commonData.js";
|
||||
//接口
|
||||
import { getDeliveryList, taskDelete } from "@/pages/api/index.js";
|
||||
// tab切换
|
||||
import UniTab from "@/components/uni-tab/index.vue";
|
||||
// 弹层
|
||||
import UniPopup from "@/components/uni-popup/index.vue";
|
||||
// 下拉提示
|
||||
import ReachBottom from "@/components/reach-bottom/index.vue";
|
||||
//空页面
|
||||
import EmptyPage from "@/components/uni-empty-page/index.vue";
|
||||
// 取件
|
||||
import Pickup from "./pickup.vue";
|
||||
// 派件
|
||||
import Delivery from "./delivery.vue";
|
||||
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 筛选时间
|
||||
dateTime: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
let popup = ref();
|
||||
const tipInfo = ref("确认删除该订单吗?");
|
||||
const tabBars = HistoryTabData;//tab标签数据
|
||||
let taskId = ref(""); //任务id
|
||||
let tabIndex = ref(0); //当前tab
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
let itemData = ref([]);//列表数据
|
||||
let reload = ref(false); //是否加载
|
||||
let pages = ref(0); //总页数
|
||||
let pageNum = users.isFiltrate ? 1 : ref(1); //存放当前页
|
||||
const emptyData = ref("暂无数据");
|
||||
let isPullDown = ref(false); //是否下拉了
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
taskType: 1,
|
||||
});
|
||||
watch(props, (newValue, oldValue) => {
|
||||
// 存储清空列表数据
|
||||
store.commit("user/setDeliveryData", []);
|
||||
getList(newValue.dateTime);
|
||||
});
|
||||
// 监听tab切换
|
||||
watch(tabIndex, (newValue, oldValue) => {
|
||||
if (newValue === 0) {
|
||||
page.taskType = 1;
|
||||
} else {
|
||||
page.taskType = 2;
|
||||
}
|
||||
// 存储清空列表数据
|
||||
store.commit("user/setDeliveryData", []);
|
||||
// 根据不同的tab值切更新 取件数据
|
||||
getList(page.dateTime);
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
if (users.tabIndex) {
|
||||
tabIndex.value = users.tabIndex;
|
||||
}
|
||||
});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
if (pageNum.value >= Number(pages.value)) {
|
||||
loadMore.value.status = "noMore";
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = "loading";
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
getList(page.dateTime);
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async (time) => {
|
||||
reload.value = true;
|
||||
//判断是否进行了距离、时间、超时任务筛选,如果是,当前页设为第一页,上拉的数值设为1,便于第二次上拉
|
||||
page = {
|
||||
...page,
|
||||
dateTime: (getTimeDate(time)).veryDayDate,
|
||||
page: pageNum.value,
|
||||
};
|
||||
await getDeliveryList(page).then((res) => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
if (users.istabChange) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit("user/setIstabChange", false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit("user/setDeliveryData", itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = "noMore";
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取tab切换当前的index
|
||||
const getTabIndex = (index) => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("user/setIstabChange", true);
|
||||
pageNum.value = 1;
|
||||
pages.value = 1;
|
||||
tabIndex.value = index;
|
||||
itemData.value = [];
|
||||
store.commit("user/setDeliveryData", []);
|
||||
};
|
||||
// 确认删除
|
||||
const handleClick = async () => {
|
||||
await taskDelete(taskId.value).then((res) => {
|
||||
if (res.code === 200) {
|
||||
store.commit("user/setDeliveryData", []);
|
||||
getList(page.dateTime);
|
||||
isPullDown.value = true;
|
||||
return uni.showToast({
|
||||
title: "删除成功!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 删除弹层
|
||||
const handleOpen = (id) => {
|
||||
popup.value.dialogOpen();
|
||||
taskId.value = id;
|
||||
};
|
||||
// 触发选项卡事件
|
||||
const onChangeSwiperTab = (e) => {
|
||||
changeTab(e.detail.current);
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
getList,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<!-- 列表内容 -->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<view class="boxBg">
|
||||
<view class="tabList">
|
||||
<view class="item" @click.stop="handleDetails($event, item)">
|
||||
<view v-if="item.status !== 1" class="history">
|
||||
<view class="titInfo">订单号:SD{{ item.orderId }}</view>
|
||||
<view class="address">寄件人:{{ item.name }}</view>
|
||||
<view class="address">取件地址:{{ item.address }}</view>
|
||||
<view class="address">取件时间:{{ item.actualEndTime }}</view>
|
||||
<view class="time" v-if="item.status === 2"
|
||||
>运费:{{ item.amount }}元</view
|
||||
>
|
||||
</view>
|
||||
<view v-else class="history">
|
||||
<view class="titInfo">
|
||||
<view>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
{{ item.phone }}
|
||||
<!-- TODO拨打电话和发信息小图标,暂时保留 -->
|
||||
<!-- <icon class="phone" @click.stop="handlePhone($event, item.phone)"></icon>
|
||||
<icon class="note" @click.stop="handleNote"></icon> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="address">{{ item.distance }}公里</view>
|
||||
<view class="time"
|
||||
>预约取件时间:{{ taskTimeFormat(item.estimatedStartTime) }} 至
|
||||
{{ overTimeFormat(item.estimatedEndTime) }}</view
|
||||
>
|
||||
</view>
|
||||
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="item.status === 1"
|
||||
><button class="uni-btn btn-default">去取件</button></text
|
||||
>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-else-if="
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 1
|
||||
"
|
||||
><button class="uni-btn btn-default">去收款</button></text
|
||||
>
|
||||
<text @click.stop="handleOpen($event, item.id)" class="delete" v-else
|
||||
><button class="uni-btn concelBtn">删除</button></text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from "vue";
|
||||
import { taskTimeFormat, overTimeFormat } from "@/utils/index.js";
|
||||
import { useStore } from "vuex";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 数据
|
||||
itemData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 当前触发的tab值
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
// ------生命周期------
|
||||
onMounted(() => {});
|
||||
// ------定义方法------
|
||||
// 删除弹层
|
||||
const handleOpen = (e, id) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
emit("handleOpen", id);
|
||||
};
|
||||
// 去取件详情
|
||||
const handleDetails = (e, item) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit("user/setTaskId", item.id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit("user/setTaskType", 1);
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit("user/setTaskStatus", 6);
|
||||
store.commit("user/setDetailType", 1); //从历史订单他跳入订单详情
|
||||
// 如果时带取件进入到去取件页面
|
||||
// 进入详情页
|
||||
if (item.status === 1) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/index",
|
||||
});
|
||||
} else if (
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 1
|
||||
) {
|
||||
// 未付款进入付款二维码页面
|
||||
store.commit("user/setPayData", {});
|
||||
uni.redirectTo({
|
||||
url: "/pages/pay/scanPay",
|
||||
});
|
||||
} else {
|
||||
// 已经完成的进入订单详情页
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
101
project-wl-kuaidiyuan-uniapp-vue3/pages/history/index.scss
Normal file
101
project-wl-kuaidiyuan-uniapp-vue3/pages/history/index.scss
Normal file
@@ -0,0 +1,101 @@
|
||||
body,
|
||||
uni-page-body {
|
||||
background: var(--neutral-color-background) !important;
|
||||
}
|
||||
.dateBox {
|
||||
padding: 14rpx 60rpx 24rpx 40rpx;
|
||||
line-height: 40rpx;
|
||||
background: var(--neutral-color-white);
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
top: 264rpx;
|
||||
::v-deep & > view {
|
||||
&:nth-child(2) {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
&:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
.date {
|
||||
width: 300rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
margin: 0 auto;
|
||||
background: var(--neutral-color-background);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16rpx;
|
||||
.dateIcon {
|
||||
width: 34rpx;
|
||||
height: 36rpx;
|
||||
background: url(@/static/date.png) no-repeat;
|
||||
background-size: contain;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
text {
|
||||
flex: 1;
|
||||
}
|
||||
.next {
|
||||
width: 30rpx;
|
||||
height: 23rpx;
|
||||
background: url(@/static/icon15.png) no-repeat 50% 50%;
|
||||
background-size: contain;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
.noDate {
|
||||
.dateIcon {
|
||||
background: url(@/static/dateno.png) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
text {
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.next {
|
||||
background: url(@/static/icon16.png) no-repeat 50% 50%;
|
||||
background-size: contain;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.red){
|
||||
color: var(--essential-color-red);
|
||||
}
|
||||
:deep(.gray){
|
||||
color: var(--neutral-color-placeholder);
|
||||
}
|
||||
}
|
||||
.history{
|
||||
background: var(--neutral-color-white);
|
||||
padding: 30rpx;
|
||||
::v-deep .navBox {
|
||||
top: 148rpx !important;
|
||||
.uni-navbar {
|
||||
padding: 40rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .historyTab{
|
||||
width: 100% !important;
|
||||
border-top: 1px solid var(--neutral-color-background);
|
||||
position: fixed;
|
||||
top: 361rpx;
|
||||
z-index: 1;
|
||||
.scroll-row-item{
|
||||
margin-right: 128rpx;
|
||||
}
|
||||
}
|
||||
::v-deep .uni-datetime-picker--btn,::v-deep .uni-calendar-item__weeks-box .uni-calendar-item--checked{
|
||||
background-color: var(--essential-color-red);
|
||||
}
|
||||
::v-deep .uni-calendar-item__weeks-box-text{
|
||||
color: var(--neutral-color-main);
|
||||
}
|
||||
|
||||
94
project-wl-kuaidiyuan-uniapp-vue3/pages/history/index.vue
Normal file
94
project-wl-kuaidiyuan-uniapp-vue3/pages/history/index.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<!-- 历史取派页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<!-- 搜索nav -->
|
||||
<view class="history">
|
||||
<view class="navBox">
|
||||
<view class="search">
|
||||
<view class="uni-navbar">
|
||||
<view class="input-view">
|
||||
<view class="input-view">
|
||||
<uni-icons
|
||||
class="input-uni-icon"
|
||||
type="search"
|
||||
size="18"
|
||||
color="#999"
|
||||
/>
|
||||
<input
|
||||
confirm-type="search"
|
||||
class="nav-bar-input"
|
||||
type="text"
|
||||
v-model="searchVal"
|
||||
placeholder="输入四位或完整运单号/手机号、姓名"
|
||||
@confirm="handleSearch"
|
||||
@tap="handleSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<view>
|
||||
<!-- 日期选择 -->
|
||||
<TateSelete @getDateTime="getDateTime"></TateSelete>
|
||||
<!-- end -->
|
||||
<!-- 取件派件列表 -->
|
||||
<TabList :dateTime="dateTime" ref="list"></TabList>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 日期选择
|
||||
import TateSelete from "./commponents/date.vue";
|
||||
// 列表
|
||||
import TabList from "./commponents/index.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
let list = ref();
|
||||
let itemData = reactive([]); //列表数据
|
||||
const title = ref("全部取派"); //nav标题
|
||||
let dateTime = ref(""); //存放日期
|
||||
const searchVal = ref(""); //搜索内容
|
||||
// ------生命周期------
|
||||
// ------定义方法------
|
||||
// 获取筛选的时间
|
||||
const getDateTime = (val) => {
|
||||
dateTime.value = val;
|
||||
};
|
||||
// 跳转到搜索页面
|
||||
const handleSearch = (e) => {
|
||||
// 跳转到搜索页面
|
||||
uni.redirectTo({
|
||||
url: "/pages/search/index",
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
if (users.taskStatus === -1) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/my/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/index/index",
|
||||
});
|
||||
}
|
||||
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("user/setTaskStatus", 0);
|
||||
store.commit("user/setTimeData", null);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<view class="commonUse">
|
||||
<view class="hometit">常用功能</view>
|
||||
<view class="commonList">
|
||||
<view @click="handleChild">
|
||||
<icon class="icon delivery"></icon>
|
||||
<text>派件扫描</text>
|
||||
</view>
|
||||
<view @click="handleChild">
|
||||
<icon class="icon sign"></icon>
|
||||
<text>签收扫描</text>
|
||||
</view>
|
||||
<view>
|
||||
<view @click="handleHistory">
|
||||
<icon class="icon history"></icon>
|
||||
<text>全部取派</text>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view @click="handleNew">
|
||||
<icon class="icon new"></icon>
|
||||
<text>消息通知</text>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<navigator url="/pages/freight/index" open-type="redirect">
|
||||
<icon class="icon freight"></icon>
|
||||
<text>运费查询</text>
|
||||
</navigator>
|
||||
</view>
|
||||
<view>
|
||||
<view @click="handleTip">
|
||||
<icon class="icon tip"></icon>
|
||||
<text>签收提醒</text>
|
||||
</view>
|
||||
</view>
|
||||
<view @click="handleChild">
|
||||
<icon class="icon exclusive"></icon>
|
||||
<text>专属取寄</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
// 获取父组件值、方法
|
||||
const props = defineProps({});
|
||||
const store = useStore(); //vuex获取储存数据
|
||||
// 定义方法
|
||||
const handleChild = () => {
|
||||
uni.showToast({
|
||||
title: "程序员哥哥正在实现中",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
};
|
||||
// 历史派件
|
||||
const handleHistory = () => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("user/setNewType", null);
|
||||
|
||||
uni.navigateTo({
|
||||
url: "/pages/history/index",
|
||||
});
|
||||
};
|
||||
// 签收提醒
|
||||
const handleTip = () => {
|
||||
store.commit("user/setTaskStatus", -1);
|
||||
uni.navigateTo({
|
||||
url: "/pages/news/system?title=签收提醒&type=302",
|
||||
});
|
||||
};
|
||||
// 消息通知
|
||||
const handleNew = () => {
|
||||
store.commit("user/setTabIndex", 1);
|
||||
uni.navigateTo({
|
||||
url: "/pages/news/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../index.scss" lang="scss"></style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<view class="commonData">
|
||||
<view class="hometit">数据展示</view>
|
||||
<view class="dataList">
|
||||
<view class="todayGet" @click="handlTodayAcquired">
|
||||
<view>今日已取</view>
|
||||
<view class="num">{{ baseData.completePickUpNum }}</view>
|
||||
<view class="rightIcon"></view>
|
||||
</view>
|
||||
<view class="todaySign" @click="handlTodaySign">
|
||||
<view>今日已签</view>
|
||||
<view class="num">{{ baseData.signedNum }}</view>
|
||||
<view class="rightIcon"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore(); //设置、获取数据
|
||||
// 获取父组件值、方法
|
||||
const props = defineProps({
|
||||
baseData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
// ------定义方法------
|
||||
// 进入 已取件列表页
|
||||
const handlTodayAcquired = () => {
|
||||
store.commit("user/setTabIndex", 1);
|
||||
store.commit("setFootStatus", 1);
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
};
|
||||
// 进入 已签收列表页
|
||||
const handlTodaySign = () => {
|
||||
store.commit("user/setTabIndex", 1);
|
||||
store.commit("setFootStatus", 3);
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../index.scss" lang="scss"></style>
|
||||
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<view>
|
||||
<scroll-view
|
||||
scroll-x="true"
|
||||
class="tabScroll"
|
||||
:scroll-into-view="scrollinto"
|
||||
:scroll-with-animation="true"
|
||||
>
|
||||
<view
|
||||
v-for="(item, index) in tabBars"
|
||||
:key="index"
|
||||
:id="'tab' + index"
|
||||
class="scroll-row-item"
|
||||
@click="changeTab(index)"
|
||||
>
|
||||
<view :class="tabIndex == index ? 'scroll-row-item-act' : ''">
|
||||
<text class="line"></text>
|
||||
{{ item.name }}
|
||||
<text class="num">{{ item.num }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="homeSwiper">
|
||||
<view v-if="tabIndex === 0 || tabIndex === 1">
|
||||
<view v-if="itemData.length > 0">
|
||||
<view
|
||||
class="boxBg"
|
||||
v-for="(item, index) in itemData.slice(0, 3)"
|
||||
:key="index"
|
||||
v-if="tabIndex === 0"
|
||||
>
|
||||
<view class="tabList">
|
||||
<view class="item" @click.stop="handleDetail(item.id)">
|
||||
<view class="titInfo">
|
||||
{{ item.name }}
|
||||
<text>{{ item.phone }}</text>
|
||||
<icon
|
||||
class="phone"
|
||||
@click.stop="handlePhone($event, item.phone)"
|
||||
></icon>
|
||||
<icon class="note" @click.stop="handleNote"></icon>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="distance">{{ item.distance }}公里</view>
|
||||
<view class="time"
|
||||
>预约取件时间:{{
|
||||
taskTimeFormat(item.estimatedStartTime)
|
||||
}}
|
||||
至 {{ overTimeFormat(item.estimatedEndTime) }}</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 待派件 -->
|
||||
<view
|
||||
class="boxBg"
|
||||
v-for="(item, index) in itemData.slice(0, 3)"
|
||||
:key="index"
|
||||
v-if="tabIndex === 1"
|
||||
>
|
||||
<view class="tabList">
|
||||
<view class="item" @click.stop="handleDetail(item.id)">
|
||||
<view class="titInfo">
|
||||
{{ item.name }}
|
||||
<text>{{ item.phone }}</text>
|
||||
<icon
|
||||
class="phone"
|
||||
@click.stop="handlePhone($event, item.phone)"
|
||||
></icon>
|
||||
<icon class="note" @click.stop="handleNote"></icon>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="address">{{ item.distance }}公里</view>
|
||||
<view class="time">运单号:{{ item.transportOrderId }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="moreInfo" v-if="itemData.length > 3" @click="handleMore">
|
||||
查看更多
|
||||
<icon></icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 无数据显示 -->
|
||||
<view v-if="itemData.length === 0"
|
||||
><EmptyPage :emptyInfo="emptyInfo"></EmptyPage
|
||||
></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- 拨打手机弹层 -->
|
||||
<Phone ref="phone" :phoneData="phoneData"></Phone>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 处理事件封装的方法
|
||||
import { taskTimeFormat, overTimeFormat } from "@/utils/index.js";
|
||||
//组件
|
||||
// 无数据
|
||||
import EmptyPage from "@/components/uni-empty-page/index.vue";
|
||||
import Phone from "@/components/uni-phone/index.vue";
|
||||
// 获取父组件值、方法
|
||||
const props = defineProps({
|
||||
itemData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tabBars: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //设置、获取数据
|
||||
let scrollinto = ref("tab0"); //tab切换
|
||||
let tabIndex = ref(0); //当前tab
|
||||
const phone = ref();
|
||||
const emptyInfo = ref("- 空空如也,无运单记录 -");
|
||||
|
||||
const emit = defineEmits("getTabIndex");
|
||||
const phoneData = ref("");
|
||||
|
||||
// ------定义方法------
|
||||
// tab选项卡切换轮播
|
||||
const changeTab = (index) => {
|
||||
// 点击的还是当前数据的时候直接return
|
||||
if (tabIndex.value == index) {
|
||||
return;
|
||||
}
|
||||
tabIndex.value = index;
|
||||
emit("getTabIndex", index);
|
||||
// 滑动
|
||||
scrollinto.value = "tab" + index;
|
||||
};
|
||||
|
||||
// 触发选项卡事件
|
||||
const onChangeSwiperTab = (e) => {
|
||||
changeTab(e.detail.current);
|
||||
};
|
||||
// 进入详情
|
||||
const handleDetail = (id) => {
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit("user/setTaskId", id);
|
||||
store.commit("user/setNewType", null);
|
||||
// 进入取件详情页
|
||||
if (tabIndex.value === 0) {
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit("user/setTaskType", 1);
|
||||
store.commit("user/setDetailType", 0);
|
||||
store.commit("setFootStatus", 1); //修改底部tab当前标签
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/index",
|
||||
});
|
||||
} else {
|
||||
// 进入派件详情页
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit("user/setTaskType", 2);
|
||||
store.commit("user/setDetailType", 0);
|
||||
store.commit("setFootStatus", 3); //修改底部tab当前标签
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 进入待取件待派件页面
|
||||
const handleMore = () => {
|
||||
if (tabIndex.value === 0) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 拨打电话弹层
|
||||
const handlePhone = (e, val) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
phoneData.value = val;
|
||||
phone.value.dialogOpen();
|
||||
};
|
||||
// 发短信
|
||||
const handleNote = () => {
|
||||
uni.showToast({
|
||||
title: "程序员哥哥正在实现中",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../index.scss" lang="scss"></style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<view class="infoBox">
|
||||
<view class="boxBg">
|
||||
<view @click="handlePicup">
|
||||
<view class="num">{{ baseData.newPickUpNum }}</view>
|
||||
<view>取件任务</view>
|
||||
</view>
|
||||
<view @click="handleDelivery">
|
||||
<view class="num">{{ baseData.newDispatchNum }}</view>
|
||||
<view>派件任务</view>
|
||||
</view>
|
||||
<view @click="handleOvertime">
|
||||
<view class="num">{{ baseData.overTimeNum }}</view>
|
||||
<view>超时任务</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore(); //设置、获取数据
|
||||
// 获取父组件值、方法
|
||||
const props = defineProps({
|
||||
baseData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
// ------定义方法------
|
||||
// 进入 待取件列表页
|
||||
const handlePicup = () => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("setFootStatus", 1);
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
};
|
||||
// 进入 待派件列表页
|
||||
const handleDelivery = () => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("setFootStatus", 3);
|
||||
store.commit("user/setDetailType", 0);
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
};
|
||||
// 进入 选中超时任务
|
||||
const handleOvertime = () => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("setFootStatus", 1);
|
||||
store.commit("user/setFilterOverTime", true);
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../index.scss" lang="scss"></style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<view class="orderTip" v-if="orderData" @click="handleLink">
|
||||
<view class="btn">消息通知</view>
|
||||
<view>{{ orderData.recentMsg }}</view>
|
||||
<view>
|
||||
{{ orderData.minutes === 0 ? 1 : orderData.minutes }}分钟前
|
||||
<icon class="iconNext"></icon>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
// 获取父组件值、方法
|
||||
const props = defineProps({
|
||||
orderData: Object,
|
||||
default: () => ({}),
|
||||
});
|
||||
// ------定义方法------
|
||||
const handleLink = () => {
|
||||
const type = props.orderData.contentType;
|
||||
store.commit("user/setTaskStatus", -1);
|
||||
if (type === 300) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/index",
|
||||
});
|
||||
} else if (type === 301) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/system?title=取件相关&type=301",
|
||||
});
|
||||
} else if (type === 302) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/system?title=签收提醒&type=302",
|
||||
});
|
||||
} else if (type === 303) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/system?title=快件取消&type=303",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/system?title=派件相关&type=304",
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../index.scss" lang="scss"></style>
|
||||
237
project-wl-kuaidiyuan-uniapp-vue3/pages/index/index.scss
Normal file
237
project-wl-kuaidiyuan-uniapp-vue3/pages/index/index.scss
Normal file
@@ -0,0 +1,237 @@
|
||||
body,
|
||||
uni-page-body,
|
||||
uni-page-head,
|
||||
.uni-page-head {
|
||||
background-color: var(--neutral-color-white) !important;
|
||||
}
|
||||
.homePageBox{
|
||||
// height: calc(100vh);
|
||||
position: relative;
|
||||
padding-top: 430rpx;
|
||||
overflow: hidden;
|
||||
.boxBg {
|
||||
box-shadow: 0 0 22rpx 22rpx rgba(162, 162, 162, 0.06);}
|
||||
}
|
||||
.noOrder{
|
||||
padding-top: 460rpx;
|
||||
}
|
||||
|
||||
.infoBox {
|
||||
margin-top: 216rpx;
|
||||
position: relative;
|
||||
z-index: 9;
|
||||
// position: fixed;
|
||||
// z-index: 10;
|
||||
// left: 0;
|
||||
// right: 0;
|
||||
|
||||
.boxBg {
|
||||
padding: 38rpx 0;
|
||||
// height: 200rpx;
|
||||
display: flex;
|
||||
box-shadow: 0 0 22rpx 22rpx rgba(162, 162, 162, 0.06);
|
||||
& > view {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
border-left: 1px solid var(--neutral-color-background);
|
||||
font-size: var(--font-size-14);
|
||||
line-height: 40rpx;
|
||||
color: var(--neutral-color-font);
|
||||
&:first-child {
|
||||
border: 0 none;
|
||||
}
|
||||
.num {
|
||||
font-weight: 600;
|
||||
font-size: 64rpx;
|
||||
line-height: 80rpx;
|
||||
color: var(--neutral-color-main);
|
||||
padding-bottom: 6rpx;
|
||||
}
|
||||
& > view {
|
||||
padding-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.orderTip {
|
||||
height: 68rpx;
|
||||
line-height: 68rpx;
|
||||
background: #fff1f0;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 40rpx;
|
||||
margin-bottom: 30rpx;
|
||||
padding: 0 22rpx 0 14rpx;
|
||||
display: flex;
|
||||
font-size: 20rpx;
|
||||
color: var(--essential-color-red);
|
||||
align-items: center;
|
||||
& > view {
|
||||
&:nth-child(2) {
|
||||
flex: 1;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
width: 106rpx;
|
||||
// height: 36rpx;
|
||||
line-height: 34rpx;
|
||||
// padding: 0 0 0 10rpx;
|
||||
background: url(@/static/new.png) no-repeat;
|
||||
background-size: contain;
|
||||
color: var(--neutral-color-white);
|
||||
font-size: 20rpx;
|
||||
margin-right: 12rpx;
|
||||
text-emphasis: none;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
// 常用功能
|
||||
.hometit {
|
||||
line-height: 46rpx;
|
||||
font-weight: 600;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 32rpx;
|
||||
color: var(--neutral-color-main);
|
||||
letter-spacing: 0.36rpx;
|
||||
}
|
||||
.commonList {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-content: flex-start;
|
||||
& > view {
|
||||
box-sizing: border-box;
|
||||
|
||||
flex: 0 0 25%;
|
||||
font-size: var(--font-size-12);
|
||||
color: var(--neutral-color-font);
|
||||
letter-spacing: 0.28px;
|
||||
line-height: 34rpx;
|
||||
padding: 30rpx 0;
|
||||
text-align: center;
|
||||
text {
|
||||
display: block;
|
||||
}
|
||||
icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-bottom: 16rpx;
|
||||
&.delivery {
|
||||
background: url(@/static/icon03.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.sign {
|
||||
background: url(@/static/icon04.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.history {
|
||||
background: url(@/static/icon05.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.new {
|
||||
background: url(@/static/icon06.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.freight {
|
||||
background: url(@/static/icon07.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.tip {
|
||||
background: url(@/static/icon08.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.exclusive {
|
||||
background: url(@/static/icon09.png);
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.commonData {
|
||||
padding-top: 18rpx;
|
||||
|
||||
.dataList {
|
||||
display: flex;
|
||||
margin-left: -20rpx;
|
||||
padding: 32rpx 0 6rpx;
|
||||
& > view {
|
||||
height: 112rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 34rpx 24rpx;
|
||||
line-height: 34rpx;
|
||||
flex: 1;
|
||||
margin-left: 20rpx;
|
||||
position: relative;
|
||||
font-size: var(--font-size-12);
|
||||
}
|
||||
.rightIcon {
|
||||
position: absolute;
|
||||
right: 18rpx;
|
||||
bottom: 6rpx;
|
||||
}
|
||||
}
|
||||
.todayGet {
|
||||
background-image: linear-gradient(178deg, #ffebeb 4%, #fbf3f3 100%);
|
||||
color: #ce6864;
|
||||
.rightIcon {
|
||||
background: url(@/static/fetch.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 136rpx;
|
||||
height: 146rpx;
|
||||
}
|
||||
}
|
||||
.todaySign {
|
||||
background-image: linear-gradient(178deg, #ffe9dd 5%, #faf3ee 100%);
|
||||
color: #c97f59;
|
||||
.rightIcon {
|
||||
background: url(@/static/sign.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 162rpx;
|
||||
height: 148rpx;
|
||||
}
|
||||
}
|
||||
.rigIcon {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
}
|
||||
.num {
|
||||
line-height: 60rpx;
|
||||
font-size: 44rpx;
|
||||
color: #c24340;
|
||||
letter-spacing: 0.5px;
|
||||
font-weight: 600;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
}
|
||||
// 首页查看更多
|
||||
.moreInfo {
|
||||
font-size: var(--font-size-12);
|
||||
padding: 62rpx 0 80rpx;
|
||||
text-align: center;
|
||||
line-height: 34rpx;
|
||||
icon {
|
||||
background: url(@/static/icon16.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 16rpx;
|
||||
height: 22rpx;
|
||||
margin-left: 6rpx;
|
||||
flex: 1;
|
||||
vertical-align: middle;
|
||||
margin-top: -4rpx;
|
||||
}
|
||||
}
|
||||
.homeSwiper{
|
||||
padding-bottom: 136rpx;
|
||||
::v-deep .uni-swiper-wrapper{
|
||||
overflow: unset !important;
|
||||
position: static !important;
|
||||
// width: auto !important;
|
||||
height:auto !important;
|
||||
uni-swiper-item{
|
||||
overflow: unset !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
147
project-wl-kuaidiyuan-uniapp-vue3/pages/index/index.vue
Normal file
147
project-wl-kuaidiyuan-uniapp-vue3/pages/index/index.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<!-- 首页 -->
|
||||
<template>
|
||||
<view class="navFrame">
|
||||
<!-- nav -->
|
||||
<UniNav :newVal="newVal" @goBack="goBack"></UniNav>
|
||||
<!-- 订单信息 -->
|
||||
<OrderInfo :baseData="baseData"></OrderInfo>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
<view class="homePageBox" :class="!orderData.value ? 'noOrder' : ''">
|
||||
<view class="boxPad">
|
||||
<!-- 订单提示 -->
|
||||
<OrderTip :orderData="orderData.value"></OrderTip>
|
||||
<!-- end -->
|
||||
<!-- 常用功能 -->
|
||||
<CommonUse></CommonUse>
|
||||
<!-- end -->
|
||||
<!-- 数据展示 -->
|
||||
<DataPresentation :baseData="baseData"></DataPresentation>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- 取件状态列表 -->
|
||||
<ExpressageInfo :itemData="itemData.value" :tabBars="tabBars" @getTabIndex="getTabIndex"></ExpressageInfo>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- footer -->
|
||||
<UniFooter :pagePath="'pages/index/index'"></UniFooter>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { getTimeDate, positionsUploadInit } from '@/utils/index.js';
|
||||
// 静态数据
|
||||
import { tabBars } from '@/utils/commonData.js'
|
||||
// 导入接口
|
||||
import { getHomeInfo, getHomeData, getDeliveryList} from '@/pages/api/index.js';
|
||||
// 导入组件
|
||||
// 导航
|
||||
import UniNav from '@/components/uni-home-nav/index.vue';
|
||||
// 底部导航
|
||||
import UniFooter from '@/components/uni-footer/index.vue';
|
||||
// 订单信息
|
||||
import OrderInfo from './components/orderInfo.vue';
|
||||
// 订单消息提示
|
||||
import OrderTip from './components/orderTip.vue';
|
||||
// 常用功能
|
||||
import CommonUse from './components/commonUse.vue';
|
||||
// 数据展示
|
||||
import DataPresentation from './components/dataPresent.vue';
|
||||
// 取件信息
|
||||
import ExpressageInfo from './components/expressageInfo.vue';
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取储存数据
|
||||
const users = store.state.user;
|
||||
const newVal = ref(Number(null)); //消息
|
||||
const orderData = reactive({}); //首页相关默认信息
|
||||
const itemData = reactive([]);
|
||||
const noPickupTaskList = reactive([]); //取件列表数据
|
||||
const noDispatchTaskList = reactive([]); //派件列表数据
|
||||
const locationData = ref({});
|
||||
let baseData = ref({});
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
dateTime: getTimeDate(new Date()).veryDayDate,
|
||||
taskStatus: 1
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
// 上报位置 进入首页立即上报
|
||||
positionsUploadInit()
|
||||
init();
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取初始值
|
||||
const init = () => {
|
||||
getNewData();
|
||||
getHomeBase();
|
||||
getList();
|
||||
};
|
||||
// 获取相关消息
|
||||
const getNewData = async () => {
|
||||
await getHomeInfo().then(res => {
|
||||
if (res.code === 200) {
|
||||
orderData.value = res.data;
|
||||
newVal.value = res.data.newsNum;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取相关任务、取件、派件、今日已取、已签
|
||||
const getList = async () => {
|
||||
await getDeliveryList(page).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
itemData.value = res.data.items;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取相关任务、取件、派件、今日已取、已签
|
||||
const getHomeBase = async () => {
|
||||
const locition = {
|
||||
longitude: 116.344015,
|
||||
latitude: 40.060607
|
||||
};
|
||||
await getHomeData(locition).then(res => {
|
||||
if (res.code === 200) {
|
||||
baseData.value = res.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 列表tab当前切换的index
|
||||
const getTabIndex = val => {
|
||||
itemData.value = [];
|
||||
if (val === 0) {
|
||||
page.taskStatus = 1;
|
||||
} else {
|
||||
page.taskStatus = 4;
|
||||
}
|
||||
getList();
|
||||
};
|
||||
|
||||
// 获取当前位置
|
||||
const getLocation = () => {
|
||||
uni.getLocation({
|
||||
type: 'gcj02',
|
||||
success: res => {}
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
<style lang="scss">
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
165
project-wl-kuaidiyuan-uniapp-vue3/pages/login/index.scss
Normal file
165
project-wl-kuaidiyuan-uniapp-vue3/pages/login/index.scss
Normal file
@@ -0,0 +1,165 @@
|
||||
body,
|
||||
uni-page-body,
|
||||
uni-page-head,
|
||||
.uni-page-head {
|
||||
background-color: var(--neutral-color-white) !important;
|
||||
}
|
||||
.navBox{
|
||||
position: static;
|
||||
}
|
||||
.loginBox {
|
||||
padding: 100rpx 34rpx 0 66rpx;
|
||||
.tit {
|
||||
line-height: 66rpx;
|
||||
font-weight: 600;
|
||||
font-size: 48rpx;
|
||||
color: var(--neutral-color-main);
|
||||
letter-spacing: 0;
|
||||
display: flex;
|
||||
padding-bottom: 52rpx;
|
||||
text {
|
||||
flex: 1;
|
||||
}
|
||||
.text {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: var(--essential-color-red);
|
||||
text-align: right;
|
||||
line-height: 50rpx;
|
||||
padding-top: 14rpx;
|
||||
icon {
|
||||
background: url(../../static/icon01.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
margin-left: 14rpx;
|
||||
vertical-align: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
.loginMain {
|
||||
::v-deep .uni-input-input{
|
||||
color: var(--neutral-color-main);
|
||||
}
|
||||
padding-right: 32rpx;
|
||||
.item {
|
||||
::v-deep .is-input-border {
|
||||
padding: 36rpx 0;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
line-height: 40rpx;
|
||||
color: #797979;
|
||||
letter-spacing: 0.36rpx;
|
||||
border: 0 none;
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
.uni-easyinput__placeholder-class {
|
||||
font-size: 32rpx;
|
||||
color: var(--neutral-color-font);
|
||||
letter-spacing: 0.36rpx;
|
||||
}
|
||||
.uni-easyinput__content-input {
|
||||
padding-left: 0 !important;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
::v-deep .is-input-error-border {
|
||||
border-bottom: 1px solid var(--essential-color-red);
|
||||
margin-bottom: 44rpx;
|
||||
}
|
||||
::v-deep .content-clear-icon{
|
||||
padding: 0;
|
||||
font-size: 28rpx !important;
|
||||
line-height: 46rpx;
|
||||
}
|
||||
::v-deep .uniui-eye-filled{
|
||||
|
||||
background: url(@/static/icon-close.png) 50% 50% no-repeat;
|
||||
background-size: contain;
|
||||
&:before{
|
||||
color:transparent;
|
||||
}
|
||||
}
|
||||
::v-deep .uniui-eye-slash-filled{
|
||||
background: url(@/static/icon-open.png) 50% 50% no-repeat;
|
||||
background-size: contain;
|
||||
&:before{
|
||||
color:transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .uni-forms-item__inner {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
::v-deep .uni-error-message {
|
||||
bottom: -10rpx;
|
||||
}
|
||||
::v-deep .content-clear-icon {
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
.inputW{
|
||||
::v-deep .is-input-border{
|
||||
padding-right: 200rpx;
|
||||
}
|
||||
}
|
||||
.codeBox {
|
||||
position: absolute;
|
||||
right: 40rpx;
|
||||
top:40rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.setUrl{
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
line-height: 48rpx;
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
}
|
||||
.btn-default{
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
&.disabled{
|
||||
background-color: var(--assist-color-logbtn) !important;
|
||||
}
|
||||
}
|
||||
.btnBox{
|
||||
padding: 100rpx 0 0;
|
||||
}
|
||||
|
||||
}
|
||||
.pwdBox {
|
||||
position: relative;
|
||||
text {
|
||||
|
||||
// &.pwdIcon {
|
||||
// background: url(@/static/icon-close.png);
|
||||
// background-size: contain;
|
||||
// }
|
||||
// &.showPwdIcon {
|
||||
// background: url(@/static/icon-open.png);
|
||||
// background-size: contain;
|
||||
// }
|
||||
&.clearIcon {
|
||||
position: absolute;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
right: 60rpx;
|
||||
top: 40rpx;
|
||||
font-size: 0.875rem !important;
|
||||
line-height: 1.4375rem;
|
||||
color: rgb(192, 196, 204);
|
||||
font-family: uniicons;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
&:before{
|
||||
content: "\e66d";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.fontCol {
|
||||
color: var(--neutral-color-font);
|
||||
}
|
||||
168
project-wl-kuaidiyuan-uniapp-vue3/pages/login/index.vue
Normal file
168
project-wl-kuaidiyuan-uniapp-vue3/pages/login/index.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<!-- 手机短信登录页 -->
|
||||
<template>
|
||||
<view class="loginBox">
|
||||
<view class="tit">
|
||||
<text>手机号登录</text>
|
||||
<text class="text" @click="goLogin">
|
||||
账号登录
|
||||
<icon></icon>
|
||||
</text>
|
||||
</view>
|
||||
<!-- 登录表单 手机号、验证码 -->
|
||||
<view class="loginMain">
|
||||
<uni-forms ref="customForm" :rules="customRules" :modelValue="fromInfo">
|
||||
<uni-forms-item name="phone"
|
||||
><uni-easyinput
|
||||
class="item"
|
||||
v-model="fromInfo.phone"
|
||||
placeholder="请输入手机号"
|
||||
/></uni-forms-item>
|
||||
<uni-forms-item name="verifyCode">
|
||||
<uni-easyinput
|
||||
class="item inputW"
|
||||
v-model="fromInfo.verifyCode"
|
||||
placeholder="请输入验证码"
|
||||
/>
|
||||
<view class="codeBox">
|
||||
<text class="code" v-show="codeInfo.show" @click="getCode"
|
||||
>获取验证码</text
|
||||
>
|
||||
<text class="code fontCol" v-show="!codeInfo.show"
|
||||
>{{ codeInfo.times }}s后重新获取</text
|
||||
>
|
||||
</view>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
<!-- 按钮 -->
|
||||
<view class="btnBox">
|
||||
<button
|
||||
class="btn-default"
|
||||
:disabled="
|
||||
fromInfo.phone.length === 0 || fromInfo.verifyCode.length === 0
|
||||
"
|
||||
:class="
|
||||
fromInfo.phone.length === 0 || fromInfo.verifyCode.length === 0
|
||||
? 'disabled'
|
||||
: ''
|
||||
"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
登录
|
||||
</button>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 接口
|
||||
import { phoneLogins, getsmsCode } from "../api/user.js";
|
||||
// 验证
|
||||
import { validatePhone, timeCountdown, isPhone } from "@/utils/validate";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取储存数据
|
||||
const customForm = ref();
|
||||
let isVerifySuccess = ref(false);
|
||||
// 表单数据
|
||||
let fromInfo = reactive({
|
||||
phone: "", //手机号
|
||||
verifyCode: "", // 验证码
|
||||
});
|
||||
// 验证码倒计时数据
|
||||
let codeInfo = reactive({
|
||||
show: true,
|
||||
timer: null,
|
||||
times: 60,
|
||||
});
|
||||
// 表单校验
|
||||
const customRules = reactive({
|
||||
phone: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
validateFunction: validatePhone,
|
||||
errorMessage: "请输入手机号",
|
||||
},
|
||||
],
|
||||
},
|
||||
verifyCode: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: "请输入验证码",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {});
|
||||
// ------定义方法------
|
||||
// 获取验证码
|
||||
const getCode = async () => {
|
||||
let p = fromInfo.phone;
|
||||
|
||||
isVerifySuccess.value = isPhone(p);
|
||||
|
||||
if (isVerifySuccess.value) {
|
||||
timeCountdown(codeInfo);
|
||||
const parent = {
|
||||
phone: phone.value,
|
||||
};
|
||||
// TODO暂时保留
|
||||
// 获取手机验证码
|
||||
// const {data} = await getsmsCode(parent)
|
||||
// if(data.code===0){
|
||||
|
||||
// }else{
|
||||
// return uni.showToast({
|
||||
// title: data.msg,
|
||||
// duration: 1000,
|
||||
// icon: 'none'
|
||||
// });
|
||||
// }
|
||||
} else {
|
||||
return uni.showToast({
|
||||
title: "手机号输入错误!请重新输入",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 登录
|
||||
const handleSubmit = async () => {
|
||||
// 表单校验
|
||||
const valid = await customForm.value.validate();
|
||||
if (valid) {
|
||||
// 登录接口
|
||||
await phoneLogins(fromInfo).then((res) => {
|
||||
if (res.code === 0) {
|
||||
store.commit("user/setToken", res.token);
|
||||
// 通过vuex获取用户信息
|
||||
store.dispatch("user/GetUsersInfo");
|
||||
// 跳转到首页
|
||||
uni.redirectTo({
|
||||
url: "/pages/index/index",
|
||||
});
|
||||
} else {
|
||||
return uni.showToast({
|
||||
title: res.msg,
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
// 去手机登录页面
|
||||
const goLogin = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/user",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
165
project-wl-kuaidiyuan-uniapp-vue3/pages/login/user.vue
Normal file
165
project-wl-kuaidiyuan-uniapp-vue3/pages/login/user.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<!-- 账号登录页 -->
|
||||
<template>
|
||||
<view class="logo">神领快递员</view>
|
||||
<view class="loginBox">
|
||||
<view class="tit">
|
||||
<text>账号登录</text>
|
||||
<!-- 一期不做,暂时隐藏 -->
|
||||
<!-- <text class="text" @click="goLogin">
|
||||
手机号登录
|
||||
<icon></icon>
|
||||
</text> -->
|
||||
</view>
|
||||
<!-- 登录表单 -->
|
||||
<view class="loginMain">
|
||||
<uni-forms ref="customForm" :rules="customRules" :modelValue="fromInfo">
|
||||
<uni-forms-item name="account"><uni-easyinput class="item" v-model="fromInfo.account" placeholder="请输入账号" /></uni-forms-item>
|
||||
<uni-forms-item name="password" class="pwdBox">
|
||||
<uni-easyinput class="item" type="password" v-model="fromInfo.password" placeholder="请输入密码" />
|
||||
<text class="clearIcon" v-if="fromInfo.password.length > 0" @click="handlePwd"></text>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
<!-- 按钮 -->
|
||||
<view class="btnBox">
|
||||
<button
|
||||
class="btn-default"
|
||||
:disabled="fromInfo.account.length === 0 || fromInfo.password.length === 0"
|
||||
:class="fromInfo.account.length === 0 || fromInfo.password.length === 0 ? 'disabled' : ''"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
登录
|
||||
</button>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 更新请求Url - 教学需求 -->
|
||||
<view class="setUrl" @click="inputDialogToggle">配置请求url</view>
|
||||
<uni-popup ref="inputDialog" type="dialog">
|
||||
<uni-popup-dialog ref="inputClose" mode="input" title="配置URL" :value="baseURL" placeholder="请输入baseURL" @confirm="dialogInputConfirm"></uni-popup-dialog>
|
||||
</uni-popup>
|
||||
<!-- 更新请求Url - 教学需求 -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import storage from '@/utils/storage.js';
|
||||
// 接口
|
||||
import { userLogins } from '../api/user.js';
|
||||
// 导入接口
|
||||
import { getHomeInfo } from '@/pages/api/index.js';
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取储存数据
|
||||
let showPassword = ref(false); //控制密码右侧图标显示隐藏
|
||||
const customForm = ref(); //表单校验
|
||||
// 表单数据
|
||||
let fromInfo = reactive({
|
||||
account: 'blkdy001', //账号
|
||||
password: '123456' // 密码
|
||||
});
|
||||
// 表单校验
|
||||
const customRules = reactive({
|
||||
account: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '请输入手机号'
|
||||
}
|
||||
]
|
||||
},
|
||||
password: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '请输入验证码'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
// ------声明周期------
|
||||
onMounted(() => {
|
||||
// 进入登录页面配置默认的请求url
|
||||
// uni.setStorageSync('baseUrl', 'http://slwl-geteway-t.itheima.net/courier');
|
||||
// 处理定时上报位置的定时器
|
||||
clearInterval(uni.getStorageSync('positions').timer);
|
||||
uni.setStorageSync('positions', null);
|
||||
});
|
||||
// ------定义方法------
|
||||
// 登录
|
||||
const handleSubmit = async () => {
|
||||
// // 表单校验
|
||||
const valid = await customForm.value.validate();
|
||||
if (valid) {
|
||||
// 登录接口
|
||||
// 网络慢的时候添加按钮loading
|
||||
let times =
|
||||
setTimeout(()=>{
|
||||
uni.showLoading({
|
||||
title: 'loading',
|
||||
});
|
||||
},500)
|
||||
await userLogins(fromInfo)
|
||||
.then(async res => {
|
||||
if (res.code === 200) {
|
||||
// 操作成功后清除loading
|
||||
setTimeout(function () {
|
||||
uni.hideLoading();
|
||||
}, 500);
|
||||
clearTimeout(times)
|
||||
// 存储token
|
||||
uni.setStorageSync('token', res.data.token);
|
||||
store.commit('user/setToken', res.data.token);
|
||||
// // 通过vuex获取用户信息
|
||||
store.dispatch('user/GetUsersInfo');
|
||||
await getHomeInfo().then(res => {
|
||||
if (res.code === 200) {
|
||||
// 跳转到首页
|
||||
uni.redirectTo({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
duration: 1000,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
// uni.showToast({
|
||||
// title: err.msg,
|
||||
// duration: 15000,
|
||||
// icon: 'none'
|
||||
// });
|
||||
});
|
||||
}
|
||||
};
|
||||
// 去手机登录页面
|
||||
const goLogin = () => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
};
|
||||
// 设置密码
|
||||
const handlePwd = () => {
|
||||
fromInfo.password = '';
|
||||
};
|
||||
// 打开设置Url窗口
|
||||
const baseURL = ref(uni.getStorageSync('baseUrl'));
|
||||
const inputDialog = ref(null);
|
||||
const inputDialogToggle = () => {
|
||||
inputDialog.value.open();
|
||||
};
|
||||
// 报错配置的Url
|
||||
const dialogInputConfirm = val => {
|
||||
baseURL.value = val;
|
||||
uni.setStorageSync('baseUrl', val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss"></style>
|
||||
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<view class="nav-bg mnav-bg">
|
||||
<view class="headBg"></view>
|
||||
<view class="header">
|
||||
<view class="headBox">
|
||||
<view class="head"
|
||||
><icon v-if="baseData.avatar === ''"></icon
|
||||
><image :src="baseData.avatar" v-else></image
|
||||
></view>
|
||||
<view class="info">
|
||||
<view class="tit">{{ baseData.name }}</view>
|
||||
<view>{{ baseData.account }}</view>
|
||||
<view class="address">
|
||||
<icon></icon>
|
||||
{{ baseData.agencyName ? baseData.agencyName : "暂无" }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="QR" @click="handleQr"
|
||||
><image src="../../../static/qr.png"></image
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
baseData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
// ------定义方法------
|
||||
// 二维码暂时不做
|
||||
const handleQr = () => {
|
||||
// TODO暂时保留
|
||||
// uni.navigateTo({
|
||||
// url:'/pages/my/qrCode'
|
||||
// })
|
||||
uni.showToast({
|
||||
title: "程序员哥哥正在实现中",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./../index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<view class="boxBg headTop">
|
||||
<view class="headItem">
|
||||
<view class="item">
|
||||
<text>我的评价</text>
|
||||
<view class="star">
|
||||
<uni-rate
|
||||
:readonly="true"
|
||||
allow-half
|
||||
:value="4.5"
|
||||
active-color="#EF4F3F"
|
||||
color="#F4F4F4"
|
||||
/>
|
||||
<text>{{ 4.5 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text>排班时间</text>
|
||||
<text
|
||||
v-if="
|
||||
(!baseData.startTime || baseData.startTime === '') &&
|
||||
(!baseData.endTime || baseData.endTime === '')
|
||||
"
|
||||
>无</text
|
||||
>
|
||||
<text v-else
|
||||
>{{ overTimeFormat(baseData.startTime) }}-{{
|
||||
overTimeFormat(baseData.endTime)
|
||||
}}</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// 时间处理
|
||||
import { overTimeFormat } from "@/utils/index.js";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
baseData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style src="./../index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<view class="boxBg">
|
||||
<view class="headItem">
|
||||
<view class="item" @click="handleHistory">
|
||||
<text>全部取派</text>
|
||||
<text><icon class="nextIcon"></icon></text>
|
||||
</view>
|
||||
<navigator url="/pages/my/map" open-type="redirect">
|
||||
<view class="item">
|
||||
<text>作业范围</text>
|
||||
<text><icon class="nextIcon"></icon></text>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore(); //vuex获取储存数据
|
||||
// ------定义方法------
|
||||
// 历史派件
|
||||
const handleHistory = () => {
|
||||
store.commit("user/setTabIndex", 0);
|
||||
store.commit("user/setTaskStatus", -1);
|
||||
uni.navigateTo({
|
||||
url: "/pages/history/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./../index.scss" lang="scss" scoped></style>
|
||||
143
project-wl-kuaidiyuan-uniapp-vue3/pages/my/index.scss
Normal file
143
project-wl-kuaidiyuan-uniapp-vue3/pages/my/index.scss
Normal file
@@ -0,0 +1,143 @@
|
||||
.mnav-bg{
|
||||
height: 370rpx;
|
||||
}
|
||||
.header {
|
||||
padding: 122rpx 86rpx 102rpx 64rpx;
|
||||
color: var(--neutral-color-white);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 40rpx;
|
||||
font-size: var(--font-size-16);
|
||||
.headBox {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
.head {
|
||||
icon{
|
||||
background: url(@/static/head.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 116rpx;
|
||||
height: 116rpx;
|
||||
}
|
||||
image{
|
||||
width: 114rpx;
|
||||
height: 114rpx;
|
||||
}
|
||||
|
||||
padding-right: 26rpx;
|
||||
}
|
||||
.tit {
|
||||
padding-bottom: 2rpx;
|
||||
}
|
||||
.address {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--font-size-14);
|
||||
padding-top: 8rpx;
|
||||
icon {
|
||||
background: url(@/static/address.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
flex: 1;
|
||||
font-size: var(--font-size-16);
|
||||
}
|
||||
}
|
||||
.QR {
|
||||
image {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.headTop {
|
||||
margin-top: -80rpx;
|
||||
}
|
||||
.headItem {
|
||||
padding: 0 34rpx;
|
||||
font-size: var(--font-size-16);
|
||||
.item {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// &:last-child {
|
||||
// border: 0 none;
|
||||
// }
|
||||
text {
|
||||
&:first-child {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.star {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
::v-deep .uni-icons {
|
||||
font-size: 48rpx !important;
|
||||
}
|
||||
::v-deep .uni-rate__icon {
|
||||
margin-right: 6rpx !important;
|
||||
}
|
||||
// icon {
|
||||
// background: url(@/static/star.png) no-repeat;
|
||||
// background-size: contain;
|
||||
// width: 32rpx;
|
||||
// height: 32rpx;
|
||||
// margin-left: 16rpx;
|
||||
// }
|
||||
}
|
||||
.boxBg {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.qrCode {
|
||||
.boxBg {
|
||||
margin-top: 32rpx;
|
||||
text-align: center;
|
||||
padding: 52rpx 60rpx 68rpx;
|
||||
}
|
||||
.img {
|
||||
padding: 30rpx 0;
|
||||
image {
|
||||
width: 416rpx;
|
||||
height: 410rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.qrHead {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
width: 416rpx;
|
||||
margin: 0 auto;
|
||||
|
||||
.head {
|
||||
background: url(@/static/head.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 86rpx;
|
||||
height: 86rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-left:20rpx;
|
||||
}
|
||||
.star {
|
||||
font-size: 20rpx;
|
||||
::v-deep .uni-icons {
|
||||
font-size: 28rpx !important;
|
||||
}
|
||||
::v-deep .uni-rate__icon {
|
||||
margin-right: 4rpx !important;
|
||||
}
|
||||
}
|
||||
.tit{
|
||||
font-size: var(--font-size-13);
|
||||
font-weight: 600;
|
||||
padding-bottom: 4rpx;
|
||||
}
|
||||
}
|
||||
55
project-wl-kuaidiyuan-uniapp-vue3/pages/my/index.vue
Normal file
55
project-wl-kuaidiyuan-uniapp-vue3/pages/my/index.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<!-- 我的页面 -->
|
||||
<template>
|
||||
<view class="navFrame">
|
||||
<!-- 我的基本信息 -->
|
||||
<BaseInfo :baseData="baseData"></BaseInfo>
|
||||
<!-- end -->
|
||||
<!-- 我的评价、排班时间 -->
|
||||
<Evaluate :baseData="baseData"></Evaluate>
|
||||
<!-- end -->
|
||||
<!-- 历史取派、作业范围 -->
|
||||
<HistoryScope></HistoryScope>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- 退出按钮 -->
|
||||
<view class="footBtn">
|
||||
<view class="btnBox"
|
||||
><button class="btn-default" @click="handleOut">退出登录</button></view
|
||||
>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- footer -->
|
||||
<UniFooter :pagePath="'pages/my/index'"></UniFooter>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
// 时间处理
|
||||
import { overTimeFormat } from "@/utils/index.js";
|
||||
// 导入组件
|
||||
// 底部导航
|
||||
import UniFooter from "@/components/uni-footer/index.vue";
|
||||
// 基本信息
|
||||
import BaseInfo from "./commponents/BaseInfo.vue"
|
||||
// 我的评价、排班时间
|
||||
import Evaluate from "./commponents/Evaluate.vue"
|
||||
// 历史取派、作业范围
|
||||
import HistoryScope from "./commponents/HistoryScope.vue"
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取储存数据
|
||||
let baseData = uni.getStorageSync("userInfo"); //获取登录时保存的用户信息
|
||||
// 退出
|
||||
const handleOut = () => {
|
||||
// 移除指定 token
|
||||
uni.removeStorageSync("token");
|
||||
// 清理本地数据缓存
|
||||
// uni.clearStorage();
|
||||
// 移出当前的tab触发事件index值,再次登录后底部菜单会默认选中首页
|
||||
store.commit("setFootStatus", 0);
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/user",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
87
project-wl-kuaidiyuan-uniapp-vue3/pages/my/map.vue
Normal file
87
project-wl-kuaidiyuan-uniapp-vue3/pages/my/map.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<!-- 作业范围页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="content"
|
||||
><map
|
||||
class="mapBox"
|
||||
:latitude="latitude"
|
||||
:longitude="longitude"
|
||||
:polygons="polygons"
|
||||
scale="16"
|
||||
></map
|
||||
></view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 导入接口
|
||||
import { getUserScope } from "@/pages/api/my.js";
|
||||
// ------定义变量------
|
||||
const title = ref("作业范围"); //nav标题
|
||||
const latitude = ref(39.997534); //维度
|
||||
const longitude = ref(116.475334); //经度
|
||||
const polygons = reactive([
|
||||
{
|
||||
//多边形的坐标数组
|
||||
points: [
|
||||
{
|
||||
longitude: 116.475334,
|
||||
latitude: 39.997534,
|
||||
},
|
||||
{
|
||||
longitude: 116.476627,
|
||||
latitude: 39.998315,
|
||||
},
|
||||
{
|
||||
longitude: 116.478603,
|
||||
latitude: 39.99879,
|
||||
},
|
||||
{
|
||||
longitude: 116.478529,
|
||||
latitude: 40.000296,
|
||||
},
|
||||
{
|
||||
longitude: 116.475082,
|
||||
latitude: 40.000151,
|
||||
},
|
||||
{
|
||||
longitude: 116.473421,
|
||||
latitude: 39.998717,
|
||||
},
|
||||
],
|
||||
fillColor: "#EF4F3F20", //填充颜色后两个数值是透明度
|
||||
strokeColor: "#EF4F3F", //描边颜色
|
||||
strokeWidth: 2, //描边宽度
|
||||
zIndex: 1, //层级
|
||||
dottedLine: true,
|
||||
},
|
||||
]);
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
getUserPolygon();
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取作业范围
|
||||
const getUserPolygon = async () => {
|
||||
await getUserScope().then((res) => {
|
||||
if (res.code === 200) {
|
||||
// TODO暂时保留
|
||||
// polygons[0].points=res.data.polygon
|
||||
// latitude.value=polygons[0].points[0].latitude
|
||||
// longitude.value=polygons[0].points[0].longitude
|
||||
}
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/my/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
51
project-wl-kuaidiyuan-uniapp-vue3/pages/my/qrCode.vue
Normal file
51
project-wl-kuaidiyuan-uniapp-vue3/pages/my/qrCode.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<!-- 专属二维码页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="pageBox qrCode">
|
||||
<view class="boxBg">
|
||||
<view class="qrHead">
|
||||
<view class="head"></view>
|
||||
<view class="info">
|
||||
<view class="tit">神领快递员-张全蛋</view>
|
||||
<view class="star">
|
||||
<uni-rate
|
||||
:readonly="true"
|
||||
allow-half
|
||||
:value="4.5"
|
||||
active-color="#EF4F3F"
|
||||
color="#F4F4F4"
|
||||
/>
|
||||
<text>4.7</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="img"><image src="../../static/scanPay.png"></image></view>
|
||||
<view>扫码快速下单</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 导入接口
|
||||
import { getUserScope } from "@/pages/api/my.js";
|
||||
// ------定义变量------
|
||||
const title = ref("专属二维码"); //nav标题
|
||||
|
||||
// ------生命周期------
|
||||
onMounted(() => {});
|
||||
// ------定义方法------
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/my/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<view v-if="tabIndex === 0">
|
||||
<!-- 垂直滚动区域 scroll和swiper的高度都要给且是一样的高度-->
|
||||
<scroll-view scroll-y="true">
|
||||
<view v-if="newItemData.length > 0">
|
||||
<view class="boxCon">
|
||||
<view class="tabConList">
|
||||
<view
|
||||
class="item"
|
||||
v-for="(item, index) in newItemData"
|
||||
:key="index"
|
||||
>
|
||||
<view @click="handleClick(item)">
|
||||
<text class="text active">
|
||||
{{ item.title }}
|
||||
</text>
|
||||
<text class="time">{{ taskTimeFormat(item.created) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 暂时先不做,后期做 -->
|
||||
<!-- <ReachBottom v-if="loading" :loadingText="loadingText"></ReachBottom> -->
|
||||
</view>
|
||||
|
||||
<!-- 无数据显示 -->
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { taskTimeFormat } from "@/utils/index.js";
|
||||
// 公告数据
|
||||
import { newItemData } from "@/utils/commonData.js";
|
||||
// 接口api
|
||||
import { getNewList } from "@/pages/api/news.js";
|
||||
// 导入组件
|
||||
//空页面
|
||||
import EmptyPage from "@/components/uni-empty-page/index.vue";
|
||||
// 下拉提示
|
||||
import ReachBottom from "@/components/reach-bottom/index.vue";
|
||||
// ------定义变量------
|
||||
let loadingText = ref("");
|
||||
let loading = ref(false);
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 当前触发的tab值
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const emit = defineEmits("handleSearch"); //子组件向父组件事件传递
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
// init();
|
||||
});
|
||||
// ------定义方法------
|
||||
const init = () => {
|
||||
// TODO 暂时不做此功能数据先写死
|
||||
// getList();
|
||||
};
|
||||
// 获取公告列表
|
||||
const getList = async () => {
|
||||
await getNewList("300")
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
itemData.value = res.data;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return uni.showToast({
|
||||
title: err.msg,
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
});
|
||||
};
|
||||
const handleClick = async (item) => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/news/detail?obj=" + JSON.stringify(item),
|
||||
});
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
getList,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<view v-if="tabIndex === 1">
|
||||
<scroll-view scroll-y="true">
|
||||
<view>
|
||||
<view class="boxCon">
|
||||
<view class="newConBox">
|
||||
<view class="item">
|
||||
<navigator
|
||||
:url="'/pages/news/system?title=取件相关&type=' + 301"
|
||||
open-type="redirect"
|
||||
>
|
||||
<view
|
||||
class="icon send"
|
||||
:class="objData.haveNewSendNotice ? 'active' : ''"
|
||||
><icon></icon
|
||||
></view>
|
||||
<view class="text">
|
||||
<view>取件相关</view>
|
||||
<view>{{
|
||||
objData.newSendNoticeTime
|
||||
? "您有一个新的取件订单"
|
||||
: "暂无消息"
|
||||
}}</view>
|
||||
</view>
|
||||
<text class="time" v-if="objData.newSendNoticeTime">{{
|
||||
taskTimeFormat(objData.newSendNoticeTime)
|
||||
}}</text>
|
||||
</navigator>
|
||||
</view>
|
||||
<view class="item">
|
||||
<navigator
|
||||
:url="'/pages/news/system?title=派件相关&type=' + 304"
|
||||
open-type="redirect"
|
||||
>
|
||||
<view
|
||||
class="icon delivery"
|
||||
:class="objData.haveNewDispatchNotice ? 'active' : ''"
|
||||
><icon></icon
|
||||
></view>
|
||||
<view class="text">
|
||||
<view>派件相关</view>
|
||||
<view>{{
|
||||
objData.newDispatchNoticeTime
|
||||
? "您有一个新的派件订单"
|
||||
: "暂无消息"
|
||||
}}</view>
|
||||
</view>
|
||||
<text class="time" v-if="objData.newDispatchNoticeTime">{{
|
||||
taskTimeFormat(objData.newDispatchNoticeTime)
|
||||
}}</text>
|
||||
</navigator>
|
||||
</view>
|
||||
<view class="item">
|
||||
<navigator
|
||||
:url="'/pages/news/system?title=签收提醒&type=' + 302"
|
||||
open-type="redirect"
|
||||
>
|
||||
<view
|
||||
class="icon income"
|
||||
:class="objData.haveNewReceiveNotice ? 'active' : ''"
|
||||
><icon></icon
|
||||
></view>
|
||||
<view class="text">
|
||||
<view>签收提醒</view>
|
||||
<view>{{
|
||||
objData.newReceiveNoticeTime
|
||||
? "您有一个派件已签收"
|
||||
: "暂无消息"
|
||||
}}</view>
|
||||
</view>
|
||||
<text class="time" v-if="objData.newReceiveNoticeTime">{{
|
||||
taskTimeFormat(objData.newReceiveNoticeTime)
|
||||
}}</text>
|
||||
</navigator>
|
||||
</view>
|
||||
<view class="item">
|
||||
<navigator
|
||||
:url="'/pages/news/system?title=快件取消&type=' + 303"
|
||||
open-type="redirect"
|
||||
>
|
||||
<view
|
||||
class="icon cancel"
|
||||
:class="objData.haveNewCancelNotice ? 'active' : ''"
|
||||
><icon></icon
|
||||
></view>
|
||||
<view class="text">
|
||||
<view>快件取消</view>
|
||||
<view>{{
|
||||
objData.newCancelNoticeTime
|
||||
? "您有一个快件已取消"
|
||||
: "暂无消息"
|
||||
}}</view>
|
||||
</view>
|
||||
<text class="time" v-if="objData.newCancelNoticeTime">{{
|
||||
taskTimeFormat(objData.newCancelNoticeTime)
|
||||
}}</text>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { taskTimeFormat } from "@/utils/index.js";
|
||||
// 接口api
|
||||
import { getNotice } from "@/pages/api/news.js";
|
||||
// 导入组件
|
||||
// ------定义变量------
|
||||
let objData = ref({}); //列表数据
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 当前触发的tab值
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const emit = defineEmits("getTabIndex"); //子组件向父组件事件传递
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
getOjb();
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取系统通知
|
||||
const getOjb = async () => {
|
||||
await getNotice()
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
objData.value = res.data;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return uni.showToast({
|
||||
title: err.msg,
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
});
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
getOjb,
|
||||
});
|
||||
</script>
|
||||
68
project-wl-kuaidiyuan-uniapp-vue3/pages/news/detail.vue
Normal file
68
project-wl-kuaidiyuan-uniapp-vue3/pages/news/detail.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<!-- 公告详情页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<view class="navHead"><UniNav :title="title" @goBack="goBack"></UniNav></view>
|
||||
<!-- end -->
|
||||
<!-- 列表 -->
|
||||
<view class="pageBox newDetail">
|
||||
<view class="tit">{{ objData.title }}</view>
|
||||
<view class="time">{{ taskTimeFormat(objData.created) }}</view>
|
||||
<view v-if="objData.firstContent" class="first">{{
|
||||
objData.firstContent
|
||||
}}</view>
|
||||
<view>{{ objData.content }}</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { taskTimeFormat } from "@/utils/index.js";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
|
||||
// ------定义变量------
|
||||
const title = ref("详情"); //nav标题
|
||||
const pages = getCurrentPages(); //获取加载的页面,获取当前页面路由信息uniapp 做安卓不支持 vue-router
|
||||
const currentPage = pages[pages.length - 1]; //获取当前页面的对象
|
||||
let objData = ref(JSON.parse(currentPage.$page.options.obj)); //基本数据 获取列表页传过来的详情页,此页没有详情接口
|
||||
// ------定义方法------
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
body,
|
||||
uni-page-body,
|
||||
uni-page-head,
|
||||
.uni-page-head {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
.pageBox {
|
||||
box-shadow: inset 0 22rpx 22rpx 0 rgba(162, 162, 162, 0.06);
|
||||
}
|
||||
.newDetail {
|
||||
padding: 60rpx 32rpx;
|
||||
color: var(--neutral-color-font);
|
||||
line-height: 48rpx;
|
||||
font-size: var(--font-size-13);
|
||||
.tit {
|
||||
line-height: 60rpx;
|
||||
font-size: var(--font-size-16);
|
||||
color: var(--neutral-color-main);
|
||||
font-weight: 600;
|
||||
}
|
||||
.time {
|
||||
font-size: var(--font-size-12);
|
||||
padding: 4rpx 0 28rpx;
|
||||
}
|
||||
.first {
|
||||
padding: 15rpx 0 40rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
124
project-wl-kuaidiyuan-uniapp-vue3/pages/news/index.scss
Normal file
124
project-wl-kuaidiyuan-uniapp-vue3/pages/news/index.scss
Normal file
@@ -0,0 +1,124 @@
|
||||
body,
|
||||
uni-page-body {
|
||||
background: var(--neutral-color-background) !important;
|
||||
}
|
||||
.newBox {
|
||||
.tabScroll {
|
||||
margin-bottom: 32rpx;
|
||||
background: var(--neutral-color-white);
|
||||
::v-deep .uni-scroll-view-content {
|
||||
font-size: var(--font-size-14) !important;
|
||||
.scroll-row-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .newConBox {
|
||||
.item {
|
||||
line-height: 40rpx;
|
||||
padding: 0 28rpx;
|
||||
|
||||
|
||||
color: var(--neutral-color-font);
|
||||
position: relative;
|
||||
font-size: var(--font-size-12);
|
||||
.navigator-wrap{
|
||||
uni-navigator{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
padding: 32rpx 0 28rpx;
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
view{
|
||||
&:first-child{
|
||||
color: var(--neutral-color-main);
|
||||
font-size: var(--font-size-14);
|
||||
padding-bottom: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.icon {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
margin-right: 36rpx;
|
||||
position: relative;
|
||||
&.send {
|
||||
background: url(@/static/icon17.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.delivery {
|
||||
background: url(@/static/icon27.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.income {
|
||||
background: url(@/static/icon18.png);
|
||||
background-size: contain;
|
||||
|
||||
}
|
||||
&.cancel {
|
||||
background: url(@/static/icon19.png);
|
||||
background-size: contain;
|
||||
}
|
||||
&.active {
|
||||
color: var(--neutral-color-main);
|
||||
icon {
|
||||
position: absolute;
|
||||
right: -14rpx;
|
||||
top: 2rpx;
|
||||
width: 14rpx;
|
||||
height: 14rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 12rpx;
|
||||
background: var(--essential-color-red);
|
||||
}
|
||||
}
|
||||
}
|
||||
.time{
|
||||
position: absolute;
|
||||
top: 32rpx;
|
||||
right: 44rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// 详情
|
||||
|
||||
// 系统列表
|
||||
.systemList{
|
||||
.item{
|
||||
padding:30rpx 32rpx;
|
||||
color: var(--neutral-color-font);
|
||||
line-height: 52rpx;
|
||||
margin-top: 40rpx;
|
||||
.tit{
|
||||
line-height: 40rpx;
|
||||
padding-bottom: 30rpx;
|
||||
color: var(--neutral-color-main);
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
margin-bottom: 22rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.time{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text{
|
||||
flex:1
|
||||
}
|
||||
.redBtn{
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
105
project-wl-kuaidiyuan-uniapp-vue3/pages/news/index.vue
Normal file
105
project-wl-kuaidiyuan-uniapp-vue3/pages/news/index.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<!-- 消息列表页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<view class="navHead">
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
</view>
|
||||
<!-- end -->
|
||||
|
||||
<!-- 列表 -->
|
||||
<view class="pageBox newBox">
|
||||
<!-- 搜索列表 -->
|
||||
<scroll-view
|
||||
scroll-x="true"
|
||||
class="tabScroll"
|
||||
:scroll-into-view="scrollinto"
|
||||
:scroll-with-animation="true"
|
||||
>
|
||||
<view
|
||||
v-for="(item, index) in tabBars"
|
||||
:key="index"
|
||||
:id="'tab' + index"
|
||||
class="scroll-row-item"
|
||||
@click="changeTab(index)"
|
||||
>
|
||||
<view :class="tabIndex == index ? 'scroll-row-item-act' : ''">
|
||||
<text class="line"></text>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="homeSwiper">
|
||||
<!-- 公告 -->
|
||||
<Announcement ref="announcement" :tabIndex="tabIndex"></Announcement>
|
||||
<!-- end -->
|
||||
<!-- 系统通知 -->
|
||||
<Notification
|
||||
ref="notificat"
|
||||
@getTabIndex="getTabIndex"
|
||||
:tabIndex="tabIndex"
|
||||
></Notification>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 公告列表
|
||||
import Announcement from "./components/announcement.vue";
|
||||
// 系统通知
|
||||
import Notification from "./components/notification.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const announcement = ref(); //定义ref
|
||||
const notificat = ref();
|
||||
const title = ref("消息"); //nav标题
|
||||
const tabBars = reactive(["公告", "系统通知"]);
|
||||
let scrollinto = ref("tab0"); //tab切换
|
||||
let tabIndex = users.tabIndex === 1 ? ref(1) : ref(0); //当前tab
|
||||
// ------定义方法------
|
||||
// tab选项卡切换轮播
|
||||
const changeTab = (index) => {
|
||||
// 点击的还是当前数据的时候直接return
|
||||
if (tabIndex.value == index) {
|
||||
return;
|
||||
}
|
||||
// 触发tab切换接口
|
||||
if (index === 0) {
|
||||
// 当前tab值为0刷新公告列表
|
||||
// announcement.value.getList()
|
||||
} else {
|
||||
// 当前tab值为1刷新系统通知
|
||||
notificat.value.getOjb();
|
||||
}
|
||||
tabIndex.value = index;
|
||||
store.commit("user/setTabIndex", index);
|
||||
// 滑动
|
||||
scrollinto.value = "tab" + index;
|
||||
};
|
||||
|
||||
// 触发选项卡事件
|
||||
const onChangeSwiperTab = (e) => {
|
||||
changeTab(e.detail.current);
|
||||
};
|
||||
// 获取子组件传来的tabindex
|
||||
const getTabIndex = (val) => {
|
||||
tabIndex.value = val;
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/index/index",
|
||||
});
|
||||
store.commit("user/setNewType", null);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
231
project-wl-kuaidiyuan-uniapp-vue3/pages/news/system.vue
Normal file
231
project-wl-kuaidiyuan-uniapp-vue3/pages/news/system.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<!-- 系统通知列表页 取件相关、签收提醒、快件取消 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<view class="navHead">
|
||||
<UniNav
|
||||
:title="title"
|
||||
@goBack="goBack"
|
||||
@handleAll="handleAll"
|
||||
:rithtText="rithtText"
|
||||
></UniNav>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 列表 -->
|
||||
<view class="pageBox newBox">
|
||||
<scroll-view
|
||||
scroll-y="true"
|
||||
:style="{ height: scrollH + 'px' }"
|
||||
v-if="itemData.length > 0"
|
||||
>
|
||||
<view class="systemList">
|
||||
<view class="boxBg item" v-for="(item, index) in itemData" :key="index">
|
||||
<view class="tit" :class="item.isRead === 0 ? 'active' : ''">
|
||||
<icon></icon>
|
||||
<text v-if="title === '取件相关'">您有一个新的取件订单</text>
|
||||
<text v-else-if="title === '派件相关'">您有一个新的派件订单</text>
|
||||
<text v-else-if="title === '签收提醒'">您有一个派件已签收</text>
|
||||
<text v-else>您有一个快件已取消</text>
|
||||
</view>
|
||||
<view class="address">{{ item.content }}</view>
|
||||
<view class="time">
|
||||
<text>{{ taskTimeFormat(item.created) }}</text>
|
||||
<button class="uni-btn redBtn" @click="handleDetail(item)">
|
||||
查看详情
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
</scroll-view>
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { onReachBottom } from "@dcloudio/uni-app";
|
||||
import { taskTimeFormat } from "@/utils/index.js";
|
||||
import { useStore } from "vuex";
|
||||
// 接口 api
|
||||
import { getMessagesList, msgRead, msgAllRead } from "@/pages/api/news.js";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
//空页面
|
||||
import EmptyPage from "@/components/uni-empty-page/index.vue";
|
||||
// 下拉提示
|
||||
import ReachBottom from "@/components/reach-bottom/index.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const pages = getCurrentPages(); //获取加载的页面,获取当前页面路由信息uniapp 做安卓不支持 vue-router
|
||||
const currentPage = pages[pages.length - 1].$page.options; //获取当前页面的对象
|
||||
const title = currentPage.title; //nav标题
|
||||
const type = currentPage.type; //当前派件类型
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
const emptyData = ref("暂无消息");
|
||||
const rithtText = ref("全部已读");
|
||||
let pageNumber = ref(1);
|
||||
|
||||
let totals = ref(0); //总页数
|
||||
let pageNum = ref(1); //存放当前页
|
||||
let page = reactive({
|
||||
contentType: type,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
let reload = ref(false);
|
||||
let scrollH = ref(null); //滚动高度
|
||||
let isReadAll = ref(false); //是否已全读
|
||||
let itemData = ref([]);
|
||||
let ids = ref([]);
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
if (pageNum.value >= Number(totals.value)) {
|
||||
loadMore.value.status = "noMore";
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = "loading";
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
getList();
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
// // 调用接口
|
||||
getList();
|
||||
// 获取屏幕信息
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
scrollH.value = res.windowHeight - uni.upx2px();
|
||||
},
|
||||
});
|
||||
});
|
||||
//
|
||||
// ------定义方法------
|
||||
// 获取列表
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
page = {
|
||||
...page,
|
||||
page: pageNum.value,
|
||||
};
|
||||
await getMessagesList(page).then((res) => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
itemData.value.map((val) => {
|
||||
if (val.isRead === 0) {
|
||||
ids.value.push(val.id);
|
||||
}
|
||||
});
|
||||
|
||||
totals.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = "noMore";
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 进入详情,标记已读
|
||||
const handleDetail = async (item) => {
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit("user/setTaskId", item.relevantId);
|
||||
store.commit("user/setTabIndex", 0);
|
||||
ids.value = [];
|
||||
ids.value.push(item.id);
|
||||
// 进入详情前先调用已读信息接口
|
||||
await msgRead(item.id).then((res) => {});
|
||||
|
||||
if (title === "取件相关") {
|
||||
// 方便从详情跳回列表页
|
||||
store.commit("user/setNewType", 301);
|
||||
if (item.status === 1) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/details/index",
|
||||
});
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
store.commit("user/setIsNew", true);
|
||||
}
|
||||
} else if (title === "派件相关") {
|
||||
if (item.status === 2) {
|
||||
store.commit("user/setTaskStatus", 5);
|
||||
store.commit("user/setIsNew", true);
|
||||
} else {
|
||||
store.commit("user/setTaskStatus", 4);
|
||||
}
|
||||
store.commit("user/setNewType", 304);
|
||||
uni.navigateTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
} else if (title === "签收提醒") {
|
||||
store.commit("user/setTaskStatus", 5);
|
||||
store.commit("user/setNewType", 302);
|
||||
uni.navigateTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
store.commit("user/setIsNew", true);
|
||||
} else {
|
||||
store.commit("user/setTaskStatus", null);
|
||||
store.commit("user/setNewType", 303);
|
||||
uni.navigateTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 全部已读
|
||||
const handleAll = async () => {
|
||||
let contentType = null;
|
||||
if (title === "取件相关") {
|
||||
contentType = 301;
|
||||
} else if (title === "派件相关") {
|
||||
contentType = 304;
|
||||
} else if (title === "签收提醒") {
|
||||
contentType = 302;
|
||||
} else {
|
||||
contentType = 303;
|
||||
}
|
||||
await msgAllRead(contentType)
|
||||
.then((res) => {
|
||||
itemData.value = [];
|
||||
pageNum.value = 1;
|
||||
getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
isReadAll.value = true;
|
||||
return uni.showToast({
|
||||
title: err.msg,
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
});
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
store.commit("user/setTabIndex", 1);
|
||||
if (users.taskStatus === -1) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/index/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/news/index",
|
||||
});
|
||||
}
|
||||
store.commit("user/setTaskStatus", 0);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<uni-popup
|
||||
ref="uppop"
|
||||
type="center"
|
||||
:animation="false"
|
||||
class="comPop"
|
||||
:mask-click="false"
|
||||
>
|
||||
<view class="con">用户已支付!</view>
|
||||
<view><button @click="goList">返回主页</button></view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
tipInfo: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const emit = defineEmits(); //子组件向父组件事件传递
|
||||
const uppop = ref();
|
||||
// ------定义方法------
|
||||
// 打开弹层
|
||||
const dialogOpen = () => {
|
||||
uppop.value.open();
|
||||
};
|
||||
// 关闭弹层
|
||||
const dialogClose = () => {
|
||||
uppop.value.close();
|
||||
};
|
||||
// 返回任务列表页
|
||||
const goList = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
};
|
||||
// 向父组件暴露方法
|
||||
defineExpose({
|
||||
dialogOpen,
|
||||
});
|
||||
</script>
|
||||
131
project-wl-kuaidiyuan-uniapp-vue3/pages/pay/index.scss
Normal file
131
project-wl-kuaidiyuan-uniapp-vue3/pages/pay/index.scss
Normal file
@@ -0,0 +1,131 @@
|
||||
body,
|
||||
uni-page-body,
|
||||
uni-page-head,
|
||||
.uni-page-head {
|
||||
background-color: var(--neutral-color-background) !important;
|
||||
}
|
||||
.pickUp {
|
||||
padding: 200rpx 0 0;
|
||||
font-size: 36rpx;
|
||||
line-height: 50rpx;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
icon {
|
||||
background: url(@/static/chenggong@2x.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 146rpx;
|
||||
height: 146rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.btnBox {
|
||||
padding-top: 64rpx;
|
||||
}
|
||||
::v-deep .navigator-wrap {
|
||||
width: 300rpx;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
display: inline-block;
|
||||
background: var(--neutral-color-white) !important;
|
||||
border-radius: 20rpx;
|
||||
color: var(--neutral-color-main) !important;
|
||||
font-size: var(--font-size-16);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.scanPay {
|
||||
.boxBg {
|
||||
margin-top: 32rpx;
|
||||
padding: 40rpx;
|
||||
}
|
||||
.srCan {
|
||||
text-align: center;
|
||||
line-height: 40rpx;
|
||||
padding-bottom: 50rpx;
|
||||
image {
|
||||
width: 416rpx;
|
||||
height: 410rpx;
|
||||
}
|
||||
.text {
|
||||
color: var(--essential-color-red);
|
||||
font-size: 50rpx;
|
||||
font-weight: 6 00;
|
||||
line-height: 58rpx;
|
||||
text {
|
||||
font-size: var(--font-size-13);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
:deep(uni-canvas){
|
||||
width: 416rpx;
|
||||
height: 400rpx;
|
||||
margin: 0 auto;
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
.payBox {
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--font-size-16);
|
||||
line-height: 52rpx;
|
||||
icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
& > view {
|
||||
&:first-child {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
icon {
|
||||
background: url(@/static/weChat.png) no-repeat;
|
||||
background-size: contain;
|
||||
|
||||
}
|
||||
}
|
||||
::v-deep .uni-radio-input {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
.checkRadio {
|
||||
uni-radio {
|
||||
vertical-align: super;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
& > view {
|
||||
&:first-child {
|
||||
icon {
|
||||
background: url(@/static/Alipay.png) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.comPop {
|
||||
|
||||
::v-deep .uni-popup__wrapper {width: 70%;
|
||||
background: var(--neutral-color-white) !important;
|
||||
border-radius: 24rpx !important;
|
||||
font-size: var(--font-size-16);
|
||||
.con{
|
||||
padding: 68rpx;
|
||||
text-align: center;
|
||||
|
||||
border-bottom: 1px solid var(--neutral-color-background);
|
||||
}
|
||||
uni-button{
|
||||
background: none;
|
||||
line-height: 94rpx;
|
||||
height: 100rpx;
|
||||
color: var(--neutral-color-font);
|
||||
font-size: var(--font-size-16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
96
project-wl-kuaidiyuan-uniapp-vue3/pages/pay/index.vue
Normal file
96
project-wl-kuaidiyuan-uniapp-vue3/pages/pay/index.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<!-- 取件成功页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav
|
||||
:title="users.isDelivery ? '签收成功' : '取件成功'"
|
||||
@goBack="goBack"
|
||||
></UniNav>
|
||||
<!-- end -->
|
||||
<view class="pickUp">
|
||||
<icon></icon>
|
||||
<view>{{ users.isDelivery ? "签收成功" : "取件成功" }}</view>
|
||||
<view class="btnBox" v-if="users.isDelivery">
|
||||
<navigator
|
||||
url="/pages/pay/scanPay?pay=true"
|
||||
open-type="redirect"
|
||||
v-if="type === '2'"
|
||||
>去收款</navigator
|
||||
>
|
||||
<view class="navigator-wrap" v-else @click="handleBack">返回主页</view>
|
||||
</view>
|
||||
<view class="btnBox" v-else>
|
||||
<navigator
|
||||
url="/pages/pay/scanPay?pay=true"
|
||||
open-type="redirect"
|
||||
v-if="type === '1'"
|
||||
>去收款</navigator
|
||||
>
|
||||
<view class="navigator-wrap" v-else @click="handleBack">返回主页</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const pages = getCurrentPages(); //获取加载的页面,获取当前页面路由信息uniapp 做安卓不支持 vue-router
|
||||
const currentPage = pages[pages.length - 1].$page.options; //获取当前页面的对象
|
||||
const type = currentPage.type;
|
||||
// ------定义方法------
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
if (users.isDelivery) {
|
||||
if (users.taskStatus === 6 && users.detailType === 2) {
|
||||
store.commit("user/setTabIndex", 1);
|
||||
uni.redirectTo({
|
||||
url: "/pages/history/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (users.taskStatus === 6) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/history/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
}
|
||||
}
|
||||
store.commit("user/setIsPickUp", false);
|
||||
store.commit("user/setIsSign", false);
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
if (users.isDelivery) {
|
||||
if (users.paymentMethod === 2) {
|
||||
store.commit("user/setIsCollect", true);
|
||||
} else {
|
||||
store.commit("user/setIsSign", true);
|
||||
}
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
} else {
|
||||
if (users.paymentMethod === 2) {
|
||||
store.commit("user/setIsCollect", true);
|
||||
}
|
||||
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/index",
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
227
project-wl-kuaidiyuan-uniapp-vue3/pages/pay/scanPay.vue
Normal file
227
project-wl-kuaidiyuan-uniapp-vue3/pages/pay/scanPay.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<!-- 扫码支付页 -->
|
||||
<template>
|
||||
<!-- 自定义头部 -->
|
||||
<UniNav :title="title" @goBack="goBack"></UniNav>
|
||||
<!-- end -->
|
||||
<view class="pageBox scanPay">
|
||||
<view class="boxBg srCan">
|
||||
<view class="qr-box" v-if="qrShow"><canvas canvas-id="qrcode" /></view>
|
||||
<image :src="qrCodeImg" v-else></image>
|
||||
<view class="text">
|
||||
<text>¥</text>
|
||||
{{ detailsData.freight }}
|
||||
</view>
|
||||
<view>支付运费</view>
|
||||
</view>
|
||||
<view class="boxBg payBox" v-for="(item, index) in PayWayData" :key="index">
|
||||
<view class="item">
|
||||
<view>
|
||||
<icon></icon>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
<view>
|
||||
<view class="checkRadio"
|
||||
><radio
|
||||
:value="String(index)"
|
||||
:class="index === current ? 'active' : ''"
|
||||
:checked="index === current"
|
||||
@click="checkbox(index)"
|
||||
/></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 支付成功弹层 -->
|
||||
<Uppop ref="uppop"></Uppop>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import uQRCode from "@/utils/uqrcode.js"; //引入uqrcode.js
|
||||
// 获取数据
|
||||
import { PayWayData } from "@/utils/commonData.js";
|
||||
// 接口
|
||||
import { getQrCode, paySucceed, getDetail } from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 导航组件
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
import Uppop from "./components/uppop.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const uppop = ref();
|
||||
const title = ref("扫码支付"); //nav标题
|
||||
const pages = getCurrentPages(); //获取加载的页面,获取当前页面路由信息uniapp 做安卓不支持 vue-router
|
||||
const currentPage = pages[pages.length - 1]; //获取当前页面的对象
|
||||
const type = currentPage.$page.options.type;
|
||||
const pay = currentPage.$page.options.pay;
|
||||
let isLeftText = true; //是否显示左侧文字
|
||||
let current = ref(0); //当前触发付款方式的值
|
||||
let qrCodeImg = ref("");
|
||||
let times = ref(null);
|
||||
let detailsData = ref({}); //详情数据
|
||||
let qrShow = ref(false); //二维码支付有两种情况:一种是后端返回的base64图片,另一种是后端返回的二维码地址,需要前端来做处理
|
||||
|
||||
onMounted(() => {
|
||||
getDetails();
|
||||
// 10秒钟监听一下付款状态是否付款
|
||||
times.value = setInterval(() => {
|
||||
getPaySucceed();
|
||||
}, 10000);
|
||||
});
|
||||
// ------定义方法------
|
||||
const getPaySucceed = async () => {
|
||||
await paySucceed(users.detailsData.orderId).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// 如果付款成功,弹出付款成功弹层
|
||||
if (res.data) {
|
||||
// 清除定时器
|
||||
clearInterval(times.value);
|
||||
uppop.value.dialogOpen();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取订单详情
|
||||
const getDetails = async () => {
|
||||
await getDetail(users.taskId).then((res) => {
|
||||
detailsData.value = res.data;
|
||||
store.commit("user/setDetailsData", detailsData.value);
|
||||
getCode(res.data);
|
||||
});
|
||||
};
|
||||
// 获取支付二维码
|
||||
const getCode = async (obj) => {
|
||||
let data = users.payData;
|
||||
let params = {};
|
||||
if (data.tradingAmount) {
|
||||
params = {
|
||||
memo: data.memo ? data.memo : "备注",
|
||||
payMethod: current.value === 0 ? 2 : 1,
|
||||
productOrderNo: data.productOrderNo,
|
||||
tradingAmount: data.tradingAmount,
|
||||
};
|
||||
} else {
|
||||
params = {
|
||||
memo: obj.remark ? obj.remark : "备注",
|
||||
payMethod: current.value === 0 ? 2 : 1,
|
||||
productOrderNo: obj.orderId,
|
||||
tradingAmount: obj.freight,
|
||||
};
|
||||
}
|
||||
// 网络慢的时候添加按钮loading
|
||||
let times =
|
||||
setTimeout(()=>{
|
||||
uni.showLoading({
|
||||
title: 'loading',
|
||||
});
|
||||
},500)
|
||||
// 调用接口
|
||||
await getQrCode(params).then((res) => {
|
||||
// 操作成功后清除loading
|
||||
uni.hideLoading();
|
||||
clearTimeout(times)
|
||||
const data = res.data;
|
||||
const str = data.qrCode.slice(0, 10);
|
||||
// 以base图片显示二维码
|
||||
if (str === "data:image") {
|
||||
qrCodeImg.value = data.qrCode.replace(/[\r\n]/g, "");
|
||||
} else {
|
||||
// 后端直接返回的二维码地址,需要前端处理一下返回的二维码地址
|
||||
qrCodeFun(data.qrCode);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 处理后端返回的地址生成二维码
|
||||
const qrCodeFun = (valUrl) => {
|
||||
qrShow.value = true;
|
||||
uQRCode.make({
|
||||
canvasId: "qrcode", //放置在哪个标签中,将ID设置为相同
|
||||
componentInstance: this,
|
||||
text: valUrl, //valUrl为存放要传输的数据的变量
|
||||
size: 200, //大小左右都为200 !注意要和容器大小一致
|
||||
margin: 0, //不改变大小添加白色边框
|
||||
backgroundColor: "#ffffff",
|
||||
foregroundColor: "#000000",
|
||||
fileType: "jpg",
|
||||
errorCorrectLevel: uQRCode.errorCorrectLevel.H,
|
||||
success: (res) => {},
|
||||
});
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = (index) => {
|
||||
current.value = index;
|
||||
getCode(detailsData.value);
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
// 清除定时器
|
||||
clearInterval(times.value);
|
||||
// 返回派件详情
|
||||
// 派件返回
|
||||
if (users.isDelivery) {
|
||||
if (users.detailType === 2 && users.taskStatus === 6) {
|
||||
// 如果时从历史取派的取件列表进入的,返回的时候进入到历史取派列表
|
||||
store.commit("user/setTabIndex", 1);
|
||||
uni.redirectTo({
|
||||
url: "/pages/history/index",
|
||||
});
|
||||
} else if (users.detailType === 0 && users.taskStatus === 5) {
|
||||
// 如果是派件列表进入的,返回的时候进入到派件列表
|
||||
store.commit("user/setTabIndex", 1);
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
} else if (users.isPickUp && users.paymentMethod === 2 && !pay) {
|
||||
// 如果时从派件列表进入的,返回的时候进入到派件列表
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/pay/index?type=" + users.paymentMethod,
|
||||
});
|
||||
pay = false;
|
||||
}
|
||||
} else {
|
||||
// 取件返回
|
||||
if (users.detailType === 1 && users.taskStatus === 6) {
|
||||
// 如果是从历史取派的取件列表进入的,返回的时候进入到历史取派列表取件
|
||||
store.commit("user/setTabIndex", 0);
|
||||
uni.redirectTo({
|
||||
url: "/pages/history/index",
|
||||
});
|
||||
} else if (
|
||||
users.detailType === 2 &&
|
||||
users.taskStatus === 3 &&
|
||||
!users.isSearch
|
||||
) {
|
||||
// 如果是从取件列表进入的,返回的时候进入到取件列表的已取件
|
||||
store.commit("user/setTabIndex", 1);
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
} else if (users.isPickUp && users.paymentMethod === 1 && !pay) {
|
||||
// 如果时从取件列表进入的,返回的时候进入到取件列表
|
||||
// 返回详情
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/index",
|
||||
});
|
||||
} else if (users.isSearch) {
|
||||
store.commit("user/setIsSearch", false);
|
||||
uni.redirectTo({
|
||||
url: "/pages/search/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/pay/index?type=" + users.paymentMethod,
|
||||
});
|
||||
pay = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,263 @@
|
||||
<!--已取件-->
|
||||
<template>
|
||||
<view v-if="tabIndex === 1">
|
||||
<view v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<!-- 列表内容-->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<!-- 父组件传递过来的isAdmi来控制是否显示多选框 -->
|
||||
<view class="checkbox" v-if="isAdmin">
|
||||
<view class="checkRadio"><radio :value="String(index)" :class="item.selected === true ? 'active' : ''" :checked="item.selected" @click="checkbox(index)" /></view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<view class="boxBg" :class="isAdmin ? 'adminActive' : ''">
|
||||
<view class="tabList">
|
||||
<view class="item" @click="handleDetails($event, item)">
|
||||
<view class="titInfo">订单号:SD{{ item.orderId }}</view>
|
||||
<view class="address">寄件人:{{ item.name }}</view>
|
||||
<view class="address">取件地址:{{ item.address }}</view>
|
||||
<view class="time">取件时间:{{ item.taskTime }}</view>
|
||||
<view class="time" v-if="item.amount > 0 && item.status === 2 && item.paymentMethod === 1">运费:{{ item.amount }}元</view>
|
||||
<text @click.stop="handleDetails($event, item)" class="delete" v-if="item.status === 2 && item.paymentStatus === 1 && item.paymentMethod === 1">
|
||||
<button class="uni-btn btn-default">去收款</button>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 上拉 -->
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 空页面 -->
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { onReachBottom } from '@dcloudio/uni-app';
|
||||
import { getTimeDate } from '@/utils/index.js';
|
||||
import { useStore } from 'vuex';
|
||||
//接口
|
||||
import { getDeliveryList, getSearch } from '@/pages/api/index.js';
|
||||
// 下拉提示
|
||||
import ReachBottom from '@/components/reach-bottom/index.vue';
|
||||
//空页面
|
||||
import EmptyPage from '@/components/uni-empty-page/index.vue';
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 当前高度
|
||||
// 是否触发管理按钮
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
// 是否触发管理按钮,此处是用来控制是否显示多选框
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// // 搜索分页
|
||||
searchInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const users = store.state.user;
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
let itemData = ref([]);//列表数据
|
||||
let reload = ref(false);//数据加载
|
||||
let pages = ref(0);//总页数
|
||||
let pageNum = ref(1);//当前页
|
||||
let selected = reactive(new Map());
|
||||
const emptyData = ref('暂无数据');//空页面提示
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
orderDistance: null,
|
||||
orderTime: null,
|
||||
filterOverTime: null,
|
||||
dateTime: getTimeDate(new Date()).veryDayDate,
|
||||
taskStatus: 2
|
||||
});
|
||||
let searchPage = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
store.commit('user/setIsInput', true); //是否在文本框里输入了文字
|
||||
if (pageNum.value >= pages.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = 'loading';
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
if (props.searchInfo.keyword) {
|
||||
getSearchList();
|
||||
} else {
|
||||
getList();
|
||||
}
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
// 计算是否全选或者单选
|
||||
watch(users, (newValue, oldValue) => {
|
||||
if (users.selectTaskData.size > 0) {
|
||||
for (let [key, value] of users.selectTaskData) {
|
||||
itemData.value.forEach(element => {
|
||||
if (value === element.id) {
|
||||
element.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
itemData.value.forEach(element => {
|
||||
element.selected = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
// 是否触发了搜索清空
|
||||
if (users.isSearchClear) {
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setSearchClear', false);
|
||||
}
|
||||
page = {
|
||||
...page,
|
||||
page: pageNum.value,
|
||||
orderDistance: users.orderDistance,
|
||||
orderTime: users.orderTime,
|
||||
filterOverTime: users.filterOverTime
|
||||
};
|
||||
await getDeliveryList(page).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 触发tab切换
|
||||
// 如果触发了tab切换或者触发了搜索清空
|
||||
if (users.istabChange || users.isSearchClear) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索数据
|
||||
const getSearchList = async () => {
|
||||
reload.value = true;
|
||||
let valNum = 0;
|
||||
if (!users.isInput) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
searchPage = {
|
||||
...searchPage,
|
||||
keyword: props.searchInfo.keyword,
|
||||
status: props.searchInfo.status,
|
||||
taskType: props.searchInfo.taskType,
|
||||
page: valNum ? 1 : pageNum.value
|
||||
};
|
||||
// 后端接口调用
|
||||
await getSearch(searchPage).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
if (users.istabChange || !users.isInput) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 有搜索数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemData.value.length > 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const getSelected = array => {
|
||||
selected.value = array;
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = index => {
|
||||
emit('checkbox', index);
|
||||
};
|
||||
// 取件详情页
|
||||
const handleDetails = (e, item) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit('user/setTaskId', item.id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit('user/setTaskType', 1);
|
||||
|
||||
store.commit('user/setDetailType', 2); //从已取件跳入订单详情
|
||||
if (item.status === 2 && item.paymentStatus === 1 && item.paymentMethod === 1) {
|
||||
// 未付款进入付款二维码页面
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit('user/setTaskStatus', 3);
|
||||
store.commit('user/setPayData', {});
|
||||
uni.redirectTo({
|
||||
url: '/pages/pay/scanPay'
|
||||
});
|
||||
} else {
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit('user/setTaskStatus', 2);
|
||||
// 进入详情页
|
||||
uni.redirectTo({
|
||||
url: '/pages/details/waybill'
|
||||
});
|
||||
}
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
getList,
|
||||
getSearchList
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,250 @@
|
||||
<template>
|
||||
<view v-if="tabIndex === 2">
|
||||
<view v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<!-- 列表内容-->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<view class="checkbox" v-if="isAdmin">
|
||||
<view class="checkRadio"><radio :value="String(index)" :class="item.selected === true ? 'active' : ''" :checked="item.selected" @click="checkbox(index)" /></view>
|
||||
</view>
|
||||
<view class="boxBg" :class="isAdmin ? 'adminActive' : ''">
|
||||
<view class="tabList cancelList">
|
||||
<view class="item" @click.stop="handleDetails($event, item.id)">
|
||||
<view>寄件人:{{ item.name }}</view>
|
||||
<view>取件地址:{{ item.address }}</view>
|
||||
<view>取消原因:{{ item.cancelReason }}</view>
|
||||
<view>原因描述:{{ item.cancelReasonDescription }}</view>
|
||||
<text @click.stop="handleOpen($event, item.id)" class="delete"><button class="uni-btn concelBtn">删除</button></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 上拉 -->
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 空页面 -->
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { onReachBottom } from '@dcloudio/uni-app';
|
||||
import { getTimeDate } from '@/utils/index.js';
|
||||
import { useStore } from 'vuex';
|
||||
//接口
|
||||
import { getDeliveryList, getSearch } from '@/pages/api/index.js';
|
||||
// 下拉提示
|
||||
import ReachBottom from '@/components/reach-bottom/index.vue';
|
||||
//空页面
|
||||
import EmptyPage from '@/components/uni-empty-page/index.vue';
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 是否触发管理按钮
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// // 搜索分页
|
||||
searchInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const users = store.state.user;
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
let itemData = ref([]);//列表数据
|
||||
let reload = ref(false); //数据加载
|
||||
let pages = ref(0); //总页数
|
||||
let pageNum = ref(1);//当前页
|
||||
let selected = reactive(new Map());
|
||||
const emptyData = ref('暂无数据');//空页面提示
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
orderDistance: null,
|
||||
orderTime: null,
|
||||
filterOverTime: null,
|
||||
dateTime: getTimeDate(new Date()).veryDayDate,
|
||||
taskStatus: 3
|
||||
});
|
||||
let searchPage = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
store.commit('user/setIsInput', true); //是否在文本框里输入了文字
|
||||
if (pageNum.value >= pages.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = 'loading';
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
if (props.searchInfo.keyword) {
|
||||
getSearchList();
|
||||
} else {
|
||||
getList();
|
||||
}
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
// 计算是否全选或者单选
|
||||
watch(users, (newValue, oldValue) => {
|
||||
if (users.selectTaskData.size > 0) {
|
||||
for (let [key, value] of users.selectTaskData) {
|
||||
itemData.value.forEach(element => {
|
||||
if (value === element.id) {
|
||||
element.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
itemData.value.forEach(element => {
|
||||
element.selected = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
// 是否触发了搜索清空
|
||||
if (users.isSearchClear) {
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setSearchClear', false);
|
||||
}
|
||||
page = {
|
||||
...page,
|
||||
page: pageNum.value,
|
||||
orderDistance: users.orderDistance,
|
||||
orderTime: users.orderTime,
|
||||
filterOverTime: users.filterOverTime
|
||||
};
|
||||
// 后端接口调用
|
||||
await getDeliveryList(page).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 触发tab切换
|
||||
// 如果触发了tab切换或者触发了搜索清空
|
||||
if (users.istabChange || users.isSearchClear) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索数据
|
||||
const getSearchList = async () => {
|
||||
reload.value = true;
|
||||
let valNum = 0;
|
||||
if (!users.isInput) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
searchPage = {
|
||||
...searchPage,
|
||||
keyword: props.searchInfo.keyword,
|
||||
status: props.searchInfo.status,
|
||||
taskType: props.searchInfo.taskType,
|
||||
page: valNum ? 1 : pageNum.value
|
||||
};
|
||||
// 后端接口调用
|
||||
await getSearch(searchPage).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
if (users.istabChange || !users.isInput) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 有搜索数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemData.value.length > 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const getSelected = array => {
|
||||
selected.value = array;
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = index => {
|
||||
emit('checkbox', index);
|
||||
};
|
||||
// 删除弹层
|
||||
const handleOpen = (e, id) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
emit('handleOpen', id);
|
||||
};
|
||||
// 取消详情页
|
||||
const handleDetails = (e, id) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit('user/setTaskId', id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit('user/setTaskType', 1);
|
||||
// 已取件\已取消\去派件\已签收\详情页用的是一个,所以用类型status声明 1:待取件,2:已取件,3:已取消,4:待派件,5:已签收
|
||||
// 用vuex保存状态,因为当从详情页返回列表页的时候要显示对应的tab列表项
|
||||
store.commit('user/setTaskStatus', 3);
|
||||
// 进入详情页
|
||||
uni.redirectTo({
|
||||
url: '/pages/details/waybill'
|
||||
});
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
getList,
|
||||
getSearchList
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<view v-if="tabIndex === 0">
|
||||
<view v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<!-- 列表内容 -->
|
||||
<view v-for="(item, index) in itemData" :key="index" class="expressage">
|
||||
<!-- 父组件传递过来的isAdmi来控制是否显示多选框 -->
|
||||
<view class="checkbox" v-if="isAdmin">
|
||||
<view class="checkRadio"><radio :value="String(index)" :class="item.selected === true ? 'active' : ''" :checked="item.selected" @click="checkbox(index)" /></view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<view class="boxBg" :class="isAdmin ? 'adminActive' : ''">
|
||||
<view class="tabList">
|
||||
<view class="item" @click.stop="handleDetails($event, item.id)">
|
||||
<view class="titInfo">
|
||||
<view>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
{{ item.phone }}
|
||||
<icon class="phone" @click.stop="handlePhone($event, item.phone)"></icon>
|
||||
<icon class="note" @click.stop="handleNote"></icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="address">{{ item.distance }}公里</view>
|
||||
<view class="time">预约取件时间:{{ taskTimeFormat(item.estimatedStartTime) }} 至 {{ overTimeFormat(item.estimatedEndTime) }}</view>
|
||||
<text @click.stop="handleCancel($event, item.id)" class="delete"><button class="uni-btn concelBtn">取消</button></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 上拉 -->
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
<!-- end -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 空页面 -->
|
||||
<view v-else><EmptyPage :emptyData="emptyData"></EmptyPage></view>
|
||||
<!-- end -->
|
||||
<!-- 拨打手机弹层 -->
|
||||
<Phone ref="phone" :phoneData="phoneData"></Phone>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { onReachBottom } from '@dcloudio/uni-app';
|
||||
import { getTimeDate } from '@/utils/index.js';
|
||||
import { useStore } from 'vuex';
|
||||
import { taskTimeFormat, overTimeFormat } from '@/utils/index.js';
|
||||
//接口
|
||||
import { getDeliveryList, getSearch } from '@/pages/api/index.js';
|
||||
// 下拉提示
|
||||
import ReachBottom from '@/components/reach-bottom/index.vue';
|
||||
//空页面
|
||||
import EmptyPage from '@/components/uni-empty-page/index.vue';
|
||||
import Phone from '@/components/uni-phone/index.vue';
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// 当前触发的tab值
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 是否触发管理按钮,此处是用来控制是否显示多选框
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// // 搜索分页
|
||||
searchInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
isInput: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
const phone = ref();
|
||||
let itemData = ref([]);//列表数据
|
||||
let reload = ref(false);//数据加载
|
||||
let pages = ref(0); //总页数
|
||||
let pageNum = users.isFiltrate ? 1 : ref(1); //存放当前页
|
||||
let selected = reactive(new Map());
|
||||
const emptyData = ref('暂无数据');//空页面提示
|
||||
const phoneData = ref('');
|
||||
let page = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
orderDistance: null,
|
||||
orderTime: null,
|
||||
filterOverTime: null,
|
||||
dateTime: getTimeDate(new Date()).veryDayDate,
|
||||
taskStatus: 1
|
||||
});
|
||||
let searchPage = reactive({
|
||||
latitude: users.loacation.latitude !== undefined ? users.loacation.latitude : 40.062595,
|
||||
longitude: users.loacation.longitude !== undefined ? users.loacation.longitude : 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
onMounted(() => {});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
store.commit('user/setIsInput', true); //是否在文本框里输入了文字
|
||||
if (pageNum.value >= Number(pages.value)) {
|
||||
loadMore.value.status = 'noMore';
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = 'loading';
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
|
||||
if (props.searchInfo.keyword) {
|
||||
getSearchList();
|
||||
} else {
|
||||
getList();
|
||||
}
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
|
||||
// ------生命周期------
|
||||
// 计算是否全选或者单选
|
||||
watch(users, (newValue, oldValue) => {
|
||||
if (users.selectTaskData.size > 0) {
|
||||
for (let [key, value] of users.selectTaskData) {
|
||||
itemData.value.forEach(element => {
|
||||
if (value === element.id) {
|
||||
element.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
itemData.value.forEach(element => {
|
||||
element.selected = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
//判断是否进行了距离、时间、超时任务筛选,如果是,当前页设为第一页,上拉的数值设为1,便于第二次上拉
|
||||
let valNum = 0;
|
||||
if (users.isFiltrate || users.isSearchClear) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
// 如果触发了距离、时间、超时筛选
|
||||
if (users.isFiltrate) {
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
// 是否触发了搜索清空
|
||||
if (users.isSearchClear) {
|
||||
store.commit('user/setSearchClear', false);
|
||||
}
|
||||
}
|
||||
page = {
|
||||
...page,
|
||||
page: valNum ? 1 : pageNum.value,
|
||||
orderDistance: users.orderDistance,
|
||||
orderTime: users.orderTime,
|
||||
filterOverTime: users.filterOverTime
|
||||
};
|
||||
// 后端接口调用
|
||||
await getDeliveryList(page).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 触发tab切换
|
||||
// 如果触发了tab切换或者触发了搜索清空
|
||||
if (users.istabChange || users.isSearchClear) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索数据
|
||||
const getSearchList = async () => {
|
||||
reload.value = true;
|
||||
let valNum = 0;
|
||||
if (!users.isInput) {
|
||||
valNum = 1;
|
||||
pageNum.value = 1;
|
||||
store.commit('user/setIsFiltrate', false);
|
||||
}
|
||||
searchPage = {
|
||||
...searchPage,
|
||||
keyword: props.searchInfo.keyword,
|
||||
status: props.searchInfo.status,
|
||||
taskType: props.searchInfo.taskType,
|
||||
page: valNum ? 1 : pageNum.value
|
||||
};
|
||||
// 后端接口调用
|
||||
await getSearch(searchPage).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (users.deliveryData.length === 0) {
|
||||
itemData.value = [];
|
||||
}
|
||||
if (users.istabChange || !users.isInput) {
|
||||
itemData.value = res.data.items;
|
||||
store.commit('user/setIstabChange', false);
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
|
||||
pages.value = res.data.pages;
|
||||
// 存储列表数据
|
||||
store.commit('user/setDeliveryData', itemData.value);
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = 'noMore';
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 有搜索数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemData.value.length > 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取多选或者单选的数据
|
||||
const getSelected = array => {
|
||||
selected.value = array;
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = index => {
|
||||
emit('checkbox', index);
|
||||
};
|
||||
// 去取件
|
||||
const handleDetails = (e, id) => {
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit('user/setTaskId', id);
|
||||
// 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
store.commit('user/setTaskType', 1);
|
||||
store.commit('user/setIsBack', '');
|
||||
store.commit('user/setDetailType', 2); //从待取件跳入订单详情
|
||||
e.stopPropagation();
|
||||
// 进入详情页
|
||||
uni.redirectTo({
|
||||
url: '/pages/details/index'
|
||||
});
|
||||
};
|
||||
// 取消
|
||||
const handleCancel = (e, id) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit('user/setTaskId', id);
|
||||
// 进入订单取消申请页
|
||||
uni.redirectTo({
|
||||
url: '/pages/cancel/index'
|
||||
});
|
||||
};
|
||||
// 拨打电话弹层
|
||||
const handlePhone = (e, val) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
phoneData.value = val;
|
||||
phone.value.dialogOpen();
|
||||
};
|
||||
// 发短信
|
||||
const handleNote = () => {
|
||||
uni.showToast({
|
||||
title: '程序员哥哥正在实现中',
|
||||
duration: 1000,
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({ getList, getSearchList });
|
||||
</script>
|
||||
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<!-- 待取件 -->
|
||||
<DealParcel
|
||||
ref="dealparcel"
|
||||
:tabIndex="tabIndex"
|
||||
:isAdmin="isAdmin"
|
||||
@checkbox="checkbox"
|
||||
@getSelected="getSelected"
|
||||
:searchInfo="searchInfo"
|
||||
></DealParcel>
|
||||
<!-- end -->
|
||||
<!-- 已取件 -->
|
||||
<AlreadyParcel
|
||||
ref="already"
|
||||
:tabIndex="tabIndex"
|
||||
:isAdmin="isAdmin"
|
||||
@checkbox="checkbox"
|
||||
:searchInfo="searchInfo"
|
||||
></AlreadyParcel>
|
||||
<!-- end -->
|
||||
<!-- 已取消 -->
|
||||
<CancelParcel
|
||||
:tabIndex="tabIndex"
|
||||
ref="cancel"
|
||||
:isAdmin="isAdmin"
|
||||
@checkbox="checkbox"
|
||||
@handleOpen="handleOpen"
|
||||
:searchInfo="searchInfo"
|
||||
></CancelParcel>
|
||||
<!-- end -->
|
||||
<!-- 提示窗 -->
|
||||
<UniPopup
|
||||
ref="popup"
|
||||
:tipInfo="tipInfo"
|
||||
@handleClick="handleClick"
|
||||
></UniPopup>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
//接口
|
||||
import { taskDelete } from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 待取件
|
||||
import DealParcel from "./components/dealParcel.vue";
|
||||
// 已取件
|
||||
import AlreadyParcel from "./components/alreadyParcel.vue";
|
||||
// 已取消
|
||||
import CancelParcel from "./components/cancelParcel.vue";
|
||||
// 弹层
|
||||
import UniPopup from "@/components/uni-popup/index.vue";
|
||||
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
// tab切换数据
|
||||
tabBars: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 是否触发管理按钮
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 获取当前筛选的距离升序还是降序
|
||||
orderDistance: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 获取当前筛选的时间升序还是降序
|
||||
orderTime: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 获取当前筛选超时
|
||||
filterOverTime: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
// ------定义变量------
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
const store = useStore(); //设置、获取储存的数据
|
||||
const users = store.state.user;
|
||||
let popup = ref();
|
||||
let dealparcel = ref();
|
||||
let already = ref();
|
||||
let cancel = ref();
|
||||
const tipInfo = ref("确定要删除吗?");
|
||||
let taskId = ref("");
|
||||
let searchInfo = reactive({
|
||||
keyword: null,
|
||||
status: null,
|
||||
taskType: null,
|
||||
});
|
||||
// ------生命周期------
|
||||
// ------定义方法------
|
||||
// 获取已经选的任务
|
||||
const getSelected = (array) => {
|
||||
emit("getSelected", array);
|
||||
};
|
||||
// 获取待取件列表方法
|
||||
const dealPList = () => {
|
||||
dealparcel.value.getList();
|
||||
};
|
||||
// 搜索待取件列表方法
|
||||
const dealSearchList = () => {
|
||||
dealparcel.value.getSearchList();
|
||||
};
|
||||
// 获取已取件列表方法
|
||||
const alreadList = () => {
|
||||
already.value.getList();
|
||||
};
|
||||
// 搜索已取件列表方法
|
||||
const alreadSearchList = () => {
|
||||
already.value.getSearchList();
|
||||
};
|
||||
// 获取取消件列表方法
|
||||
const cancelList = () => {
|
||||
cancel.value.getList();
|
||||
};
|
||||
// 搜索取消件列表方法
|
||||
const cancelSearchList = () => {
|
||||
cancel.value.getSearchList();
|
||||
};
|
||||
// 确认删除
|
||||
const handleClick = async () => {
|
||||
await taskDelete(taskId.value).then((res) => {
|
||||
if (res.code === 200) {
|
||||
store.commit("user/setDeliveryData", []);
|
||||
cancel.value.getList();
|
||||
store.commit("user/setIsDelete", true);
|
||||
return uni.showToast({
|
||||
title: "删除成功!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
//左右滑动tab切换
|
||||
const onChangeSwiperTab = (e) => {
|
||||
emit("onChangeSwiperTab", e);
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = (index) => {
|
||||
emit("checkbox", index);
|
||||
};
|
||||
// 删除弹层id
|
||||
const handleOpen = (id) => {
|
||||
popup.value.dialogOpen();
|
||||
taskId.value = id;
|
||||
};
|
||||
|
||||
//把数据、方法暴漏给父组件
|
||||
defineExpose({
|
||||
dealPList,
|
||||
dealSearchList,
|
||||
alreadList,
|
||||
alreadSearchList,
|
||||
cancelList,
|
||||
cancelSearchList,
|
||||
searchInfo,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,7 @@
|
||||
.expressage {
|
||||
.tabScroll {
|
||||
.scroll-row-item {
|
||||
margin-right: 80rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
237
project-wl-kuaidiyuan-uniapp-vue3/pages/pickup/index.vue
Normal file
237
project-wl-kuaidiyuan-uniapp-vue3/pages/pickup/index.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<!-- 取件页面 -->
|
||||
<template>
|
||||
<!-- 搜索nav -->
|
||||
<SearchPage
|
||||
@handleSearch="handleSearch"
|
||||
ref="search"
|
||||
@clearSearchData="clearSearchData"
|
||||
></SearchPage>
|
||||
<!-- end -->
|
||||
<view>
|
||||
<!-- tab切换 -->
|
||||
<UniTab
|
||||
:tabBars="tabBars"
|
||||
ref="tab"
|
||||
@getTabIndex="getTabIndex"
|
||||
class="pickupTab"
|
||||
></UniTab>
|
||||
<!-- end -->
|
||||
<!-- 距离\时间\超时筛选 -->
|
||||
<ListFiltrate
|
||||
v-if="tabIndex === 0"
|
||||
@getList="getList"
|
||||
class="pickupFilrate"
|
||||
></ListFiltrate>
|
||||
<!-- end -->
|
||||
<!-- 取件状态列表 -->
|
||||
<view
|
||||
:class="tabIndex === 0 ? 'pickupBoxTop' : 'pickupTop'"
|
||||
style="padding: 0 0 200rpx 0"
|
||||
>
|
||||
<TabList
|
||||
:tabBars="tabBars"
|
||||
:tabIndex="tabIndex"
|
||||
:isAdmin="isAdmin"
|
||||
@onChangeSwiperTab="onChangeSwiperTab"
|
||||
@checkbox="checkbox"
|
||||
:isInput="isInput"
|
||||
ref="list"
|
||||
></TabList>
|
||||
</view>
|
||||
|
||||
<!-- end -->
|
||||
</view>
|
||||
<ExpressageFoot
|
||||
ref="expressageFoot"
|
||||
@getAdmin="getAdmin"
|
||||
:isAdmin="isAdmin"
|
||||
:selected="selected"
|
||||
:tabIndex="tabIndex"
|
||||
@allSelect="allSelect"
|
||||
@handleClick="handleClick"
|
||||
></ExpressageFoot>
|
||||
<!-- footer -->
|
||||
<UniFooter :pagePath="'pages/delivery/index'"></UniFooter>
|
||||
<!-- end -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// 基本数据
|
||||
import { DeliveryData } from "@/utils/commonData.js";
|
||||
// 接口api
|
||||
import { taskBatchDelete } from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 导航
|
||||
import UniNav from "@/components/uni-nav/index.vue";
|
||||
// 搜索组件
|
||||
import SearchPage from "@/components/uni-search/index.vue";
|
||||
// 底部导航
|
||||
import UniFooter from "@/components/uni-footer/index.vue";
|
||||
// tab切换
|
||||
import UniTab from "@/components/uni-tab/index.vue";
|
||||
// 筛选
|
||||
import ListFiltrate from "@/components/uni-list-filtrate/index.vue";
|
||||
// 底部管理全选组件
|
||||
import ExpressageFoot from "@/components/uni-expressage-foot/index.vue";
|
||||
// list
|
||||
import TabList from "./components/list.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore();
|
||||
const users = store.state.user;
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
const tab = ref();
|
||||
const list = ref(); //定义列表 ref
|
||||
const search = ref(); //定义搜索 ref
|
||||
const tabBars = DeliveryData;
|
||||
let tabIndex = ref(0); //当前tab
|
||||
let isInput = ref(false); //是否触发了输入框
|
||||
let isAdmin = ref(false); //是否触发管理按钮
|
||||
// 存储已选内容, 因为这个列表是增删很频繁的,所以选用map而不是数组,key对应的是数据的下标。至于value存放什么,完全由自己定
|
||||
let selected = reactive(new Map());
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
if (users.tabIndex) {
|
||||
tabIndex.value = users.tabIndex;
|
||||
}
|
||||
if (users.tabIndex === 0) {
|
||||
list.value.dealPList();
|
||||
} else if (users.tabIndex === 1) {
|
||||
list.value.alreadList();
|
||||
} else {
|
||||
list.value.cancelList();
|
||||
}
|
||||
});
|
||||
|
||||
// ------定义方法------
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
list.value.searchInfo.taskType = 1;
|
||||
list.value.searchInfo.keyword = search.value.searchVal;
|
||||
store.commit("user/setIsInput", false); //是否在文本框里输入了文字,默认false
|
||||
store.commit("user/setDeliveryData", []);
|
||||
if (tabIndex.value === 0) {
|
||||
list.value.searchInfo.status = 1;
|
||||
list.value.dealSearchList();
|
||||
} else if (tabIndex.value === 1) {
|
||||
list.value.searchInfo.status = 2;
|
||||
list.value.alreadSearchList();
|
||||
} else {
|
||||
list.value.searchInfo.status = 3;
|
||||
list.value.cancelSearchList();
|
||||
}
|
||||
};
|
||||
// 批量删除
|
||||
const handleClick = async () => {
|
||||
const ids = [];
|
||||
// 要批量删除的id
|
||||
for (const [key, value] of selected) {
|
||||
ids.push(value);
|
||||
}
|
||||
await taskBatchDelete({ idList: ids }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
list.value.cancelList();
|
||||
return uni.showToast({
|
||||
title: "删除成功!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 清除搜索
|
||||
const clearSearchData = () => {
|
||||
store.commit("user/setIsInput", true);
|
||||
store.commit("user/setDeliveryData", []); //清空列表数据
|
||||
store.commit("user/setSearchText", ""); //清空搜索框内容
|
||||
store.commit("user/setSearchClear", true); //是否清空搜索框
|
||||
list.value.searchInfo.keyword = ""; //清空搜索框内容
|
||||
// 总页数清空
|
||||
store.commit("user/setPages", 0);
|
||||
if (tabIndex.value === 0) {
|
||||
list.value.dealPList();
|
||||
} else if (tabIndex.value === 1) {
|
||||
list.value.alreadList();
|
||||
} else {
|
||||
list.value.cancelList();
|
||||
}
|
||||
};
|
||||
// 获取tab切换当前的index
|
||||
const getTabIndex = (index) => {
|
||||
store.commit("user/setFilterOverTime", null);
|
||||
search.value.searchVal = "";
|
||||
store.commit("user/setSearchText", ""); //清空搜索框内容
|
||||
store.commit("user/setSearchClear", true); //是否清空搜索框
|
||||
tabIndex.value = index;
|
||||
// 根据不同的tab值切更新 取件数据
|
||||
if (index === 0) {
|
||||
list.value.dealPList();
|
||||
} else if (index === 1) {
|
||||
list.value.alreadList();
|
||||
} else {
|
||||
list.value.cancelList();
|
||||
}
|
||||
selected.clear();
|
||||
// 修改底部管理按钮状态,因为取件、派件公用了一个底部管理组件,因此切换tab的时候先把isAdmin设置成false,以防数据混搅。
|
||||
isAdmin.value = false;
|
||||
// 存储列表数据
|
||||
store.commit("user/setDeliveryData", []);
|
||||
// 总页数清空
|
||||
store.commit("user/setPages", 0);
|
||||
store.commit("user/setSelectTaskData", new Map());
|
||||
};
|
||||
// 触发选项卡事件
|
||||
const onChangeSwiperTab = (e) => {
|
||||
tab.value.changeTab(e.detail.current);
|
||||
};
|
||||
// 获取foot底部组件的管理按钮触发值,向列表页传递,用来控制全选,单选功能
|
||||
const getAdmin = (val) => {
|
||||
isAdmin.value = val;
|
||||
};
|
||||
// 给筛选组件传递,刷新列表
|
||||
const getList = () => {
|
||||
list.value.dealPList();
|
||||
};
|
||||
// 全选与反选事件
|
||||
const allSelect = () => {
|
||||
// 已经全选情况下,就是反选,全选就说明长度一样
|
||||
let itemData = users.deliveryData;
|
||||
if (selected.size === itemData.length) {
|
||||
selected.clear(); // 全部清除
|
||||
itemData.forEach((element) => {
|
||||
element.selected = false; // 全部不选,就行了
|
||||
});
|
||||
}
|
||||
// 还未全选的状态下
|
||||
else {
|
||||
itemData.forEach((element, index) => {
|
||||
// 因为可能存在部分已经选择了,所以得先判断是否已存在,不存在才需要添加
|
||||
if (!selected.has(index)) {
|
||||
selected.set(index, element.id); // key是对应的下标index,而value是可以自定义的
|
||||
element.selected = true; // 设为选中
|
||||
}
|
||||
});
|
||||
}
|
||||
emit("getSelected", selected);
|
||||
store.commit("user/setSelectTaskData", selected);
|
||||
};
|
||||
// 选项框点击事件,参数是数据的下标
|
||||
const checkbox = (index) => {
|
||||
// 选中的状态下再次点击,即为取消选中
|
||||
let itemData = users.deliveryData;
|
||||
if (itemData[index].selected) {
|
||||
itemData[index].selected = false;
|
||||
selected.delete(index); // 然后删除对应key即可
|
||||
}
|
||||
// 未选中状态下点击
|
||||
else {
|
||||
itemData[index].selected = true;
|
||||
selected.set(index, itemData[index].id);
|
||||
}
|
||||
store.commit("user/setSelectTaskData", selected);
|
||||
};
|
||||
</script>
|
||||
<style src="../../styles/expressage.scss" lang="scss" scoped></style>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
@@ -0,0 +1,38 @@
|
||||
<!--完成未付款-->
|
||||
<template>
|
||||
<view class="item" v-if="item.taskType === 2 && item.status === 2">
|
||||
<view class="titInfo">运单号:{{ item.transportOrderId }}</view>
|
||||
<view class="address">收件人:{{ item.name }}</view>
|
||||
<view class="address">派件地址:{{ item.address }}</view>
|
||||
<view class="address">签收时间:{{ item.taskTime }}</view>
|
||||
<view class="time" v-if="item.amount > 0 && item.status === 2"
|
||||
>运费:{{ item.amount }}元</view
|
||||
>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 2
|
||||
"
|
||||
>
|
||||
<button class="uni-btn btn-default">去收款</button>
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
//进入待取件详情
|
||||
const handleDetails = (e, item) => {
|
||||
emit("handleDetails", e, item);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<!--已取件-->
|
||||
<template>
|
||||
<view class="item" v-if="item.taskType === 1 && item.status === 2">
|
||||
<view class="titInfo">订单号:SD{{ item.orderId }}</view>
|
||||
<view class="address">寄件人:{{ item.name }}</view>
|
||||
<view class="address">取件地址:{{ item.address }}</view>
|
||||
<view class="time">取件时间:{{ item.taskTime }}</view>
|
||||
<view
|
||||
class="time"
|
||||
v-if="item.amount > 0 && item.status === 2 && item.paymentMethod === 1"
|
||||
>运费:{{ item.amount }}元</view
|
||||
>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 1
|
||||
"
|
||||
>
|
||||
<button class="uni-btn btn-default">去收款</button>
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
//进入已取件详情
|
||||
const handleDetails = (e, item) => {
|
||||
emit("handleDetails", e, item);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<!--已取消-->
|
||||
<template>
|
||||
<view class="expressage" v-if="item.taskType === 1 && item.status === 3">
|
||||
<view class="cancelList">
|
||||
<view class="item">
|
||||
<view>寄件人:{{ item.name }}</view>
|
||||
<view>取件地址:{{ item.address }}</view>
|
||||
<view>取消原因:{{ item.cancelReason }}</view>
|
||||
<view>原因描述:{{ item.cancelReasonDescription }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<!--已签收-->
|
||||
<template>
|
||||
<view class="item" v-if="item.taskType === 2 && item.status === 5">
|
||||
<view class="titInfo">运单号:{{ item.transportOrderId }}</view>
|
||||
<view class="address">收件人:{{ item.name }}</view>
|
||||
<view class="address">派件地址:{{ item.address }}</view>
|
||||
<view class="address">签收时间:{{ item.taskTime }}</view>
|
||||
<view class="time" v-if="item.amount > 0 && item.status === 2"
|
||||
>运费:{{ item.amount }}元</view
|
||||
>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1 &&
|
||||
item.paymentMethod === 2
|
||||
"
|
||||
>
|
||||
<button class="uni-btn btn-default">去收款</button>
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(""); //子组件向父组件事件传递
|
||||
//进入待取件详情
|
||||
const handleDetails = (e, item) => {
|
||||
emit("handleDetails", e, item);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<!--待取件-->
|
||||
<template>
|
||||
<view
|
||||
class="item"
|
||||
v-if="(item.taskType === 1 || item.taskType === 2) && item.status === 1"
|
||||
>
|
||||
<view class="titInfo">
|
||||
{{ item.name }}
|
||||
<text>{{ item.phone }}</text>
|
||||
</view>
|
||||
<view class="address">{{ item.address }}</view>
|
||||
<view class="distance">{{ item.distance }}公里</view>
|
||||
<view class="time" v-if="item.taskType === 1"
|
||||
>预约取件时间:{{ taskTimeFormat(item.estimatedStartTime) }} 至
|
||||
{{ overTimeFormat(item.estimatedEndTime) }}</view
|
||||
>
|
||||
<view class="time" v-else>运单号:{{ item.transportOrderId }}</view>
|
||||
<text
|
||||
@click.stop="handleDetails($event, item)"
|
||||
class="delete"
|
||||
v-if="
|
||||
((item.taskType === 1 && item.paymentMethod === 1) ||
|
||||
(item.taskType === 2 && item.paymentMethod === 2)) &&
|
||||
item.status === 2 &&
|
||||
item.paymentStatus === 1
|
||||
"
|
||||
>
|
||||
<button class="uni-btn btn-default">去收款</button>
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { taskTimeFormat, overTimeFormat } from '@/utils/index.js';
|
||||
// 获取父组件数据
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(''); //子组件向父组件事件传递
|
||||
//进入待取件详情
|
||||
const handleDetails = (e, item) => {
|
||||
emit("handleDetails", e, item);
|
||||
};
|
||||
</script>
|
||||
|
||||
87
project-wl-kuaidiyuan-uniapp-vue3/pages/search/index.scss
Normal file
87
project-wl-kuaidiyuan-uniapp-vue3/pages/search/index.scss
Normal file
@@ -0,0 +1,87 @@
|
||||
body,
|
||||
uni-page-body,
|
||||
{
|
||||
background-color: var(--neutral-color-white) !important;
|
||||
}
|
||||
.recentBox {
|
||||
padding: 34rpx 38rpx;
|
||||
font-size: var(--font-size-12);
|
||||
box-shadow: inset 0 22rpx 22rpx 0 rgba(162,162,162,0.06);
|
||||
background: #fff;
|
||||
// min-height: calc(100vh - 280rpx);
|
||||
.tit {
|
||||
height: 36rpx;
|
||||
line-height: 36rpx;
|
||||
font-size: var(--font-size-13);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text{
|
||||
flex: 1;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
icon{
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
background: url(@/static/delete.png) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
.recentList {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-content: flex-start;
|
||||
margin-left: -18rpx;
|
||||
position: relative;
|
||||
.item {
|
||||
margin-top: 28rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
flex: 0 0 25%;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
background: var(--neutral-color-background);
|
||||
border-radius: 28rpx;
|
||||
margin-left: 18rpx;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.iconUp{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right:22rpx;
|
||||
text-align: center;
|
||||
.icon_img{
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
}
|
||||
}
|
||||
.serachList{
|
||||
.iconTip{
|
||||
icon{
|
||||
width:40rpx ;
|
||||
height: 44rpx;
|
||||
background: url(@/static/icon013.png);
|
||||
background-size: contain;
|
||||
}
|
||||
.send{
|
||||
background: url(@/static/icon014.png);
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
.item{
|
||||
// box-shadow: 0 0 11px 11px rgba(162,162,162,0.06);
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
}
|
||||
::v-deep .uni-scroll-view{
|
||||
overflow:inherit !important;
|
||||
}
|
||||
.concelBtn{
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
bottom: 70rpx;
|
||||
}
|
||||
.boxBg{
|
||||
box-shadow: 0 0 22rpx 22rpx rgba(162, 162, 162, 0.06)
|
||||
}
|
||||
395
project-wl-kuaidiyuan-uniapp-vue3/pages/search/index.vue
Normal file
395
project-wl-kuaidiyuan-uniapp-vue3/pages/search/index.vue
Normal file
@@ -0,0 +1,395 @@
|
||||
<!-- 首页搜索页 -->
|
||||
<template>
|
||||
<!-- 搜索nav -->
|
||||
<SearchPage
|
||||
ref="search"
|
||||
@handleSearch="handleSearch"
|
||||
@handleBlur="handleBlur"
|
||||
@clearSearchData="clearSearchData"
|
||||
@goBack="goBack"
|
||||
:isShowCancel="isShowCancel"
|
||||
></SearchPage>
|
||||
<!-- end -->
|
||||
<view class="searchTop">
|
||||
<view class="pageBox">
|
||||
<!-- 最近查找 -->
|
||||
<view class="recentBox" v-if="!isClear">
|
||||
<view class="tit">
|
||||
<text>最近查找</text>
|
||||
<icon @click="handleClear"></icon>
|
||||
</view>
|
||||
|
||||
<view class="recentList">
|
||||
<view
|
||||
class="item"
|
||||
v-for="(item, index) in listDataes.value"
|
||||
:key="index"
|
||||
@click="handleTransportOrderId(item)"
|
||||
>{{ item }}</view
|
||||
>
|
||||
<view class="iconUp" v-if="!showDisplay">
|
||||
<view
|
||||
@click="showDisplay = !showDisplay"
|
||||
v-if="itemDataRecent.length > 10"
|
||||
><image
|
||||
class="icon_img"
|
||||
src="../../static/open.png"
|
||||
mode=""
|
||||
></image
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<!-- 搜索列表 -->
|
||||
<scroll-view scroll-y="true" class="swiperH" v-if="itemData.length > 0">
|
||||
<view class="serachList">
|
||||
<view class="">
|
||||
<view class="tabList">
|
||||
<view
|
||||
class="boxBg"
|
||||
v-for="(item, index) in itemData"
|
||||
:key="index"
|
||||
@click.stop="handleDetails($event, item)"
|
||||
>
|
||||
<!-- 待取件 -->
|
||||
<StayPicup
|
||||
:item="item"
|
||||
@handleDetails="handleDetails"
|
||||
></StayPicup>
|
||||
<!-- end -->
|
||||
<!-- 已取件 -->
|
||||
<AlreadyPicUp
|
||||
:item="item"
|
||||
@handleDetails="handleDetails"
|
||||
></AlreadyPicUp>
|
||||
<!-- end -->
|
||||
<!-- 取件取消 -->
|
||||
<Canceled :item="item"></Canceled>
|
||||
<!-- end -->
|
||||
<!-- 已签收 -->
|
||||
<SignFor :item="item" @handleDetails="handleDetails"></SignFor>
|
||||
<!-- end -->
|
||||
<!-- 已经完成到付未付款 -->
|
||||
<Accomplish
|
||||
:item="item"
|
||||
@handleDetails="handleDetails"
|
||||
></Accomplish>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
</scroll-view>
|
||||
<!-- end -->
|
||||
<!-- 无数据 -->
|
||||
<view v-if="itemData.length === 0 && isClear"
|
||||
><EmptyPage :emptyData="emptyData"></EmptyPage
|
||||
></view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
|
||||
<!-- 提示窗示例 -->
|
||||
<UniPopup
|
||||
ref="popups"
|
||||
:tipInfo="tipInfo"
|
||||
@handleClick="clearData"
|
||||
></UniPopup>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed, onUnmounted } from "vue";
|
||||
import { onReachBottom } from "@dcloudio/uni-app";
|
||||
import { useStore } from "vuex";
|
||||
// 接口
|
||||
import {
|
||||
getSearch,
|
||||
getRecentSearch,
|
||||
setMarkRecent,
|
||||
clearRecentSearch,
|
||||
} from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 搜索组件
|
||||
import SearchPage from "@/components/uni-search/index.vue";
|
||||
// 暂无搜索内容
|
||||
import EmptyPage from "@/components/uni-empty-page/index.vue";
|
||||
// 弹层
|
||||
import UniPopup from "@/components/uni-popup/index.vue";
|
||||
// 下拉提示
|
||||
import ReachBottom from "@/components/reach-bottom/index.vue";
|
||||
//
|
||||
// 待取件
|
||||
import StayPicUp from "./components/StayPicUp.vue";
|
||||
// 已取件
|
||||
import AlreadyPicUp from "./components/AlreadyPicUp.vue";
|
||||
//已取消
|
||||
import Canceled from "./components/Canceled.vue";
|
||||
// 已签收
|
||||
import SignFor from "./components/SignFor.vue";
|
||||
// 完成未付款
|
||||
import Accomplish from "./components/Accomplish.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //vuex获取、储存数据
|
||||
const users = store.state.user;
|
||||
const search = ref(); //定义搜索框的ref
|
||||
let showDisplay = ref(false); //最近查找更多触发,触发之后按钮隐藏
|
||||
let isClear = ref(false); //触发清除按钮
|
||||
const tipInfo = ref("确定要全部清空吗?");
|
||||
let popups = ref();
|
||||
let isShowCancel = ref(true);
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
let reload = ref(false);
|
||||
let pages = ref(0); //总页数
|
||||
let pageNum = ref(1); //存放当前页
|
||||
const itemData = ref([]); //数据
|
||||
const itemDataRecent = reactive([]); //近期数据
|
||||
const emptyData = ref("没有找到相关内容");
|
||||
let keyword = ref(""); //当前的搜索对象
|
||||
let isInput = ref(false); //是否触发了输入框
|
||||
let page = reactive({
|
||||
latitude:
|
||||
users.loacation.latitude !== undefined
|
||||
? users.loacation.latitude
|
||||
: 40.062595,
|
||||
longitude:
|
||||
users.loacation.longitude !== undefined
|
||||
? users.loacation.longitude
|
||||
: 116.372809,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
// 计算数据
|
||||
const listDataes = computed(() => {
|
||||
let testList = [];
|
||||
if (showDisplay.value === false) {
|
||||
if (itemDataRecent.length > 10) {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
testList.push(itemDataRecent[i]);
|
||||
}
|
||||
} else {
|
||||
testList = itemDataRecent;
|
||||
}
|
||||
return testList;
|
||||
} else {
|
||||
return itemDataRecent;
|
||||
}
|
||||
});
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
isInput.value = true;
|
||||
if (pageNum.value >= Number(pages.value)) {
|
||||
loadMore.value.status = "noMore";
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = "loading";
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
getList();
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
// 离开此页面
|
||||
onUnmounted(() => {
|
||||
itemData.value = [];
|
||||
isInput.value = false;
|
||||
});
|
||||
// ------生命周期------
|
||||
onMounted(() => {
|
||||
init();
|
||||
if (users.searchText !== "") {
|
||||
keyword.value = users.searchText;
|
||||
search.value.searchVal = users.searchText;
|
||||
getList();
|
||||
}
|
||||
});
|
||||
// 获取初始值
|
||||
const init = () => {
|
||||
getRecent(); //近期搜索数据
|
||||
};
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
page = {
|
||||
...page,
|
||||
page: pageNum.value,
|
||||
keyword: keyword.value,
|
||||
};
|
||||
// 后端接口调用
|
||||
await getSearch(page).then((res) => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (!isInput.value) {
|
||||
itemData.value = res.data.items;
|
||||
} else {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
}
|
||||
|
||||
pages.value = res.data.pages;
|
||||
if (Number(res.data.pages) === pageNum.value) {
|
||||
loadMore.value.status = "noMore";
|
||||
}
|
||||
} else {
|
||||
itemData.value = [];
|
||||
}
|
||||
// 有搜索数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemData.value.length > 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 显示最近查找
|
||||
const getRecent = async () => {
|
||||
await getRecentSearch().then((res) => {
|
||||
if (res.code === 200) {
|
||||
itemDataRecent.value = res.data;
|
||||
// 没数据的时候隐藏最近查询标题和清除按钮
|
||||
if (itemDataRecent.value.length === 0) {
|
||||
isClear.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索框搜索
|
||||
const handleSearch = (val) => {
|
||||
if (val.value.trim().length > 0) {
|
||||
isInput.value = false;
|
||||
keyword = val;
|
||||
getList();
|
||||
}
|
||||
};
|
||||
// input焦点
|
||||
const handleBlur = () => {
|
||||
isInput.value = true;
|
||||
};
|
||||
// 清除最近查找
|
||||
const handleClear = () => {
|
||||
popups.value.dialogOpen();
|
||||
};
|
||||
// 点击关闭按钮之后页面为显示最近查找页
|
||||
const clearSearchData = () => {
|
||||
itemData.value = []; //清空搜索列表
|
||||
// 设置搜索的内容,从详情页返回搜索页的时候显示默认搜索的内容
|
||||
isClear.value = false;
|
||||
store.commit("user/setSearchText", "");
|
||||
getRecent();
|
||||
};
|
||||
// 清空
|
||||
const clearData = async (val) => {
|
||||
isClear.value = val;
|
||||
await clearRecentSearch().then(() => {
|
||||
if (res.code === 200) {
|
||||
uni.showToast({
|
||||
title: "清除成功",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 标记为最近查找
|
||||
const setRecent = async (id) => {
|
||||
await setMarkRecent(id);
|
||||
itemData.value = []; //清空搜索列表
|
||||
};
|
||||
// 取件详情页
|
||||
const handleDetails = (e, item) => {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
// 把任务id用vuex的方法存储,方便其他页面调用
|
||||
store.commit("user/setTaskId", item.id);
|
||||
// // 由于取件详情地址和派件详情地址样式一致,所以用类型 1取件,2派件区分开
|
||||
// store.commit('user/setTaskType', 1);
|
||||
// 设置是否由搜索页进的详情页,方便详情页返回
|
||||
store.commit("user/setIsSearch", true);
|
||||
// 设置搜索的内容,从详情页返回搜索页的时候显示默认搜索的内容
|
||||
store.commit("user/setSearchText", search.value.searchVal);
|
||||
|
||||
// 如果有运单号标记为最近查询记录
|
||||
if (item.transportOrderId) {
|
||||
setRecent(item.transportOrderId);
|
||||
}
|
||||
// 取件
|
||||
if (item.taskType === 1) {
|
||||
// 待取件
|
||||
if (item.status === 1) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/index",
|
||||
});
|
||||
return false;
|
||||
} else if (item.status === 2) {
|
||||
// 如果是已取件
|
||||
// 未付款的状态进入二维码付款页面
|
||||
if (item.paymentStatus === 1 && item.paymentMethod === 1) {
|
||||
store.commit("user/setDetailType", 2);
|
||||
store.commit("user/setTaskStatus", 3);
|
||||
store.commit("user/setPayData", {});
|
||||
uni.redirectTo({
|
||||
url: "/pages/pay/scanPay",
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
// 已取件
|
||||
store.commit("user/setTaskStatus", 2);
|
||||
}
|
||||
} else {
|
||||
// 取消的订单
|
||||
store.commit("user/setTaskStatus", 3);
|
||||
}
|
||||
// 如果是已付款或者是到付,取消的订单,进入运单详情页
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
} else {
|
||||
// 派件
|
||||
// 待派件
|
||||
if (item.status === 1) {
|
||||
store.commit("user/setTaskStatus", 4);
|
||||
} else if (item.status === 2) {
|
||||
// 如果是已取件
|
||||
// 未付款的状态进入二维码付款页面
|
||||
if (item.paymentStatus === 1 && item.paymentMethod === 2) {
|
||||
store.commit("user/setPayData", {});
|
||||
uni.redirectTo({
|
||||
url: "/pages/pay/scanPay",
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
store.commit("user/setTaskStatus", 5);
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
}
|
||||
}
|
||||
// 如果是去派件\已付款或者是寄付,进入运单详情页
|
||||
uni.redirectTo({
|
||||
url: "/pages/details/waybill",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 根据最近查找的运单id搜索
|
||||
const handleTransportOrderId = (val) => {
|
||||
// 给搜索对象赋值
|
||||
keyword.value = val;
|
||||
// 把值赋给子组件的搜索框
|
||||
search.value.searchVal = val;
|
||||
getList();
|
||||
};
|
||||
// 回首页
|
||||
const goBack = () => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/index/index",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style src="./../../styles/expressage.scss" lang="scss" scoped></style>
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
<style lang="scss">
|
||||
body {
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
42
project-wl-kuaidiyuan-uniapp-vue3/pages/start/index.scss
Normal file
42
project-wl-kuaidiyuan-uniapp-vue3/pages/start/index.scss
Normal file
@@ -0,0 +1,42 @@
|
||||
.starPage{
|
||||
.page{
|
||||
background: #fff url(@/static/goink.jpg) no-repeat 50% 50%;
|
||||
background-size:contain;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.tit{
|
||||
width: 38rpx;
|
||||
line-height: 40rpx;
|
||||
font-size: 36rpx;
|
||||
margin: 0 auto;
|
||||
letter-spacing: 0.42rpx;
|
||||
text-align: center;
|
||||
text{
|
||||
display: block;
|
||||
padding:0 0 10rpx 0;
|
||||
}
|
||||
}
|
||||
.map{
|
||||
background: url(@/static/star.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 320rpx;
|
||||
height: 232rpx;
|
||||
margin-top: 80rpx;
|
||||
margin-bottom: 142rpx;
|
||||
}
|
||||
.logo{
|
||||
background: url(@/static/logo.png) no-repeat;
|
||||
background-size: contain;
|
||||
width: 712rpx;
|
||||
height: 184rpx;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
position: absolute;
|
||||
bottom: 5%;
|
||||
|
||||
}
|
||||
}
|
||||
26
project-wl-kuaidiyuan-uniapp-vue3/pages/start/index.vue
Normal file
26
project-wl-kuaidiyuan-uniapp-vue3/pages/start/index.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<!-- 引导页 -->
|
||||
<template>
|
||||
<view class="starPage">
|
||||
<view class="page"> </view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted } from "vue";
|
||||
export default {
|
||||
name: "StarPage",
|
||||
setup: (props) => {
|
||||
onMounted(() => {
|
||||
const times = setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/user",
|
||||
});
|
||||
clearTimeout(times);
|
||||
}, 3000);
|
||||
});
|
||||
return {};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="./index.scss" lang="scss" scoped></style>
|
||||
201
project-wl-kuaidiyuan-uniapp-vue3/pages/turnorder/index.vue
Normal file
201
project-wl-kuaidiyuan-uniapp-vue3/pages/turnorder/index.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<!-- 转单页 -->
|
||||
<template>
|
||||
<!-- 搜索nav -->
|
||||
<view class="navBox">
|
||||
<view class="search">
|
||||
<!-- 头部自定义导航 -->
|
||||
<view class="uni-navbar">
|
||||
<view class="input-view">
|
||||
<uni-icons
|
||||
class="input-uni-icon"
|
||||
type="search"
|
||||
size="18"
|
||||
color="#999"
|
||||
/>
|
||||
<input
|
||||
confirm-type="search"
|
||||
class="nav-bar-input"
|
||||
type="text"
|
||||
v-model="searchVal"
|
||||
placeholder="请输入快递员账号查询"
|
||||
@input="handleSearch"
|
||||
/>
|
||||
<!-- 先保留,后期可能要加次功能 -->
|
||||
<!-- <view class="scanIcon" @click="handleQr"></view> -->
|
||||
</view>
|
||||
<view class="concelBox" @click="handleCancel" v-if="isShowCancel"
|
||||
>取消</view
|
||||
>
|
||||
</view>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</view>
|
||||
<!-- end -->
|
||||
<view class="boxTop">
|
||||
<view class="btnBox turnBox" v-if="itemData.length > 0">
|
||||
<scroll-view scroll-y="true">
|
||||
<view
|
||||
class="boxBg"
|
||||
v-for="(item, index) in itemData"
|
||||
:key="index"
|
||||
@click="handleOpen(item.userId)"
|
||||
>
|
||||
<view class="turnItem">
|
||||
<view class="item">
|
||||
<view>{{ item.employeeNumber }}</view>
|
||||
<view>{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<ReachBottom ref="loadMore"></ReachBottom>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view v-else
|
||||
><EmptyPage :emptyData="emptyData" :emptyImage="'emptyImage'"></EmptyPage
|
||||
></view>
|
||||
<!-- 提示窗示例 -->
|
||||
<UniPopup
|
||||
ref="popup"
|
||||
:tipInfo="tipInfo"
|
||||
@handleClick="handleClick"
|
||||
></UniPopup>
|
||||
<!-- end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { onReachBottom } from "@dcloudio/uni-app";
|
||||
import { useStore } from "vuex";
|
||||
// 接口api
|
||||
import { getSameAgency, transferBatch } from "@/pages/api/index.js";
|
||||
// 导入组件
|
||||
// 下拉提示
|
||||
import ReachBottom from "@/components/reach-bottom/index.vue";
|
||||
// 弹层
|
||||
import UniPopup from "@/components/uni-popup/index.vue";
|
||||
//空页面
|
||||
import EmptyPage from "@/components/uni-empty-page/index.vue";
|
||||
// ------定义变量------
|
||||
const store = useStore(); //设置、获取数据
|
||||
const users = store.state.user;
|
||||
const loadMore = ref(); //定义子组件的ref,可以调取子组件的值
|
||||
let popup = ref(); //定义ref
|
||||
let isShowCancel = ref(true);
|
||||
const tipInfo = ref("确定要转单吗?"); //转单提示语
|
||||
let reload = ref(false);
|
||||
let pages = ref(0); //总页数
|
||||
let pageNum = ref(1);
|
||||
const emptyData = ref("暂无排班内快递员");
|
||||
const anotherCourierId = ref(""); //快递员id
|
||||
const searchVal = ref(""); //搜索内容
|
||||
let page = reactive({
|
||||
keyword: "",
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
let itemData = ref([]); //列表数据
|
||||
// 上下拉取
|
||||
onReachBottom(() => {
|
||||
if (pageNum.value >= pages.value) {
|
||||
loadMore.value.status = "noMore";
|
||||
return false;
|
||||
} else {
|
||||
loadMore.value.status = "loading";
|
||||
let times = setTimeout(() => {
|
||||
pageNum.value++;
|
||||
getList();
|
||||
}, 1000); //这里延时一秒在加载方法有个loading效果
|
||||
}
|
||||
});
|
||||
// ------生命周期------
|
||||
// ------定义方法------
|
||||
// 获取数据
|
||||
const getList = async () => {
|
||||
reload.value = true;
|
||||
await getSameAgency(page).then((res) => {
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
reload.value = false;
|
||||
if (res.data.items) {
|
||||
itemData.value = itemData.value.concat(res.data.items);
|
||||
pages.value = res.data.pages;
|
||||
if (Number(pages.value) === pageNum.value) {
|
||||
loadMore.value.status = "noMore";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
itemData.value = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 转单弹层
|
||||
const handleOpen = (id) => {
|
||||
anotherCourierId.value = id;
|
||||
// 打开确认转单弹层
|
||||
popup.value.dialogOpen();
|
||||
};
|
||||
// 确认转单
|
||||
const handleClick = async () => {
|
||||
// 获取已经选择的任务id
|
||||
let ids = [];
|
||||
for (const [key, value] of users.selectTaskData) {
|
||||
ids.push(value);
|
||||
}
|
||||
let params = {
|
||||
anotherCourierId: anotherCourierId.value,
|
||||
idList: ids,
|
||||
};
|
||||
await transferBatch(params).then((res) => {
|
||||
if (res.code === 200) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
return uni.showToast({
|
||||
title: "转单成功!",
|
||||
duration: 1000,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleSearch = () => {
|
||||
page.keyword = searchVal.value;
|
||||
itemData.value = [];
|
||||
getList();
|
||||
};
|
||||
// 取消搜索
|
||||
const handleCancel = () => {
|
||||
searchVal.value = "";
|
||||
store.commit("user/setIsDelivery", false);
|
||||
store.commit("user/setTabIndex", 0);
|
||||
clearData();
|
||||
if (users.isDelivery) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: "/pages/pickup/index",
|
||||
});
|
||||
}
|
||||
};
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
clearData();
|
||||
uni.redirectTo({
|
||||
url: "/pages/delivery/index",
|
||||
});
|
||||
};
|
||||
// 清空数据
|
||||
const clearData = () => {
|
||||
// 存储列表数据
|
||||
store.commit("user/setDeliveryData", []);
|
||||
// 总页数清空
|
||||
store.commit("user/setPages", 0);
|
||||
store.commit("user/setSelectTaskData", new Map());
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="../../styles/expressage.scss" lang="scss" scoped></style>
|
||||
Reference in New Issue
Block a user