Commit f47e6d5d authored by 贺世双's avatar 贺世双

初始化

parents
/node_modules/
/unpackage/dist
.idea
\ No newline at end of file
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
"version": "0.0",
"configurations": [{
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]
}
<script>
import { MINI, ENV_MODEL, TokenPrefix} from './publicConfig/config.js'
const loginBehavior = require('./mixins/loginBehavior.js')
// #ifdef H5
import VConsole from 'vconsole'; //引入H5调试工具
// #endif
export default {
mixins: [loginBehavior],
onLaunch() {
this.judgePlatform(); //判断运行平台,仅初始化时执行
},
globalData: {
projectMini: 'biz-trina5-app', //项目名
loginAction: '', //登录Action
cacheUserLocation: {}, //用户地址位置信息缓存,含经、纬度地址描述等
shipmentInfo: { //运单信息 跳转运单详情时设置
shipmentNo: "", //运单号
shipmentId: "", //运单id
shipmentBizName: "" //运单模式 tm.MovementShipment, tm.SimpleShipment
},
stopsInfo: { //站点信息 站点预约时修改
loadStop: '', //是否装货站点
unloadStop: '', //是否卸货站点
locationName: '', //站点名称
locationAddress: '', //站点地址
locationOrders: '', //订单数
locationQty: '', //件数数
locationWeight: '', //重量
locationVolume: '', //体积
},
allotInfo: {}, // 当前分配信息, 分配司机、车辆时赋值
backPagePath: '', //回退页面路径,含完整参数
serviceProvider: 'AMap' ,//地图服务商,默认为高德地图
MapIns: null , //地图实例, 默认在Index首页初始化, mxins下getUserLocation中赋值
},
methods: {
//判断平台
judgePlatform() {
//项目是否为H5 条件编译,代码块仅判断成功才运行
//#ifdef H5
if (process.env.NODE_ENV === 'development') { //HBuilderX中,点击运行是--开发环境,点击发行是--生产环境
this.globalData.projectMini = MINI.h5Dev
const vConsole = new VConsole(); //H5实例化调试工具,工具git地址:https://github.com/Tencent/vConsole
} else { //生产环境区分,默认生产PROD
switch(ENV_MODEL.model){
case 'UAT':
this.globalData.projectMini = MINI.h5Uat
break;
default:
this.globalData.projectMini = MINI.h5Prod
}
}
this.isRunningWxBrowser()
//#endif
//项目是否为小程序 MP代表所有小程序 MP-WEIXIN:微信小程序
//#ifdef MP
this.globalData.projectMini = MINI.wxApp
this.getWxToken()
//#endif
},
//判断是否运行于微信环境
isRunningWxBrowser() {
if (this.isWxBrowser()) { //判断是否运行在微信浏览器
const { code, time } = this.getH5Code()
if (code) {
this.login(code)
}
} else {
this.globalData.projectMini = MINI.web
this.login('')
}
},
//判断是否为微信浏览器
isWxBrowser(){
let ua = window.navigator.userAgent.toLowerCase() //判断浏览器类型, 包含浏览器类型、版本、操作系统类型、浏览器引擎类型等信息
return ua.match(/MicroMessenger/i) == 'micromessenger'
},
}
}
</script>
<style lang="scss">
@import "uview-ui/index.scss";
@import "static/iconfont/iconfont-weapp-icon.css";
/*每个页面公共css */
// 设置整个项目的背景色
page,
view {
margin: 0;
padding: 0;
font-family: PingFangSC-Regular, PingFang SC !important; //苹方简体
}
page,
view,
::after,
::before {
box-sizing: border-box
}
/*flex布局容器*/
.flex {
display: flex;
}
.flex_col {
display: flex;
flex-direction: column;
}
.flex_center {
display: flex;
align-items: center;
}
.flex_sb {
display: flex;
justify-content: space-between;
}
.flex_wrap {
flex-wrap: wrap;
}
.flex_end {
justify-content: flex-end;
}
.flex_cen {
display: flex;
justify-content: center;
}
/* 写一个CSS用于隐藏页面 */
.display_none {
display: none;
}
/* 字体加粗 */
.font_bolder {
font-weight: bolder;
}
/* 单行字体溢出省略 */
.overflowOmitRow {
width: 100%;
display: -webkit-box;
word-break: break-all;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
/* 多行字体溢出省略 */
.overflowOmitRows {
width: 100%;
display: -webkit-box;
word-break: break-all;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.content_box {
color: #434343;
background: #FAFAFA;
min-height: 100vh;
font-size: 32rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
/* 统一样式类 */
.box_shadow_card {
padding: 20rpx;
border-radius: 24rpx;
background-color: #FFFFFF;
box-shadow: 1px 3px 12px 0px rgba(0, 0, 0, 0.04);
}
.routine_radius_card {
padding: 24rpx;
margin: 0 24rpx 24rpx;
background-color: #FFFFFF;
border-radius: 0 0 16rpx 16rpx;
}
/* 客户单号 */
.consumer_code {
font-size: 28rpx;
font-weight: 400;
color: #8C8C8C;
}
// 通用按钮
.common_btn {
width: 327rpx;
height: 88rpx;
font-size: 32rpx;
font-weight: bolder;
color: #2E75E6;
border-radius: 44rpx;
border: 2rpx solid;
background-image: linear-gradient(136deg, rgba(46, 117, 230, 1), rgba(46, 46, 230, 1)) 2 2;
margin-top: 20rpx;
&::after {
border: none;
}
}
.operation-btn {
width: 100%;
flex-grow: 1;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
margin-bottom: 40rpx;
.submitBtn {
color: #FFFFFF;
background: linear-gradient(136deg, #2E75E6 0%, #2E2EE6 100%);
}
}
/deep/.u-form-item__body__left__content__required{
left: -16rpx !important;
line-height: 150% !important;
font-size: 28rpx !important;
top: 0 !important;
}
</style>
# biz-carrier-uniapp
承运商端
## 项目初始化
1. git clone #####项目地址
2. yarn/yarn start
3. 替换publicConfig目录下config.js 中的项目名、APPid等信息为实际项目信息。H5项目需要同步将manifest.json下H5代理地址替换为BASEURL的请求地址
4. 步骤3中项目名等信息,需要提前在bo-designer中系统配置 → 移动端配置下配置。
## 打包发布
1. HBuilderX工具中点击发布。(点击运行为开发环境,点击发布为生产环境)
2. 选择H5或网站PC将发布为H5项目,打包后文件部署至服务器即可。
3. 选择微信开发者工具则为小程序项目,将代码点击上传即可
## 添加彩色图标
1. 在iconfont官网将所需图标添加至购物车→我的项目中→下载至本地解压缩
2. 安装icon工具包
npm install -g iconfont-tools
yarn add -g iconfont-tools
3. 执行命令iconfont-tools
一路回车,将 iconfont-weapp 文件夹下iconfont-weapp-icon.css 替换static下文件即可。 更新图标只需执行步骤3即可
\ No newline at end of file
import Request from "./request";
import uploadFile from "./uploadFile";
import downloadFile from "./downloadFile";
// 登录接口
// mimi: 项目名:biz-carrier-wxapp LOGIN_ACTION: loginByUserInfo
export function userLogin(loginAction, loginCode, data) {
return Request(
`/api/auth/app-login/{mini}/miniAppDriverLogin?weixin_config_key={mini}&code=${loginCode}`,data
);
}
//登录小程序初始化时,调用auth自动登录
export function authLogin(loginAction, loginCode, data) {
return Request(
`/api/auth/app-login/{mini}/miniAppCarrierAuth?weixin_config_key={mini}&code=${loginCode}`,data
);
}
// 用户中心操作&&初始化JS-SDK action 说明: 退出登录:logout 获取用户信息: getUserInfo 修改密码:changePassword 初始化SDK: querySignature
export function userMobileOperation(action, data) {
if (action === "logout") {
//退出登录
return Request(`/logout`, data, "GET"); // data: {openId, entryName}
} else {
return Request(`/api/entry/{mini}/m-action/${action}`, data);
}
}
//获取地图key
export function getMap() {
return Request(`/api/query/*/action/getMap`);
}
//获取地图颜色
export function getMapColor(data) {
return Request(`/api/query/biz.md.Truck/action/service-getMapColor`, data);
}
// 上传图片
export function uploadImg(data, fileType = "image") {
return uploadFile("/api/doc/upload", data, fileType);
}
// 下载图片
export function downloadImg(data) {
return downloadFile("/api/doc/download", data);
}
//查询运单列表
export function findShipmentOrders(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.Shipment.tm_shipment_m_carrier.paging`,
data
);
}
//查询运单详情
export function findShipmentDetail(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.Shipment.tm_shipment_m_carrier_page.get`,
data
);
}
//查询运单途径站点
export function findShipmentStops(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.ShipmentStop.tm_shipmentstop_m_carrier.paging`,
data
);
}
// 查询货量明细
// OM模式
export function OMOrderDetail(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.OrderMovementLine.tm_ordermovementline_m_search.paging`,
data
);
}
// OR模式
export function OROrderDetail(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.OrderLine.tm_orderline_m_search.paging`,
data
);
}
//查询中转地址
export function searchTransferAddress(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.TransferAddress.md_transferaddress_m_search.paging`,
data
);
}
//查询准驾车型
export function queryDrivingType() {
return Request(`/api/query/choice.md.QuasiDrivingType/action/auto_choice`);
}
//查询车辆车型
export function queryTruckType(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.TruckMode.md_truckmode_m_search.paging`,
data
);
}
//查询司机列表
export function searchDriverList(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.Driver.md_driver_m_search.paging`,
data
);
}
//查询车辆列表
export function searchTruckList(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.Truck.md_truck_m_search.paging`,
data
);
}
//查询道口
export function searchDockList(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.Dock.md_dock_m_search.paging`,
data
);
}
//查询道口可预约时间
export function searchDockTime(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.DockTimeTable.md_docktimetable_m_search.paging`,
data
);
}
//中转换、卸货 分配车辆司机
//action说明: 中转换车:transferAndChangeTruck 中转卸货:transferAndUnload 分配车辆司机: assign
export function reportInfo(action, data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.Shipment.operation.${action}`,
data
);
}
//司机、车辆注册
//registerType说明: 司机注册:Driver 车辆注册:Truck
export function serviceRegister(registerType, data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.${registerType}.service.register`,
data
);
}
//司机、车辆详情
//action说明: 司机:Driver 车辆:Truck
export function searchDriverTruckDetail(action, data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.${action}.md_${action.toLocaleLowerCase()}_m_page.get`,
data
);
}
//预约站点
export function loadDockBooking(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.ShipmentStop.operation.loadDockBooking`,
data
);
}
//取消站点预约
export function dockBookingCancel(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.ShipmentStop.operation.dockBookingCancel`,
data
);
}
//调度确认、取消确认 operationType: approve approveCancel
export function shipmentDispatch(operationType, data) {
return Request(`/api/entry/{mini}/m-action/biz.tm.Shipment.operation.${operationType}`, data);
}
//签收 模式:OM:OrderMovement OR: SimpleOrder
export function signFor(shipMode, data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.${shipMode}.operation.receive`,
data
);
}
//订单列表 OM/OR/MASS模式
export function ordermovementOM(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.OrderMovement.tm_ordermovement_m_search.paging`,
data
);
}
export function ordermovementOR(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.SimpleOrder.tm_simpleorder_m_search.paging`,
data
);
}
export function ordermovementMASS(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.MassShipment.tm_massshipment_m_page.get`,
data
);
}
//修改人员详情
export function UpdateDriverInfo(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.Driver.service.updateInfo`,
data
);
}
//修改车辆详情
export function UpdateTruckInfo(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.Truck.service.updateInfo`,
data
);
}
//获取大宗订单
export function getMassOrderList(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.MassOrderCarrier.tm_massordercarrier_m_search.paging`,
data
);
}
//获取大宗订单已分配车辆
export function getMassOrderTruckList(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.MassOrderTruck.tm_massordertruck_m_search.paging`,
data
);
}
//大宗订单车辆分配 assignType: 分配单辆车:assignTruck 分配多量车:assignTrucks
export function massAssignTruck(data, assignType) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.MassOrderCarrier.${assignType}`,
data
);
}
//更新大宗订单配车
export function updateMassAssignTruck(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.MassOrderTruck.service.updateOrderTrucks`,
data
);
}
//更新大宗订单配车
export function GetSignUrl(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.OrderRelease.operation.electronicVisa`,
data
);
}
// 验证码发送
export function SendMessage(data) {
return Request(`/handler/sendMessage`, data);
}
// 订单轨迹
export function findShipmentLbs(data) {
return Request(
`/api/entry/{mini}/m-action/biz.tm.Shipment.service.lbs`,
data
);
}
//获取承运商
export function GetCarrierList(data) {
return Request(
`/api/entry/{mini}/m-action/biz.md.Company.md_company_search.paging`,
data
);
}
// 百度OCR ocrType: 身份证 idCard 驾驶证 drivingLicense 行驶证 vehicleLicense
export function OCRService(ocrType, data) {
return Request(`/api/entry/{mini}/m-action/biz.adapter.AdapterTask.service.${ocrType}`, data)
}
\ No newline at end of file
import { BASEURL, TokenPrefix, APIPrefix } from '../publicConfig/config'
let downloadFile = (api, filePath, header = {}) => {
filePath = filePath.split('=')[1] ? filePath.split('=')[1] : filePath
header = {
'Cookie': 'XSRF-TOKEN=' + uni.getStorageSync(`${TokenPrefix}_XSRFToken`) || '',
"X-XSRF-TOKEN": uni.getStorageSync(`${TokenPrefix}_XSRFToken`) || '',
"Authorization": uni.getStorageSync(`${TokenPrefix}_token`) || '',
}
uni.showLoading({
title: '下载中',
})
return new Promise((reslove, reject) => {
api = APIPrefix + api
uni.downloadFile({
//#ifdef MP
url: BASEURL.url + `${api}/` + filePath, //下载资源的 url
//#endif
//#ifdef H5
url: `${api}/` + filePath, //H5使用代理
//#endif
header,
success: (res) => {
uni.hideLoading()
if (res.statusCode == 401 || res.statusCode == -1) {
let app = getApp()
uni.showToast({
title: '登录已过期',
icon: 'error',
duration: 3000
})
uni.removeStorageSync(`${TokenPrefix}_token`)
uni.removeStorageSync(`${TokenPrefix}_XSRFToken`)
uni.removeStorageSync('cookies')
app.judgePlatform();
}
reslove(res.tempFilePath)
},
fail: (err) => {
uni.hideLoading()
uni.showToast({
title: '下载失败!',
icon: 'error'
})
reject(err)
}
})
})
}
export default downloadFile
import { BASEURL, TokenPrefix, APIPrefix } from '../publicConfig/config'
let serverCode = {
3: '重定向',
4: '请求包含错误或未找到资源',
5: '服务器错误'
}
let Request = (api, data, method = 'POST', header = {}, showLoading = true) => {
header = {
'Content-Type': 'application/json;charset=UTF-8',
'Cookie': 'XSRF-TOKEN=' + uni.getStorageSync(`${TokenPrefix}_XSRFToken`) || '',
"X-XSRF-TOKEN": uni.getStorageSync(`${TokenPrefix}_XSRFToken`) || '',
"Authorization": uni.getStorageSync(`${TokenPrefix}_token`) || '',
...header
}
if(showLoading){
uni.showLoading({
title: '加载中...',
})
}
console.log('请求参数:', data);
return new Promise((reslove, reject) => {
const { projectMini } = getApp().globalData
const newApi = APIPrefix + api.replace(/{mini}/g, projectMini)
uni.request({
//#ifdef MP
url: BASEURL.url + newApi,
//#endif
//#ifdef H5
url: newApi,
//#endif
data,
method,
header,
success: (res) => {
if(showLoading){
uni.hideLoading()
}
if (res.statusCode == '404') {
uni.showToast({
title: '无法找到资源',
icon: 'error',
duration: 3000
})
} else if (res.statusCode === 401 && !newApi.includes('/auth/app-login')) {
let app = getApp()
uni.showToast({
title: '登录已过期',
icon: 'error',
duration: 3000
})
uni.removeStorageSync(`${TokenPrefix}_token`)
uni.removeStorageSync(`${TokenPrefix}_XSRFToken`)
uni.removeStorageSync('cookies')
app.judgePlatform();
} else if (res.statusCode !== 200) {
console.log('响应日志:', res.data);
if (res.data.messageType) {
if(!newApi.includes('/auth/app-login')){ //登录接口自定义处理
uni.showToast({
title: res.data.message,
icon: 'none',
duration: 3000
})
}
reject(res.data)
} else {
uni.showToast({
title: serverCode[res.statusCode.toString()[0]],
icon: 'error',
duration: 3000
})
}
} else {
reslove(res)
}
},
fail: (err) => {
if(showLoading){
uni.hideLoading()
}
uni.showToast({
title: err.info || '请求失败!',
icon: 'error',
duration: 2000
})
reject(err)
}
})
})
}
export default Request
import {BASEURL, TokenPrefix, APIPrefix} from '../publicConfig/config'
import compress from '../utils/compress'
let uploadFile = async (api, filePath, fileType, header = {}) => {
header = {
'Cookie': 'XSRF-TOKEN=' + uni.getStorageSync(`${TokenPrefix}_XSRFToken`) || '',
"X-XSRF-TOKEN": uni.getStorageSync(`${TokenPrefix}_XSRFToken`) || '',
"Authorization": uni.getStorageSync(`${TokenPrefix}_token`) || '',
}
uni.showLoading({
title: '上传中',
})
if(fileType === 'image'){
filePath = await compress(filePath) //图片压缩
}
return new Promise((reslove, reject) => {
api = APIPrefix + api
uni.uploadFile({
//#ifdef MP
url: BASEURL.url + `${api}`, //开发者服务器地址
//#endif
//#ifdef H5
url: api, //H5使用代理
//#endif
filePath,
name: 'file',
header,
success: (res) => {
uni.hideLoading()
if (res.data.reCode == 401 || res.data.reCode == -1) {
let app = getApp()
uni.showToast({
title: '登录已过期',
icon: 'error',
duration: 3000
})
uni.removeStorageSync(`${TokenPrefix}_token`)
uni.removeStorageSync(`${TokenPrefix}_XSRFToken`)
uni.removeStorageSync('cookies')
app.judgePlatform();
}
reslove(res.data)
},
fail: (err) => {
uni.hideLoading()
uni.showToast({
title: '上传失败!',
icon: 'error'
})
console.log(err);
reject(err)
}
})
})
}
export default uploadFile
<template>
<view class="custom_camera" v-if="visible">
<CustomCamera ref="customCamera" :coverImage="coverImage" @onCancel="onCancel" @onConfirm="onConfirm"/>
</view>
</template>
<script>
// #ifdef H5
import CustomCamera from './cameraH5.vue'
// #endif
// #ifdef MP-WEIXIN
import CustomCamera from "./cameraWeChat.vue"
// #endif
// #ifdef APP
import CustomCamera from "./cameraApp.vue"
// #endif
export default {
components:{CustomCamera},
data() {
return {
coverImage: '', //证照遮罩图
}
},
props: {
visible: {
type: Boolean,
default: false
},
cameraType: {
type: String,
default: '' //相机类型 idCardFace idCardBack
}
},
watch: {
visible: {
handler(visible) {
if(visible){
this.$nextTick(() => this.$refs.customCamera.onInitCamera()) //因v-if异步渲染,避免获取组件实例失败
const cardImges = {
idCardFace: 'static/img/camera/idCardFace.png', //身份证正面
idCardBack: 'static/img/camera/idCardBack.png', //身份证国徽面
driveCardFace: 'static/img/camera/driveCardFace.png', //驾驶证正页
driveCardBack: 'static/img/camera/driveCardBack.png', //驾驶证副页
vehicleCardFace: 'static/img/camera/driveCardBack.png', //行驶证正页
vehicleCardBack: 'static/img/camera/driveCardBack.png', //行驶证副页
}
const coverImage = cardImges[this.cameraType]
if(coverImage){
// #ifdef H5
this.coverImage = `../../${coverImage}`
// #endif
// #ifdef MP
let base64Png = uni.getFileSystemManager().readFileSync(cardImges[this.cameraType], 'base64');
this.coverImage = 'data:image/jpg;base64,' + base64Png
// #endif
}
} else {
//退出拍照 清空画布、停止视频流等操作
this.$refs.customCamera.onExitCamera()
}
}
}
},
methods: {
//退出拍照
onCancel() {
this.$emit('uploadCancel')
},
//拍照完成
onConfirm(imgSrc){
this.$emit('uploadFinish', imgSrc)
}
}
}
</script>
<style scoped lang="scss">
.custom_camera {
width: 100vw;
height: 100vh;
background-color: #000000;
position: fixed;
top: 0;
left: 0;
z-index: 9999;
}
</style>
\ No newline at end of file
<template>
<view class="custom_camera_App">
<live-pusher id="livePusher" style="width: 100%; flex-grow: 1;position: relative" :url="url" :mode="mode" :aspect="aspect" :beauty="0" :whiteness="0"
:orientation="orientation" :auto-focus="true" :muted="true" :enable-camera="true" @error="onError">
<!-- 遮罩层 -->
<template v-if="previewImg">
<cover-image class="previewImg" :src="previewImg" />
</template>
<template v-else>
<cover-image class="coverImage" v-if="coverImage" :src="coverImage" />
<cover-view class="camera-menuTop">
<cover-image class="menuBtn" mode="aspectFill" src="/static/img/camera/back.png" @click="onCancel" />
<cover-image class="menuBtn" mode="aspectFill" src="/static/img/camera/track.png" @click="onTrack" />
</cover-view>
</template>
</live-pusher>
<view class="camera-menuBottom">
<view class="previewBtns" v-if="previewImg">
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/cancel.png" @click="onRetry" />
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/confirm.png" @click="onConfirm" />
</view>
<template v-else>
<image class="takeBtn" mode="aspectFill" src="/static/img/camera/shutter.png" @click="onTakePhoto" />
<image class="menuBtn reversalBtn" mode="aspectFill" src="/static/img/camera/reversal.png" @click="onReversePhoto" />
</template>
</view>
</view>
</template>
<script>
// 1.因为uniapp的camera组件只支持微信小程序,所以APP只能采用live-pusher组件来解决这个问题
// 当然live-pusher组件没有camera的性能好,而且必须是nvue文件(这些官方也有介绍[](https://uniapp.dcloud.net.cn/component/live-pusher.html))
export default {
props: {
coverImage: {
type: String,
default: '' //遮罩类型
}
},
data() {
return {
previewImg: '', //预览图
livePusherCtx: null,
//相机参数
url: '', //必填 推流地址,支持RTMP协议。
mode: 'SD', //推流视频模式,可取值:SD(标清), HD(高清), FHD(超清)
aspect: '3:2', //视频宽高比例
orientation: 'vertical', //画面方向 竖直:vertical 水平:horizontal
}
},
methods: {
//相机初始化
onInitCamera(){
this.livePusherCtx = uni.createLivePusherContext('livePusher', this);
setTimeout(() => {
this.startPreview()
}, 1000)
},
startPreview() {
this.livePusherCtx.startPreview({
success: () => {
switch (plus.os.name) {
case 'Android':
break;
case 'iOS':
this.onReversePhoto()
break
}
},
fail: (err) => {
console.log(err)
}
});
},
//退出相机
onExitCamera(){
this.previewImg = ''
this.livePusherCtx = null
},
// 返回
onCancel(){
this.$emit('onCancel')
},
//拍照
onTakePhoto(){
this.livePusherCtx.snapshot({
success: (res) => {
this.previewImg = res.message.tempImagePath
}
})
},
//翻转摄像头
onReversePhoto(){
this.livePusherCtx.switchCamera();
},
//闪光灯
onTrack(){
},
//渲染错误事件
onError(err) {
console.log(err)
},
//提交
onConfirm(){
this.$emit('onConfirm', this.previewImg)
},
//重拍
onRetry(){
this.previewImg = ''
}
}
}
</script>
<style lang="scss" scoped>
.custom_camera_App {
height: 100%;
display: flex;
flex-direction: column;
.previewImg{
width: 100%;
height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6; //层级应高于 Vido、Canvas
}
.coverImage {
width: 65%;
height: 75%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6; //层级应高于 Vido、Canvas
}
.menuBtn{
width: 60rpx;
height: 60rpx;
}
.camera-menuTop{
width: 100%;
padding: 30rpx 60rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
position: absolute;
z-index: 6; //层级应高于 Vido、Canvas
}
.camera-menuBottom{
height: 320rpx;
display: flex;
justify-content: center;
align-items: center;
.previewBtns{
width: 100%;
padding: 0 60rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.takeBtn{
width: 120rpx;
height: 120rpx;
}
.reversalBtn{
position: absolute;
right: 60rpx;
}
}
}
</style>
<template>
<view class="custom_camera_h5">
<!-- 拍摄区域&遮罩层 -->
<view class="mayCameraH5" style="width: 100%; flex-grow: 1;position: relative">
<template v-if="previewImg">
<image class="previewImg" :src="previewImg" />
</template>
<template v-else>
<image class="coverImage" v-if="coverImage" :src="coverImage" />
<view class="camera-menuTop">
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/back.png" @click="onCancel" />
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/track.png" @click="onTrack" />
</view>
</template>
</view>
<!-- 操作按钮 -->
<view class="camera-menuBottom">
<view class="previewBtns" v-if="previewImg">
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/cancel.png" @click="onRetry" />
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/confirm.png" @click="onConfirm" />
</view>
<template v-else>
<image class="takeBtn" mode="aspectFill" src="/static/img/camera/shutter.png" @click="onTakePhoto" />
<image class="menuBtn reversalBtn" mode="aspectFill" src="/static/img/camera/reversal.png" @click="onReversePhoto" />
</template>
</view>
<input v-show="false" ref="fileRef" type="file" @change="get_file" accept="image/*">
</view>
</template>
<script>
export default {
props: {
coverImage: {
type: String,
default: '' //遮罩类型
}
},
data() {
return {
previewImg: '', //预览图
exact: 'environment', // environment 后摄像头 user 前摄像头
constraints: {}, //打开摄像头的默认配置
video: null, //视频播放控件
canvas: null, //图片画布
cameraWidth: 0, //默认拍照宽度
cameraHeight: 0, //默认拍照高度
// 闪光灯
track: null,
trackStatus: false, //闪光灯状态
}
},
methods: {
//初始化方法
onInitCamera() {
const maskDom = document.querySelector('.mayCameraH5') //设置相机宽高
const {width, height} = maskDom.getBoundingClientRect()
this.cameraWidth = width;
this.cameraHeight = height
//创建Video节点,直接书写节点会被uni编译
this.video = document.createElement('video')
this.video.width = this.cameraWidth
this.video.height = this.cameraHeight
this.video.style ='position: absolute;top: 0;left: 0;z-index: 1'
maskDom.append(this.video) //添加入DOM
//创建画布, 用于预览照片
this.canvas = document.createElement('canvas')
this.canvas.id = 'canvas'
this.canvas.width = this.cameraWidth
this.canvas.height = this.cameraHeight
this.canvas.style ='position: absolute;top: 0;left: 0;z-index: 2' //style="perspective:1000;" transform: perspective(1000);
maskDom.append(this.canvas)
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 判断浏览器是否实现MediaDevices中getUserMedia功能,并设置异步回调
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function(constraints) {
//获取当前的getUserMedia(如果存在), 有些浏览器不支持,则设置统一错误信息
let _getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (_getUserMedia) {
return new Promise((resolve, reject) => {
_getUserMedia.call(navigator, constraints, resolve, reject);
});
} else {
return Promise.reject(new Error('浏览器不支持访问用户媒体设备,请升级或更换浏览器'));
}
}
}
this.openScan() //打开摄像
},
openScan() {
let width = this.cameraHeight //使用后置摄像头设置分辨率时,宽高颠倒才能正确显示(手机本身的比例是高大于宽)
let height = this.cameraWidth
let constraints = {}; //默认摄像头配置,宽高用于指定摄像头的分辨率: 1280x720
//手机端默认开启后置摄像头,当运行于浏览器则不能添加facingMode,否则无法找到设备
if (this.isMobile()) {
constraints = {
audio: false,
video: {width, height, facingMode: { exact: this.exact }}
};
} else {
constraints = { audio: false, video: { width, height } };
}
this.constraints = constraints
this.getUserMedia(); //直接进行调起
},
//判断是否为手机,因为还包含有浏览器的用法
isMobile() {
const info = navigator.userAgent; //获取浏览器navigator对象的userAgent属性(浏览器用于HTTP请求的用户代理头的值)
const isPhone = /mobile/i.test(info); //通过正则表达式的test方法判断是否包含“Mobile”字符串
return isPhone; //如果包含Mobile(即手机设备)则返回true
},
//访问用户媒体设备, 优雅降级向下兼容
getUserMedia() {
const constraints = this.constraints
//关闭打开的摄像头
if (this.video.srcObject) {
this.onCloseCamera()
}
if (navigator.mediaDevices.getUserMedia) { //最新的标准API
navigator.mediaDevices.getUserMedia(constraints).then(this.onSuccess).catch(this.onFail);
} else if (navigator.webkitGetUserMedia) { //webkit核心浏览器
navigator.webkitGetUserMedia(constraints).then(this.onSuccess).catch(this.onFail);
} else if (navigator.mozGetUserMedia) { //firfox浏览器
navigator.mozGetUserMedia(constraints).then(this.onSuccess).catch(this.onFail);
} else if (navigator.getUserMedia) { //旧版API
navigator.getUserMedia(constraints).then(this.onSuccess).catch(this.onFail);
}
},
//访问媒体设备成功-回调
onSuccess(mediaStream) {
//保存视频流
this.video.setAttribute('autoplay', '');
this.video.setAttribute('muted', '');
this.video.setAttribute('playsinline', true);
this.video.setAttribute('webkit-playsinline', true)
// 旧的浏览器可能没有 srcObject
if ("srcObject" in this.video) {
this.video.srcObject = mediaStream;
} else {
// 防止在新的浏览器里使用它,因为它已经不再支持了
const CompatibleURL = window.URL || window.webkitURL
this.video.src = CompatibleURL.createObjectURL(mediaStream);
}
//强制播放,防止IOS黑屏, 即使有autoplay属性
this.video.onloadedmetadata = () => this.video.play();
// 添加水印显示
// this.onAddWatermark()
// 闪光灯
this.track = mediaStream.getVideoTracks()[0]
},
//访问媒体设备失败-回调
onFail(error) {
const errMsg = error.message
if (errMsg === 'Permission denied') { //用户拒绝授权,返回上一步
if (uni.getStorageSync('CameraFirstAuth')) {
uni.showToast({
title: '用户已拒绝授权, 重新授权请重新进入公众号',
icon: 'none',
duration: 3000
})
} else {
uni.setStorageSync("CameraFirstAuth", true);
}
this.onCancel()
} else {
uni.showToast({
title: error.name ? `访问用户媒体设备失败${error.name}: ${errMsg}` : JSON.stringify(error),
icon: 'none',
duration: 2000
})
}
},
//进行拍照
onTakePhoto() {
this.video.pause(); //暂停
const ctx2d = this.canvas.getContext('2d'); //获取画布上下文
ctx2d.drawImage(this.video, 0, 0, this.cameraWidth, this.cameraHeight);
// this.onAddWatermark() //添加水印
this.previewImg = this.canvas.toDataURL() || ''//默认为base64,可指定类型如: 'image/png'
},
//反转摄像头
onReversePhoto() {
const exact = this.constraints.video.facingMode?.exact == 'user' ? 'environment' : 'user'
this.exact = exact
this.onResetCamera() //切换摄像头时销毁并重新创建画布,解决镜像翻转问题
},
//保存照片
onConfirm() {
this.$emit('onConfirm', this.previewImg)
},
//重拍照片
onRetry() {
this.previewImg = ''
this.onResetCamera() //切换摄像头时销毁并重新创建画布,解决镜像翻转问题
},
//重置相机
onResetCamera(){
this.onDestroyDom()
this.onInitCamera()
},
//退出拍照
onExitCamera() {
this.onCloseCamera()
this.onDestroyDom()
},
//关闭相机摄像头
onCloseCamera() {
if (this.video?.srcObject) {
this.video.srcObject.getTracks().forEach(track => track.stop())
}
},
//退出时销毁DOM
onDestroyDom() {
const maskDom = document.querySelector('.mayCameraH5')
const oldVideo = document.querySelector('.mayCameraH5 video')
const oldCanvas = document.querySelector('.mayCameraH5 canvas')
if (oldVideo && oldCanvas) {
maskDom.removeChild(oldCanvas)
maskDom.removeChild(oldVideo)
this.video = null
this.canvas = null
}
},
//回退上一页
onCancel() {
this.$emit('onCancel')
},
//闪光灯
onTrack() {
this.trackStatus = !this.trackStatus
this.track.applyConstraints({
advanced: [{
torch: this.trackStatus
}]
})
},
//添加水印
async onAddWatermark() {
const newTime = this.formatTime(new Date())
const {address} = this.locationInfo
const {userInfo} = getApp().globalData
const watermarks = [
{ type: 'text', text: `拍摄人:${userInfo.name}`, x: 18, y: this.cameraHeight - 70 },
{ type: 'text', text: `时间:${newTime}`, x: 18, y: this.cameraHeight - 50 },
{ type: 'text', text: `地址:${address}`, x: 18, y: this.cameraHeight - 30 }
]
const ctx2d = this.canvas.getContext('2d'); //获取画布上下文
for (let item of watermarks) {
switch (item.type) {
case 'img':
// const img = await this.getImg(imgPath)
// ctx2d.drawImage(img, item.x, item.y, item.w, item.h)
break;
case 'text':
const color = item.font_color || "#FFFFFF"
const fontSize = item.font_size || 24
ctx2d.fillStyle = color
ctx2d.font = `${fontSize}rpx normal`
ctx2d.fillText(item.text, item.x, item.y)
break;
}
}
},
formatTime(date){
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const weekDay = date.getDay()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
const week = { 0: '日', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六',}
return `${[year, month, day].map(this.formatNumber).join('-')} ${[hour, minute, second].map(this.formatNumber).join(':')} 星期${week[weekDay]}`
},
formatNumber (n) {
n = n.toString()
return n[1] ? n : `0${n}`
},
//直接选择的方法 change事件
get_file(e) {
const currentFiles = e.target.files
if (currentFiles.length > 0) {
for (const file of currentFiles) {
let url = URL.createObjectURL(file)
}
}
},
}
}
</script>
<style scoped lang="scss">
.custom_camera_h5 {
height: 100%;
display: flex;
flex-direction: column;
.previewImg{
width: 100%;
height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6; //层级应高于 Vido、Canvas
}
.coverImage {
width: 65%;
height: 75%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6; //层级应高于 Vido、Canvas
}
.menuBtn{
width: 60rpx;
height: 60rpx;
}
.camera-menuTop{
width: 100%;
padding: 30rpx 60rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
position: absolute;
z-index: 6; //层级应高于 Vido、Canvas
}
.camera-menuBottom{
height: 320rpx;
display: flex;
justify-content: center;
align-items: center;
.previewBtns{
width: 100%;
padding: 0 60rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.takeBtn{
width: 120rpx;
height: 120rpx;
}
.reversalBtn{
position: absolute;
right: 60rpx;
}
}
}
</style>
\ No newline at end of file
<template>
<view class="custom_camera_WeChat">
<camera style="width: 100%; flex-grow: 1;position: relative" mode="normal" :resolution="resolution" :device-position="device"
:frame-size="frameSize" :flash="flash" @error="onError">
<!-- 遮罩层 -->
<template v-if="previewImg">
<cover-image class="previewImg" :src="previewImg" />
</template>
<template v-else>
<cover-image class="coverImage" v-if="coverImage" :src="coverImage" />
<cover-view class="camera-menuTop">
<cover-image class="menuBtn" mode="aspectFill" src="/static/img/camera/back.png" @click="onCancel" />
<cover-image class="menuBtn" mode="aspectFill" src="/static/img/camera/track.png" @click="onTrack" />
</cover-view>
</template>
</camera>
<view class="camera-menuBottom">
<view class="previewBtns" v-if="previewImg">
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/cancel.png" @click="onRetry" />
<image class="menuBtn" mode="aspectFill" src="/static/img/camera/confirm.png" @click="onConfirm" />
</view>
<template v-else>
<image class="takeBtn" mode="aspectFill" src="/static/img/camera/shutter.png" @click="onTakePhoto" />
<image class="menuBtn reversalBtn" mode="aspectFill" src="/static/img/camera/reversal.png" @click="onReversePhoto" />
</template>
</view>
</view>
</template>
<script>
export default {
props: {
coverImage: {
type: String,
default: '' //遮罩类型
}
},
data() {
return {
previewImg: '', //预览图
cameraContext: null,
//相机参数
device: 'back', //前置或后置摄像头,前置: front 后置: back
flash: 'off', // 闪光灯 自动: auto 打开: on 关闭: off 常亮: torch
resolution: 'high', //分辨率: 有效值为low, medium, high,不支持动态修改
frameSize: 'medium', //指定期望的相机帧数据尺寸,值为small, medium, large
}
},
methods: {
//相机初始化
onInitCamera(){
uni.getSetting({ //判断用户是否授权相机权限
success: (res) => {
if (!res.authSetting['scope.camera']) {
uni.authorize({
scope: 'scope.camera',
success: () => {
this.cameraContext = uni.createCameraContext()
},
fail: () => {
uni.showModal({
title: '提示',
content: '缺失相机权限,前往系统设置开启相机权限!',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: () => {
this.onInitCamera()
}
});
}
}
});
}
});
} else {
this.cameraContext = uni.createCameraContext()
}
}
})
},
//退出相机
onExitCamera(){
this.previewImg = ''
this.cameraContext = null
},
// 返回
onCancel(){
this.$emit('onCancel')
},
//拍照
onTakePhoto(){
this.cameraContext.takePhoto({
quality: 'high', //成像质量,值为high(高质量)、normal(普通质量)、low(低质量),默认normal
selfieMirror: 'true', //是否开启镜像,默认true。仅微信小程序 2.22.0+ 支持
success: (res) => {
this.previewImg = res.tempImagePath
}
})
},
//翻转摄像头
onReversePhoto(){
this.device = this.device === 'back' ? 'front' : 'back'
},
//闪光灯
onTrack(){
this.flash = this.flash === 'off' ? 'torch' : 'off'
},
//用户不允许使用摄像头时触发
onError(err) {
console.log(err)
},
//提交
onConfirm(){
this.$emit('onConfirm', this.previewImg)
},
//重拍
onRetry(){
this.previewImg = ''
}
},
}
</script>
<style lang="scss" scoped>
.custom_camera_WeChat {
height: 100%;
display: flex;
flex-direction: column;
.previewImg{
width: 100%;
height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6; //层级应高于 Vido、Canvas
}
.coverImage {
width: 65%;
height: 75%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6; //层级应高于 Vido、Canvas
}
.menuBtn{
width: 60rpx;
height: 60rpx;
}
.camera-menuTop{
width: 100%;
padding: 30rpx 60rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
position: absolute;
z-index: 6; //层级应高于 Vido、Canvas
}
.camera-menuBottom{
height: 320rpx;
display: flex;
justify-content: center;
align-items: center;
.previewBtns{
width: 100%;
padding: 0 60rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.takeBtn{
width: 120rpx;
height: 120rpx;
}
.reversalBtn{
position: absolute;
right: 60rpx;
}
}
}
</style>
\ No newline at end of file
<template>
<view class="custom-cell-row">
<u-row>
<u-col :span="labelCol" @click.stop>
<view class="custom-cell-label">
<slot name="label"></slot>
<text class="custom-cell-col" v-if="label">{{label}}</text>
</view>
</u-col>
<u-col :span="wrapCol">
<view class="custom-cell-value">
<slot name="value"></slot>
<text class="custom-cell-col" v-if="value">{{value}}</text>
</view>
</u-col>
<slot name="right-icon"></slot>
</u-row>
</view>
</template>
<script>
export default {
name: 'bs-customCell',
props: {
label: {
type: String,
default: "" //默认值为空
},
value: {
type: String,
default: "" //默认值为空
},
labelCol: {
type: String,
default: '6'
},
wrapCol: {
type: String,
default: '6'
},
}
}
</script>
<style lang="scss">
.custom-cell-row {
font-size: 28rpx;
margin-top: 24rpx;
color: #434343;
.custom-cell-col {
width: 100%;
}
}
</style>
<template>
<view class="customRowCell">
<u-cell-group>
<u-cell center :url="linkUrl" :link-type="linkType" arrow="false">
<view slot="icon" :class="['t-icon cell-leftIcon', 't-icon-' + leftIcon]" />
<view slot="title" class="customRow-title">
<slot name="title"></slot>
<text :class="{ overflowOmitRows: isOmits}" v-if="title">{{title}}</text>
</view>
<view class="customRow-value" slot="value">
<slot name="value"></slot>
<text v-if="value"> {{value}}</text>
</view>
<view slot="right-icon" class="flex_sb icon-min-width">
<text class="right-separator" v-if="separator" />
<slot name="rightIcon"></slot>
<view slot="icon" :class="['t-icon cell-rightIcon', 't-icon-' + rightIcon]" v-if="rightIcon" />
</view>
</u-cell>
</u-cell-group>
</view>
</template>
<script>
export default {
name: 'bs-customRowCell',
options: { styleIsolation: 'shared' },
props: {
title: { //标题
type: String,
default: ''
},
value: { //右侧内容
type: String,
default: ''
},
leftIcon: { //标题左侧图标
type: String,
default: ""
},
rightIcon: { //右侧图标
type: String,
default: ""
},
linkUrl: { //跳转页面地址
type: String,
default: ""
},
linkType: { //跳转类型
type: String,
default: 'navigateTo'
},
isOmits: { //是否多行省略
type: Boolean,
default: false
},
separator: { //是否显示分隔符
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss">
.customRowCell {
&/deep/.u-cell-group {
.u-line {
border: none !important;
}
.u-cell__body {
padding: 20rpx 0;
border: none !important;
}
}
.cell-leftIcon,
.cell-rightIcon {
width: 44rpx;
height: 45rpx;
}
.right-separator {
border-left: 2rpx solid #E5E5E5;
min-height: 30rpx;
}
.customRow-title {
margin-left: 20rpx;
}
.customRow-value {
color: #333333;
white-space: nowrap;
}
.icon-min-width {
min-width: 75rpx;
}
}
</style>
<template>
<view class="datetimePicker" @touchmove.stop.prevent="moveHandle">
<u-datetime-picker ref="datetimePicker" itemHeight="120" :visibleItemCount="visibleItem" :show="visible"
v-model="timestamp" :mode="dateType" @confirm="onSelsectDate" @cancel="onVisible" />
</view>
</template>
<script>
export default {
name: "bs-datetimePicker",
options: { styleIsolation: 'shared' },
props: {
visible: {
type: Boolean,
default: false
},
dateType: {
type: String,
default: 'date'
}
},
onReady() {
// 微信小程序需要用此写法
this.$refs.datetimePicker.setFormatter(this.formatter)
},
data() {
return {
//时间选择配置
showPopup: false,
timestamp: new Date().getTime(),
dateValue: "", //时间戳转换后 年-月-日
visibleItem: 4,
};
},
methods: {
moveHandle(){
},
//自定义时间格式
formatter(type, value) {
if (type === 'year') {
return `${value}年`;
}
if (type === 'month') {
return `${value}月`;
}
if (type === 'day') {
return `${value}日`;
}
if (type === 'hour') {
return `${value}时`;
}
return `${value}分`;
},
onVisible() {
this.$emit('onVisible')
},
// 时间选择
onSelsectDate(dateInfo) {
const date = this.formatDate(dateInfo.value)
this.dateValue = date
this.timestamp = dateInfo.value
this.$emit('onSelsectDate', { dateValue: date, timestamp: dateInfo.value, })
},
//时间戳转换
formatDate(timestamp) {
const nowDate = new Date(timestamp)
var year = nowDate.getFullYear();
var month = nowDate.getMonth() + 1;
var date = nowDate.getDate();
const hour = nowDate.getHours()
const minute = nowDate.getMinutes()
if (this.dateType === 'date') {
return `${year}-${ month}-${date}`
} else {
return `${year}-${ month}-${date} ${hour}-${ minute}`
}
},
}
}
</script>
<style lang="scss">
.datetimePicker{
z-index: 1000;
/* #ifdef MP */
/deep/.u-popup__content {
height: 40vh !important;
.u-picker__view__column {
.u-picker__view__column__item {
line-height: 88rpx !important;
}
}
}
/* #endif */
}
</style>
<template>
<view class="page-header">
<view class="page-header-orderNo flex_center">
运单号: {{shipmentNo}}
</view>
</view>
</template>
<script>
export default {
name: "bs-pageHeader-orderNo",
props: {
shipmentNo: {
type: String,
default: "" //运单号
},
}
}
</script>
<style lang="scss">
.page-header {
padding: 40rpx 24rpx 0;
background: #2E75E6;
border-radius: 0 0 32rpx 32rpx;
.page-header-orderNo {
color: #2E75E6;
padding: 30rpx 24rpx;
background: linear-gradient(90deg, rgba(46, 117, 230, .1), rgba(46, 117, 230, .1));
background-color: #EDEFFD;
border-radius: 16rpx 16rpx 0 0;
}
}
</style>
<template>
<view class="selectPicker" @touchmove.stop.prevent="moveHandle">
<u-picker ref="uPicker" keyName="label" immediateChange confirmText="确定" :show="visible" :title="PanelTitle" :closeOnClickOverlay="true" :itemHeight="68"
:columns="[pickerEnums]" :singleIndex="singleIndex" :visibleItemCount="visibleNum" @cancel="onCancel" @confirm="onConfirm" @close="onCancel"/>
</view>
</template>
<script>
export default {
name: "bs-selectPicker",
options: { styleIsolation: 'shared' },
data() {
return {
singleIndex: 0 //默认选中项
};
},
props: {
visible: {
type: Boolean,
default: false
},
pickerEnums: { //选择项枚举
type: Array,
default: []
},
PanelTitle: { //面板标题
type: String,
default: ""
},
visibleNum: {
type: Number,
default: 3
}
},
methods: {
moveHandle(){
},
//确定
onConfirm(e) {
const value = e.value[0].value
this.$emit('onConfirm', value)
},
//设置默认值
setDefaultValue(index) {
this.singleIndex = index
},
//取消
onCancel() {
this.$emit('onVisible')
}
}
}
</script>
<style lang="scss">
.selectPicker{
/deep/.u-toolbar{
height: 80rpx !important;
}
/deep/.u-slide-up-enter-active {
height: 240rpx;
}
}
</style>
<template>
<!-- 选择弹窗 -->
<view class="selectPopup" @touchmove.stop.prevent="onTouchMove">
<u-popup :show="visible" round="32" mode="bottom" closeable @close="onCancel" duration="1">
<view class="select-container">
<view class="popTitle"> <text>{{popTitle}}</text> </view>
<scroll-view scroll-y class="select-list">
<u-radio-group v-model="currentChecked" placement="column" iconPlacement="right">
<u-radio :customStyle="{margin: '22rpx 40rpx'}" :size="40" :iconSize="32" :labelSize="32"
labelColor="#262626" v-for="(item, index) in selectEnum" :key="index" :label="item.label"
:name="item.value" @change="onChange">
</u-radio>
</u-radio-group>
</scroll-view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
name: "bs-selectPopup",
options: { styleIsolation: 'shared' },
props: {
visible: { //弹窗显隐
type: Boolean,
default: false
},
selectEnum: { //选择项枚举
type: Array,
default: []
},
popTitle: { //弹窗标题
type: String,
default: ""
}
},
data() {
return {
currentChecked: '', //当前选中类型
};
},
methods: {
setSelect(value) {
this.currentChecked = value
},
onChange(value) {
this.setSelect(value)
setTimeout(() => {
this.onConfirm()
}, 350)
},
onCancel() {
this.$emit('onVisible')
},
//确认选择
onConfirm() {
this.$emit('onConfirm', this.currentChecked)
},
//防止滚动穿透
onTouchMove() {}
}
}
</script>
<style lang="scss">
.selectPopup {
.select-container {
min-width: 70vw;
height: 50vh;
padding: 30rpx;
font-weight: 400;
.popTitle {
color: #8C8C8C;
font-size: 32rpx;
text-align: center;
margin-bottom: 44rpx;
}
.select-list{
height: 460rpx;
}
}
/deep/.uicon-close {
font-size: 40rpx !important;
width: 24rpx;
height: 24rpx;
margin-right: 20rpx;
}
}
</style>
<template>
<view class="uploade-file">
<view class="uploade-title" v-if="uploadTitle">
<text style="color: #EB2F48;position: absolute;left: 18rpx;" v-if="required">*</text>
<text>{{uploadTitle}}{{fileList.length}}/{{maxCount}}</text>
</view>
<view class="fileList flex flex_wrap">
<view class="previewImages" v-for="(item,index) in fileDetailList" :key="index">
<template v-if="item.type === 'image'">
<image mode="aspectFill" :src="item.url" :data-index="index" @click="previewImage" class="previewImg" />
</template>
<template v-if="item.type === 'video'">
<video class="previewImg" :src="item.url" :page-gesture="true" :show-mute-btn="true" :enable-play-gesture="true"/>
</template>
<u-icon v-if="isShowDelete" name="close-circle-fill" class="clearIcon" size="30" @click="deleteFile" :index='index' />
</view>
<template v-if="isIos || cameraType">
<view class="uploadeBtn flex_col" @click="onUpLoad">
<view class="t-icon t-icon-picture" />
<text style="margin-top:10rpx">{{btnTitle}}</text>
<text class="font_bolder orderTotal" v-if="!uploadTitle">{{fileList.length}}/{{maxCount}}</text>
</view>
</template>
<template v-else>
<u-upload :fileList="fileList" :maxCount="maxCount" :accept="uploadAccept" :maxDuration="maxDuration"
:sizeType="['compressed']" multiple @afterRead="uploadAfterRead" :previewImage="false">
<!-- 自定义上传按钮 -->
<view class="uploadeBtn flex_col" v-if="isShowBtn">
<view class="t-icon t-icon-picture" />
<text style="margin-top:10rpx">{{btnTitle}}</text>
<text class="font_bolder orderTotal" v-if="!uploadTitle">{{fileList.length}}/{{maxCount}}</text>
</view>
<view v-else style=" height: 140rpx"></view>
</u-upload>
</template>
</view>
<!-- 自定义相机 -->
<bs-customCamera :visible="visible" :cameraType="cameraType" @uploadFinish="customCameraFinish" @uploadCancel="visible=false"/>
</view>
</template>
<script>
const uploadBehavior = require('../../../mixins/uploadBehavior')
export default {
name: "bs-uploader",
mixins: [uploadBehavior],
options: { styleIsolation: 'shared' },
props: {
uploadTitle: {
type: String,
default: ""
},
uploadAccept: {
type: String, //接受的文件类型: image | video | file | all | media; file只支持H5(all、media仅小程序支持)
default: "image"
},
maxDuration: {
type: [String, Number], //当accept为video时生效,拍摄视频最长拍摄时间,单位秒
default: 60
},
maxCount: {
type: [String, Number], //最大上传数量
default: 6
},
btnTitle: { //按钮名字
type: String,
default: "上传图片"
},
isShowBtn: {
type: Boolean,
default: true //是否显示上传按钮
},
required: {
type: Boolean,
default: false //图片是否必传
},
isShowDelete: {
type: Boolean,
default: true //是否显示删除按钮
},
cameraType: {
type: String,
default: '' //自定义拍照类型 如:身份证、驾驶证等
},
},
data() {
return {
}
}
}
</script>
<style lang="scss">
.uploade-file {
.uploade-title {
font-size: 28rpx;
color: #8C8C8C;
}
.fileList {
width: 100%;
.previewImages {
position: relative;
overflow: hidden;
.previewImg {
width: 180rpx;
height: 140rpx;
margin: 24rpx 24rpx 0 0;
}
/deep/.uicon-close-circle-fill {
width: 30rpx;
height: 30rpx;
border-radius: 50%;
background-color: #fff;
color: #D81E06 !important;
position: absolute;
top: 4rpx;
right: 4rpx;
}
}
.uploadeBtn {
position: relative;
color: #BFBFBF;
width: 180rpx;
height: 140rpx;
margin-top: 24rpx;
border: 2rpx dashed #D9D9D9;
background-color: #FAFAFA;
justify-content: center;
align-items: center;
font-size: 24rpx;
.t-icon-picture{
width: 50rpx;
height: 50rpx;
}
.orderTotal {
color: #333333;
position: absolute;
right: -100rpx;
bottom: 0;
z-index: 999;
}
}
}
}
</style>
<template>
<view class="user-agreement flex_center flex_cen">
<u-checkbox-group>
<u-checkbox name="userAuth" shape="circle" size="44" iconSize='44' @change="onChange" />
</u-checkbox-group>
<text>请您详细阅读并授权</text>
<text class="special-text" @click="onVisible(true)">运匠用户协议</text>
<text></text>
<text class="special-text" @click="onVisible(true)">隐私政策</text>
<!-- 协议详情 -->
<view @touchmove.stop.prevent="onTouchMove">
<u-popup :show="visible" mode="right" duration="300" :overlay="false">
<view class="agreement-contentBox" style="width: 100%;">
<view class="agreement-title flex_center">
<u-icon name="arrow-left" size="48" style="margin-right: 25rpx;" @click="onVisible(false)" />
<view class="flex_cen" style="flex-grow: 1;font-size: 38rpx; color: #2c3e50;">用户隐私协议</view>
</view>
<scroll-view scroll-y class="agreement-container">
<view class="detail-title">一、位置及第三方授权</view>
<view class="detail-content">
您明确知悉并同意,您授权我平台通过中交兴路及关联方、第三方机构对您在平台认证的车辆进行当前位置、轨迹跟踪等定位信息查询并授权我平台及其关联方予以使用。授权时间为长期有效。
</view>
<view class="detail-title">二、其它</view>
<view class="detail-content">本应用仅公司内部用户和POC演示使用</view>
</scroll-view>
</view>
</u-popup>
</view>
</view>
</template>
<script>
export default {
name: 'bs-userPrivacy',
data() {
return {
userAuth: false, //用户是否授权
visible: false,
}
},
methods: {
onTouchMove() {
//防止滚动穿透
},
onVisible(value) {
this.visible = value
},
onChange(value) {
this.userAuth = value
this.$emit('onAuthChange', value)
}
}
}
</script>
<style lang="scss">
.user-agreement {
font-size: 26rpx;
font-weight: 400;
color: #8C8C8C;
line-height: 37rpx;
letter-spacing: 2rpx;
margin: 40rpx 0 95rpx;
.special-text {
font-size: 28rpx;
font-weight: bolder;
color: #2E75E6;
margin: 0 4rpx
}
.agreement-title {
padding: 50rpx 25rpx;
}
.agreement-container {
padding: 0 12rpx;
height: calc(100vh - 148rpx);
.detail-title {
color: #2c3e50;
font-weight: 400;
padding: 10rpx 14rpx;
}
.detail-content {
text-indent: 50rpx; //首行缩进
letter-spacing: 4rpx; //字符间距
}
}
}
</style>
\ No newline at end of file
<template>
<view class="orderCard">
<bs-customCell :label="propData.orderNo" labelCol="9.4" wrapCol="2">
<text slot="value" @click="navToOrderDetail">查看详情</text>
<view slot="right-icon" class="t-icon t-icon-rightArrow" @click="navToOrderDetail" />
</bs-customCell>
<!-- 起始目的地 -->
<u-line color="#E5E5E5" margin="0" />
<view class="orderCard-container">
<view class="stations">
<view class="start-station flex">
<view class="start-icon flex_center"></view>{{propData['originalAddress.name']}}
</view>
<view class="end-station flex">
<view class="end-icon flex_center"></view>{{propData['destinationAddress.name']}}
</view>
</view>
<bs-customCell label="货量 :" labelCol="2" wrapCol="10"
:value="`${propData.qty}件 / ${propData.weight}千克 / ${propData.volume}方`" />
</view>
</view>
</template>
<script>
export default {
name: "orderCard",
options: { styleIsolation: 'shared' },
props: {
propData: {
type: Object,
default: {}
},
},
data() {
return {
};
},
methods: {
navToOrderDetail() {
wx.navigateTo({
url: `/subpkg/orderDetail/orderDetail?data=${JSON.stringify(this.propData)}`,
})
},
}
}
</script>
<style lang="scss">
.orderCard {
margin-bottom: 24rpx;
background-color: #FFFFFF;
.start-station,
.end-station {
margin: 20rpx 0;
font-size: 30rpx;
font-weight: bolder;
.start-icon,
.end-icon {
width: 40rpx;
height: 40rpx;
font-size: 24rpx;
padding: 8rpx;
border-radius: 50%;
color: #FFFFFF;
background-color: #2E75E6;
margin-right: 20rpx;
}
.end-icon {
background-color: #F7A64A;
}
}
.custom-cell-row {
color: #8C8C8C;
margin: 0;
padding: 28rpx 30rpx 24rpx 32rpx;
}
.orderCard-container {
padding: 8rpx 32rpx;
.custom-cell-row {
color: #434343;
padding: 0;
margin: 49rpx 0 32rpx;
}
}
}
</style>
<template>
<view class="shipmentItem box_shadow_card">
<view class="shipment-header flex_sb" style="padding: 28rpx 24rpx 0;">
<view class="consumer_code flex_center">
<text selectable> 订单号:{{propData['massOrder.orderNo'] || ''}}</text>
</view>
<view class="consumer_code flex_center">
<text selectable>
剩余货量:{{propData['massOrder.splitMode'] === 'Weight'? propData.weight : propData.qty || '0'}}{{['massOrder.splitMode'] === 'Weight'? "kg": '件'}}</text>
</view>
</view>
<u-line color="#E5E5E5" margin="20rpx 0" />
<view style="padding: 0 24rpx 32rpx;">
<view class="stations">
<view class="start-station flex_center">
<view class="t-icon-start-sddress t-icon" style="margin-right: 8rpx;"></view>
{{propData['massOrder.originalAddress.name'] || ''}}
</view>
<view class="end-station flex_center">
<view class="t-icon-end-sddress t-icon" style="margin-right: 8rpx;"></view>
{{propData['massOrder.destinationAddress.name'] || ''}}
</view>
</view>
<bs-customCell label="接单日期 :" :value="orderDate" labelCol="3" wrapCol="6" />
</view>
<view class="flex_cen flex_center orderItemButtonGroup">
<button class="flex_cen flex_center" @click="onAllotCar('unMulti')">分配车辆</button>
<button class="flex_cen flex_center" @click="onAllotCar('multi')">分配多辆车</button>
<button class="flex_cen flex_center" style="margin-top: 24rpx;" @click="onAllotCar('record')">分配记录</button>
</view>
</view>
</template>
<script>
import { formatGMT } from '../../utils/util'
export default {
name: 'shipmentItem',
options: { styleIsolation: 'shared' },
props: {
propData: {
type: Object,
default: {}
},
},
methods: {
onAllotCar(allotType) {
const orderNo = this.propData['massOrder.orderNo']
const orderId = this.propData['id']
uni.navigateTo({
url: `/subpkg/allotCars/allotCars?orderId=${orderId}&orderNo=${orderNo}&allotType=${allotType}`,
})
},
},
computed: {
orderDate() {
return formatGMT(this.propData['massOrder.orderDate'], 'D') || ''
}
}
}
</script>
<style lang="scss">
.shipmentItem {
position: relative;
margin: 24rpx 24rpx 0;
padding: 0;
padding-bottom: 32rpx;
&/deep/.custom-cell-row {
margin-top: 20rpx;
}
.consumer_code {
line-height: 40rpx;
text-shadow: 1rpx 3rpx 12rpx rgba(0, 0, 0, 0.04);
}
.shipment-state {
font-size: 24rpx;
color: #F7A64A;
line-height: 33rpx;
padding: 6rpx 24rpx;
border-radius: 8rpx;
background: rgba(247, 166, 74, .1);
text-shadow: 1rpx 3rpx 12rpx rgba(0, 0, 0, 0.04);
}
.shipmenting {
color: #66CCCC;
background: rgba(61, 204, 185, .1);
}
.start-station,
.end-station {
margin: 20rpx 0;
font-size: 30rpx;
font-weight: bolder;
.start-icon,
.end-icon {
width: 40rpx;
height: 40rpx;
font-size: 24rpx;
padding: 8rpx;
border-radius: 50%;
color: #FFFFFF;
background-color: #2E75E6;
margin-right: 20rpx;
}
.end-icon {
background-color: #F7A64A;
}
}
.orderItemButtonGroup {
justify-content: space-between;
padding: 0 24rpx;
flex-wrap: wrap;
button {
font-size: 32rpx;
font-weight: 500;
color: #FFFFFF;
width: 315rpx;
height: 80rpx;
margin: 0;
border-radius: 44rpx;
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
box-shadow: 1rpx 3rpx 12rpx 0rpx rgba(0, 0, 0, 0.04);
}
}
}
</style>
\ No newline at end of file
<template>
<view class="orderTruckCard">
<view class="flex_center flex_sb">
<view class="orderTruckCardTruckNo">
<template v-if="isNewAllot">
{{(propData['name'] || '') + '&nbsp;&nbsp;&nbsp;'+(propData['facilityMode.name'] || '')}}
</template>
<template v-else>
{{(propData['truck.name'] || '') + '&nbsp;&nbsp;&nbsp;'+(propData['truck.specification'] || '')}}
</template>
</view>
<image style="width: 40rpx;height: 40rpx;" src="../../static/img/icons/deleteIcon.png" @click="onDeleteTruck(propData.id)"/>
</view>
<u-line customStyle="position:absolute;left:0;"></u-line>
<view class="flex_center flex_sb">
<view class="orderTruckCardContenxt flex">
<view>{{isNewAllot ? propData['driver1.name'] || '' : propData['driver.name'] || ''}}</view>
<view style="margin-left: 80rpx">
{{isNewAllot ? propData['driver1.tel'] || '' : propData['driver.tel'] || ''}}
</view>
</view>
<!-- <u-icon name="arrow-right" v-if="isNewAllot"/> -->
</view>
<u-line></u-line>
<view class="flex_center flex_sb">
<view class="orderTruckCardContenxt"> 最小趟次 </view>
<u-number-box v-model="minFrequency" integer>
<view class="minus" slot="minus"> - </view>
<view slot="input" class="flex_cen flex_center"
style="width: 100rpx; height:56rpx; text-align: center;">
<input v-model="minFrequency" type='number'>
</view>
<view class="plus" slot="plus"> + </view>
</u-number-box>
</view>
<u-line></u-line>
<view class="flex_center flex_sb">
<view class="orderTruckCardContenxt">最大趟次</view>
<u-number-box v-model="maxFrequency" integer>
<view class="minus" slot="minus"> - </view>
<view slot="input" class="flex_cen flex_center"
style="width: 100rpx; height:56rpx; text-align: center;">
<input v-model="maxFrequency" type='number'>
</view>
<view class="plus" slot="plus"> + </view>
</u-number-box>
</view>
<u-line></u-line>
<view class="flex_center flex_sb">
<view class="orderTruckCardContenxt" style="margin-right: 32rpx;">分配量</view>
<u-input type='number' border="none" v-model="alloutQty" placeholder="请填写分配量"/>
</view>
</view>
</template>
<script>
export default {
name: "orderTruckCard",
props: {
propData: {
type: Object,
default: {}
},
isNewAllot: {
type: Boolean,
default: false
}
},
data() {
return {
minFrequency: this.propData.minShipments || 1, //最小趟次
maxFrequency: this.propData.maxShipments || 1, //最大趟次
alloutQty: this.propData.splitMode === 'Weight' ? this.propData.loadWeight : this.propData.loadQty || 0, //分配量
};
},
methods: {
//删除订单已分配车型
onDeleteTruck(truckId) {
uni.$emit('onRemoveMassAssignTruck', truckId)
}
}
}
</script>
<style lang="scss">
.orderTruckCard {
padding: 0 24rpx;
background-color: #FFFFFF;
border-radius: 16rpx;
margin-bottom: 24rpx;
position: relative;
.orderTruckCardTruckNo {
height: 114rpx;
color: #2E75E6;
line-height: 114rpx;
font-size: 32rpx;
font-weight: bolder;
}
.orderTruckCardContenxt {
height: 120rpx;
color: #434343;
line-height: 120rpx;
font-size: 28rpx;
}
.minus {
width: 56rpx;
height: 56rpx;
border: 1rpx solid #BFBFBF;
border-radius: 8rpx;
line-height: 48rpx;
text-align: center;
color: #BFBFBF;
font-weight: bolder;
}
.plus {
width: 56rpx;
height: 56rpx;
border: 1rpx solid #2E75E6;
background-color: #2E75E6;
border-radius: 8rpx;
line-height: 48rpx;
text-align: center;
color: #FFFFFF;
font-weight: bolder;
}
}
</style>
\ No newline at end of file
<template>
<scroll-view class="virtual-list" :style="{ height: `${height}px` }" @scroll="onScroll" :scroll-y="true">
<div class="virtual-list-placeholder" :style="{ height: `${placeholderHeight}px` }"></div>
<div class="virtual-list-viewport" :style="{ transform: `translate3d(0, ${viewportOffset}px, 0)` }">
<slot :items="visibleItems"></slot>
</div>
</scroll-view>
</template>
<script>
export default {
name: 'VirtualList',
props: {
height: {
type: Number,
required: true,
},
itemHeight: {
type: Number,
required: true,
},
items: {
type: Array,
required: true,
},
},
data() {
return {
scrollTop: 0,
viewportOffset: 0,
placeholderHeight: 0,
visibleRange: [0, 0],
visibleItems: [],
};
},
computed: {
viewportHeight() {
return this.height;
},
contentHeight() {
return this.items.length * this.itemHeight;
},
overscanCount() {
return Math.ceil(this.viewportHeight / this.itemHeight) + 1;
},
},
watch: {
items() {
this.updateViewport();
},
scrollTop(newVal) {
this.updateViewport();
this.viewportOffset = newVal;
},
},
mounted() {
this.updateViewport();
},
methods: {
onScroll(e) {
this.scrollTop = e.detail.scrollTop;
},
updateViewport() {
const { scrollTop, overscanCount } = this;
const visibleCount = Math.ceil(this.viewportHeight / this.itemHeight);
const contentCount = this.items.length;
const visibleTop = Math.max(Math.floor(scrollTop / this.itemHeight) - overscanCount, 0);
const visibleBottom = Math.min(visibleTop + visibleCount + overscanCount * 2, contentCount);
this.visibleRange = [visibleTop, visibleBottom];
this.visibleItems = this.items.slice(visibleTop, visibleBottom);
this.placeholderHeight = visibleTop * this.itemHeight;
},
},
};
</script>
<style scoped>
.virtual-list {
position: relative;
overflow: hidden;
}
.virtual-list-placeholder {
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
}
.virtual-list-viewport {
position: relative;
pointer-events: auto;
}
</style>
<template>
<view class="shipmentBriefInfo">
<bs-pageHeader-orderNo :shipmentNo="shipmentNo" />
<view class="primary-info routine_radius_card flex_center">
<view class="flex">
<view class="left-icon">
<view :class="['t-icon', stopsInfo.loadStop ? 't-icon-a-zhuang2x1' : 't-icon-a-xie2x1']" />
</view>
<view class="primary-desc flex_col">
<view style="margin-bottom: 8rpx;" class="font_bolder">{{stopsInfo.locationName}}</view>
<view>{{stopsInfo.locationAddress}}</view>
</view>
</view>
<view style="width: 100%;">
<bs-customCell label="货量 :" labelCol="2" wrapCol="10"
:value="stopsInfo.locationOrders + '单/' +stopsInfo.locationQty+ '件/' + stopsInfo.locationWeight+'千克/'+ stopsInfo.locationVolume+'方'" />
</view>
</view>
</view>
</template>
<script>
export default {
name: "shipmentBriefInfo",
options: { styleIsolation: 'shared' },
created: function() { //定义组件的生命周期
this.initData()
},
data() {
return {
stopsInfo: {}, //站点信息,
shipmentNo: '' //运单号
};
},
methods: {
initData() {
const appInstance = getApp()
const { stopsInfo, shipmentInfo } = appInstance.globalData
this.stopsInfo = stopsInfo
this.shipmentNo = shipmentInfo.shipmentNo
}
}
}
</script>
<style lang="scss">
.primary-info {
flex-wrap: wrap;
.left-icon {
position: relative;
margin-right: 20rpx;
.leftIcon-text {
font-size: 28rpx;
display: inline-block;
position: absolute;
top: 5px;
left: 12px;
}
.t-icon {
width: 70rpx;
height: 70rpx;
}
}
/deep/.custom-cell-row {
width: 100%;
margin-top: 32rpx;
color: #8C8C8C;
}
}
</style>
<template>
<view class="shipmentCard" v-if="isShow">
<view class="shipment-header flex_sb">
<view class="consumer_code flex_center">
<text selectable> 运单号:{{data.header.shipmentNo}}</text>
</view>
<view :class="data.header.shipmentStatus ==='Approved' ? 'shipment-state' : 'shipment-state shipmenting'">
{{data.header.shipmentStatusLabel}}
</view>
</view>
<!-- 主要运单信息 -->
<bs-customCell :label="'发运日期:'" :value="data.header.shipmentDate" labelCol="3" wrapCol="8" />
<!-- <bs-customCell label="运输时效 :" :value="data.header.shipTime + '天'" labelCol="3" wrapCol="8" /> -->
<!-- 司机信息 -->
<bs-customCell label="司机姓名:" :value="data.header['driver1.name']" labelCol="3" wrapCol="8" v-if="data.header['driver1.name']" />
<bs-customCell label="司机手机:" :value="data.header['driver1.tel']" labelCol="3" wrapCol="8" v-if="data.header['driver1.tel']" />
<bs-customCell label="车牌号:" :value="data.header['truck.name']" labelCol="3" wrapCol="8" v-if="data.header['truck.name']" />
<bs-customCell label="车型:" :value="data.header['truck.facilityMode.name']" labelCol="3" wrapCol="8" v-if="data.header['truck.facilityMode.name']" />
<bs-customCell label="装载率:" :value="data.header['loadRate'] + '%'" labelCol="3" wrapCol="8" v-if="!data.header['loadRate'] === 0" />
<bs-customCell label="货量:" labelCol="2" wrapCol="9"
:value="`${data.header.shipOrders}单 / ${data.header.shipQty}件 / ${data.header.shipWeight}千克 / ${data.header.shipVolume}方`" />
</view>
</template>
<script>
export default {
name: "shipmentCard",
options: { styleIsolation: 'shared' },
props: {
propData: {
type: String,
default: ""
},
},
created() {
if(this.propData){
this.data = JSON.parse(this.propData);
}
},
watch: {
propData: {
handler(newValue) {
this.data = JSON.parse(newValue);
this.$nextTick(() => {
this.isShow = false
this.isShow = true
})
}
},
},
data() {
return {
data: {},
isShow: true
}
}
}
</script>
<style lang="scss">
.shipmentCard {
background-color: #fff;
padding: 32rpx;
.consumer_code {
line-height: 40rpx;
text-shadow: 1rpx 3rpx 12rpx rgba(0, 0, 0, 0.04);
}
.shipment-state {
font-size: 24rpx;
color: #F7A64A;
line-height: 33rpx;
padding: 6rpx 24rpx;
border-radius: 8rpx;
background: rgba(247, 166, 74, .1);
text-shadow: 1rpx 3rpx 12rpx rgba(0, 0, 0, 0.04);
}
.shipmenting {
color: #66CCCC;
background: rgba(61, 204, 185, .1);
}
}
</style>
<template>
<view class="shipmentItem box_shadow_card" @click="navToShipmentDetail">
<view class="shipment-header flex_sb" style="padding: 28rpx 24rpx 0;">
<view class="consumer_code flex_center">
<text selectable> 运单号:{{propData.shipmentNo}}</text>
</view>
<view :class="propData.shipmentStatus ==='Approved' ? 'shipment-state' : 'shipment-state shipmenting'">
{{propData.shipmentStatusLabel}}
</view>
</view>
<u-line color="#E5E5E5" margin="20rpx 0" />
<view style="padding: 0 24rpx 32rpx;">
<view class="stations">
<view class="start-station flex_center">
<view class="t-icon-start-sddress t-icon" style="margin-right: 8rpx;"></view>
{{propData['original.name'] || ''}}
</view>
<view class="end-station flex_center">
<view class="t-icon-end-sddress t-icon" style="margin-right: 8rpx;"></view>
{{propData['destination.name'] || ''}}
</view>
</view>
<bs-customCell label="发运日期 :" :value="propData.shipmentDate" labelCol="3" wrapCol="6" />
<!-- <customCell label="运输时效" :value="propData.shipTime || '0天'" labelCol="4" wrapCol="6" /> -->
<template v-if="0">
<bs-customCell label="司机名" :value="propData['driver1.tel']" labelCol="2" wrapCol="10" />
<bs-customCell label="车牌号" :value="propData['truck.name']" labelCol="2" wrapCol="10" />
</template>
<bs-customCell label="货量 :" labelCol="2" wrapCol="10" :value="`${propData.shipOrders}单 / ${propData.shipQty}件 / ${propData.shipWeight}千克 / ${propData.shipVolume}方`" />
<template v-if="propData.shipmentStatus ==='Approving'">
<view class="operationBtn flex_center flex_cen" @click.stop="onClick(propData.id, 'approve')">确认</view>
</template>
<template v-if="propData.shipmentStatus ==='Approved'">
<view class="operationBtn flex_center flex_cen" @click.stop="onClick(propData.id, 'approveCancel')">取消确认</view>
</template>
</view>
</view>
</template>
<script>
import {shipmentDispatch} from '../../api/apiList.js'
export default {
name: 'shipmentItem',
options: { styleIsolation: 'shared' },
props: {
propData: {
type: Object,
default: {}
},
},
methods: {
navToShipmentDetail() {
this.onSetGlobalData()
const shipmentId = this.propData.id
wx.navigateTo({
url: `/subpkg/shipmentDetail/shipmentDetail?id=${shipmentId}`,
})
},
//设置全局变量
onSetGlobalData() {
const appInstance = getApp()
appInstance.globalData.shipmentInfo = { //设置全局变量
shipmentNo: this.propData.shipmentNo,
shipmentId: this.propData.id,
shipmentBizName: this.propData.bizName,
}
},
onClick(shipmentId, operationType){
const reqData = {
"args": {
"selectedIds": [shipmentId]
}
}
shipmentDispatch(operationType, reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '操作成功',
duration: 1500
})
setTimeout(() => {
this.$emit('onReload')
}, 1500)
}
})
}
}
}
</script>
<style lang="scss">
.shipmentItem {
position: relative;
margin: 24rpx 24rpx 0;
padding: 0;
&/deep/.custom-cell-row {
margin-top: 20rpx;
}
.consumer_code {
line-height: 40rpx;
text-shadow: 1rpx 3rpx 12rpx rgba(0, 0, 0, 0.04);
}
.shipment-state {
font-size: 24rpx;
color: #F7A64A;
line-height: 33rpx;
padding: 6rpx 24rpx;
border-radius: 8rpx;
background: rgba(247, 166, 74, .1);
text-shadow: 1rpx 3rpx 12rpx rgba(0, 0, 0, 0.04);
}
.shipmenting {
color: #66CCCC;
background: rgba(61, 204, 185, .1);
}
.start-station,
.end-station {
margin: 20rpx 0;
font-size: 30rpx;
font-weight: bolder;
.start-icon,
.end-icon {
width: 40rpx;
height: 40rpx;
font-size: 24rpx;
padding: 8rpx;
border-radius: 50%;
color: #FFFFFF;
background-color: #2E75E6;
margin-right: 20rpx;
}
.end-icon {
background-color: #F7A64A;
}
}
.operationBtn {
color: #FFFFFF;
padding: 20rpx;
margin-top: 32rpx;
border-radius: 44rpx;
box-shadow: 1rpx 3rpx 12rpx 0px rgba(0, 0, 0, 0.04);
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
width: 100%;
}
}
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
// #ifdef H5
import jwx from 'jweixin-module' //H5页面引入微信JSSDK,并全局挂载
Vue.prototype.$jwx = jwx
// #endif
// 引入uView并配置
import uView from 'uview-ui'
Vue.use(uView)
// 修改uView内置配置方案: 需要在Vue.use(uView)之后执行,目前只建议修改config、props属性, 除非您清楚知道自己的修改所带来的影响。
uni.$u.setConfig({
// 修改$u.config对象的属性
config: {
// 修改默认单位为rpx,相当于执行 uni.$u.config.unit = 'rpx'
unit: 'rpx'
},
// 修改$u.props对象的属性
props: {
// 修改radio组件的size参数的默认值,相当于执行 uni.$u.props.radio.size = 30
radio: {
size: 15
}
// 其他组件属性配置
// ......
}
})
Vue.prototype.getLocationCity = (cityInfo)=>{
const addressIsEmpty = (add)=>{
if (add) return add
return ""
}
let cityStr = ""
cityStr += addressIsEmpty(cityInfo['location.province'])
if (cityInfo['location.province'] !== cityInfo['location.city']){
cityStr += addressIsEmpty(cityInfo['location.city'])
}
cityStr += addressIsEmpty(cityInfo['location.district']) + addressIsEmpty(cityInfo['location.detail'])
return cityStr
}
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif
{
"name" : "运匠运输管理系统",
"appid" : "__UNI__2878006",
"description" : "TMS-承运商",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* 模块配置 */
"modules" : {},
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios打包配置 */
"ios" : {},
/* SDK配置 */
"sdkConfigs" : {}
}
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "wxd7383e6db760127c",
"setting" : {
"urlCheck" : false,
"es6" : true,
"postcss" : false
},
"usingComponents" : true,
"lazyCodeLoading" : "requiredComponents",
"requiredPrivateInfos" : [ "getLocation" ],
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于中转换车等上报操作"
},
"scope.camera" : {
"desc" : "该操作仅用于OCR识别时拍照辅助定位"
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2",
"h5" : {
"devServer" : {
"https" : false,
"disableHostCheck" : true,
"port" : 8080,
"proxy" : {
"/api" : {
"target" : "https://miniapp.logwirecloud.com",
// "target": "http://192.168.1.199:7080",
"changeOrigin" : true,
"secure" : false
},
"/handler" : {
"target" : "https://miniapp.logwirecloud.com",
// "target": "http://192.168.1.199:7080",
"changeOrigin" : true,
"secure" : false
},
"/sandtable" : {
"target" : "https://miniapp.logwirecloud.com",
// "target": "http://192.168.1.199:7080",
"changeOrigin" : true,
"secure" : false
},
"/tmsca" : {
"target" : "https://miniapp.logwirecloud.com",
// "target": "http://192.168.1.199:7080",
"changeOrigin" : true,
"secure" : false
}
}
},
"router" : {
"mode" : "hash",
"base" : "./"
},
"template" : "template.h5.html",
"sdkConfigs" : {
"maps" : {}
}
}
}
import AMap from '../utils/AMapUtil'; //高德工具类
import BMap from '../utils/BMapUtil'; //百度工具类
import { formatTime } from './../utils/util.js';
import { getMap, userMobileOperation } from '../api/apiList.js'
// #ifdef MP
import AMapSDK from "../utils/MapSDK/amap-wx.130"
import BMapSDK from '../utils/MapSDK/bmap-wx.min.js'
// #endif
// #ifdef H5
import AMapLoader from "@amap/amap-jsapi-loader"; //高德
// #endif
module.exports = {
data() {
return {
locationInfo: {}, //用户当前位置信息
isLocation: true, //是否获取位置中
};
},
//事件处理函数
methods: {
//初始化地图服务
async initMapService() {
await this.initMapInstance()
// #ifdef H5
const isWxBrowser = getApp().isWxBrowser()
if (isWxBrowser) {
await this.initWXH5SDK() //H5时初始化微信JSSDK, 以调用扫码、获取经纬度等功能
}
// #endif
return Promise.resolve('done');
},
//获取地图密钥并初始化地图实例, 用于转换接口获取的经纬度为文字描述, 小程序返回MapInstance H5返回MapContext
initMapInstance() {
const _this = this
return new Promise((resolve, reject) => {
getMap().then(res => {
//参数说明: 微信小程序KEY: wechatKey WEB地图KEY: jsKey WEB地图密钥: securityJsCode 地图服务商:BaiduMap/AMap(默认使用AMap高德服务)
const { wechatKey, jsKey, securityJsCode, serviceProvider } = res.data.data || {}
getApp().globalData.serviceProvider = serviceProvider
// #ifdef MP
if (!wechatKey) {
_this.showMapTost('请在BO系统集成中配置地图的Wechat Key')
} else {
let newMap = null
if(serviceProvider === 'AMap'){
newMap = new AMapSDK.AMapWX({ key: wechatKey }) //高德地图Key
} else {
newMap = new BMapSDK.BMapWX({ ak: wechatKey }); //百度地图key
}
getApp().globalData.MapIns = newMap
resolve(newMap);
}
// #endif
// #ifdef H5
if (!jsKey) {
_this.showMapTost('请在BO系统集成中配置地图的JS API Key')
} else if (!securityJsCode && serviceProvider === 'AMap') { //高德无需Security秘钥
_this.showMapTost('请在BO系统集成中配置地图的JS Security')
} else {
if(serviceProvider === 'AMap'){
window._AMapSecurityConfig = { securityJsCode}
AMapLoader.load({
"key": jsKey, // 申请好的Web端开发者Key,首次调用 load 时必填
"version": "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
"plugins": ["AMap.Marker", "AMap.Pixel","AMap.Geocoder","AMap.Geolocation"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then(async (AMapCtx) => {
getApp().globalData.MapIns = AMapCtx
resolve(AMapCtx);
}).catch(err => {
_this.showMapTost(err, 'errrr')
});
} else {
const BMap_URL = `https://api.map.baidu.com/api?v=2.0&ak=${jsKey}&callback=onBMapCallback`;
// 插入script脚本
let scriptNode = document.createElement("script");
scriptNode.type="text/javascript";
scriptNode.setAttribute("src", BMap_URL);
document.body.appendChild(scriptNode);
// 百度地图异步加载回调处理
window.onBMapCallback = function() {
getApp().globalData.MapIns = window.BMap
resolve(window.BMap);
};
}
}
// #endif
// APP && PDA端需引入指定定位SDK, 暂未兼容地图及定位服务
// #ifdef APP-PLUS
// #endif
})
})
},
//弹窗提示
showMapTost(tostText) {
uni.showToast({
title: tostText,
icon: 'none',
duration: 3000
})
},
//初始化微信JSSDK
async initWXH5SDK() {
const { appId, timestamp, nonceStr, sign } = await this.getJwxConfig()
await this.setJwxConfig(appId, timestamp, nonceStr, sign)
return Promise.resolve('done');
},
//获取JSSDK配置签名
getJwxConfig() {
return new Promise(resolve => {
let url = window.location.href.split('#')[0] //当前页面域名 botms.logwirecloud.com, 相同url无需重复获取
const { projectMini } = getApp().globalData
const data = { args: { entryName: projectMini, url } }
userMobileOperation('querySignature', data).then(res => { //获取签名
if (res.data.data) {
const { appId, timestamp, nonceStr, sign } = res.data.data
resolve({ appId, timestamp, nonceStr, sign })
}
})
})
},
//配置JS-SDK
setJwxConfig(appId, timestamp, nonceStr, signature) {
return new Promise((resolve, reject) => {
this.$jwx.config({ //JWX 已在main.js 中全局挂载
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature, // 必填,签名
jsApiList: ['scanQRCode', 'getLocation', 'openLocation','chooseImage'] // 必填,需要使用的JS接口列表
});
this.$jwx.ready(() => {
this.$jwx = this.$jwx //ready 完成后供全局调用
resolve(this.$jwx)
});
this.$jwx.error(err => {
console.log('微信JSSDK实例化失败: ' + err.errMsg)
reject(err)
})
})
},
//获取用户授权和当前位置 关于uni.getLocation(): 使用该接口需要在Manifest.json中配置相关地图Key,由于为明文故弃用
getUserSetting() {
this.isLocation = false
const { serviceProvider } = getApp().globalData
// #ifdef H5
const callBack = (res) => {
const { latitude, longitude } = res
getApp().globalData.userLocation = { latitude, longitude } //H5转换坐标时使用
this.getSiteName() //H5授权后手动设置一次当前位置信息
}
const isWxBrowser = getApp().isWxBrowser() //判断是否为微信H5
if (isWxBrowser && this.$jwx) {
this.$jwx.getLocation({ //H5时使用JSSDK获取经纬度,自动弹出授权对话框,真机仅弹出一次
type: 'gcj02',
success: (res) => {
callBack(res)
}
})
} else { //WEB浏览器
if(serviceProvider === 'AMap'){
AMap.AMapGetLocation().then(res => callBack(res))
} else {
BMap.BMapGetLocation().then(res => callBack(res))
}
}
// #endif
// #ifdef MP
uni.getSetting({ //小程序中判断用户是否授权位置权限
success: (res) => {
if (!res.authSetting['scope.userLocation']) {
uni.authorize({
scope: 'scope.userLocation',
success: () => {
this.getSiteName();
},
fail: () => {
this.isLocation = true
uni.showModal({
title: '提示',
content: '缺失定位信息,前往系统设置开启定位权限!',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: () => {
this.getUserSetting()
}
});
}
}
});
}
});
} else {
this.getSiteName();
}
}
});
// #endif
},
//获取当前位置信息
getSiteName() {
const { serviceProvider } = getApp().globalData
const newMapUtil = serviceProvider === 'AMap' ? AMap : BMap
newMapUtil.reverseGeocoder()
.then((res) => {
const address = res.textData.desc;
const time = formatTime(new Date());
const info = { ...res, address, time };
getApp().globalData.userLocation = info;
this.locationInfo = info
this.isLocation = true
})
.catch((err) => {
this.isLocation = true
uni.showToast({
title: err,
icon: 'none',
duration: 3000
});
});
}
}
};
\ No newline at end of file
import { userLogin,authLogin, updateLocation } from "../api/apiList";
import { APP_ID, ENV_MODEL, TokenPrefix } from "../publicConfig/config";
module.exports = {
methods: {
//获取微信token
getWxToken() {
uni.login({
success: (res) => {
this.login(res.code);
},
});
},
// 获取H5 授权Code
getH5Code() {
//是否重新获取授权
let code = this.getQueryString("code");
let time = new Date().getTime();
if (code) {
return {
code,
time,
};
} else {
this.onRedirect(); //重定向获取Code
}
},
//重定向授权 用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知。
onRedirect() {
let href = window.location.href;
if (href.includes("?")) {
//防止重定向地址重复拼接
href = href.split("?")[0];
}
let url = encodeURIComponent(href);
let appId = "";
if (process.env.NODE_ENV === "development") {
appId = APP_ID.h5Dev;
} else {
switch (ENV_MODEL.model) {
case "UAT":
appId = APP_ID.h5Uat;
break;
default:
appId = APP_ID.h5Prod;
}
}
let HREF = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${url}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`;
window.location.href = HREF;
},
//用户登录
login(code) {
const _this = this;
if (!uni.getStorageSync("SearchHistory")) {
uni.setStorageSync("SearchHistory", []);
}
const { projectMini } = getApp().globalData;
let { pagePath, route } = this.getPathRoute(1); //获取跳转前当前页面完整路径及路由
try {
// #ifdef H5
pagePath = window.location.href.split("#")[1]; //获取跳转前当前页面完整路径及路由
route = pagePath.split("?")[0];
// #endif
//登录Action: loginByUserInfo已与手机号验证码登录实现互通, 故自动认证时默认为loginByUserInfo
let reqData = { entryName: projectMini }
authLogin("loginByUserInfo", code, reqData).then(res => {
let XSRFToken = "";
//#ifdef MP
if (res.header["Set-Cookie"]) {
XSRFToken = res.header["Set-Cookie"].split(";")[0].split("=")[1];
uni.setStorageSync(`${TokenPrefix}_XSRFToken`, XSRFToken);
}
//#endif
// #ifdef H5
XSRFToken = _this.getCookies("XSRF-TOKEN");
uni.setStorageSync(`${TokenPrefix}_XSRFToken`, XSRFToken);
// #endif
const messageType = res.data.messageType;
if (messageType === "success") {
let token = res.data.renewedToken;
uni.setStorageSync(`${TokenPrefix}_token`, token);
// #ifdef MP
uni.setStorageSync("cookies", res.cookies);
// #endif
if (route && route !== "pages/login/login" && route !== "/") {
uni.reLaunch({
url: pagePath,
}); //可跳转至任意页面
} else {
uni.switchTab({
url: "/pages/index/index",
});
}
// #ifdef MP
// _this.onUpdateLocation()
// #endif
}
}).catch((err) => {
if (route && route !== "pages/login/login" && route !== "/") {
//非登录页认证,则跳转至登录页面
getApp().globalData.backPagePath = pagePath; //当需要跳转登录页面,跳转前记录当前页面,作为回退页面
uni.navigateTo({
url: "/pages/login/login",
});
}
uni.showToast({
title: err.message,
icon: "none",
duration: 3000,
});
});
} catch (err) {
//非登录页认证,则跳转至登录页面
getApp().globalData.backPagePath = pagePath; //当需要跳转登录页面,跳转前记录当前页面,作为回退页面
uni.navigateTo({
url: "/pages/login/login",
});
}
},
//获取页面完整路径及路由, pageIndex为页面索引,
getPathRoute(pageIndex) {
let pagePath = "";
let route = ""; //当前页面完整路径及路由
const pages = getCurrentPages(); // 获取所有页面实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。在onLaunch时获取为空,因为页面还未加载
const currentPage = pages[pages.length - pageIndex]; //获取当前页面实例
if (currentPage) {
pagePath = currentPage.$page.fullPath;
route = currentPage.route;
}
return {
pagePath,
route,
};
},
// 开始地理位置监听
onUpdateLocation() {
uni.startLocationUpdateBackground({
success: (res) => {
console.log("开启小程序接收位置消息成功");
uni.onLocationChange(function (res) {
const { longitude, latitude, speed } = res;
const timestamp = new Date().getTime();
const data = {
aux: {
map: {
gpsDevice: {
deviceId: "沪TESTM01",
deviceType: "MiniApp",
},
gpsDataList: [
{
longitude,
latitude,
speed,
timestamp,
},
],
},
},
};
updateLocation(data);
});
},
fail: (err) => console.log("开启小程序接收位置消息失败:", err),
});
},
getCookies(cName) {
// 调用函数let cookie_val = getCookie(cookie的名字);
var name = cName + "=";
var ca = document.cookie.split(";");
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
}
return "";
},
getQueryString(name) {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
let r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
let context = "";
if (r != null) context = decodeURIComponent(r[2]);
reg = null;
r = null;
return context == null || context == "" || context == "undefined"
? ""
: context;
},
},
};
import { uploadImg } from '../api/apiList';
module.exports = {
data() {
return {
fileList: [], //文件列表
fileDetailList: [], //文件列表, 含文件名等
isIos: false,
visible: false ,//是否显示自定义相机
};
},
created() {
// #ifdef H5
const platform = uni.getSystemInfoSync().platform
if (platform === 'ios') {
// this.isIos = true
}
// #endif
},
//事件处理函数
methods: {
//图片上传 IOS兼容
onUpLoad() {
if (this.cameraType) {
this.visible = true //跳转自定义相机
} else if (this.$jwx) {
const _this = this
const sourceType = this.isIos ? ['album'] : ['album', 'camera'] // 可以指定来源是相册还是相机, ios指定为仅相册
this.$jwx.chooseImage({
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: sourceType,
success: function(res) {
_this.onConvert(res.localIds)
}
})
}
},
async onConvert(localIds) {
for (var i = 0; i < localIds.length; i++) {
await this.onReadImage(localIds[i]);
}
},
onReadImage(localId) {
const _this = this
return new Promise((resolve, reject) => {
_this.$jwx.getLocalImgData({
localId: localId, // 图片的localID
success: function(res) {
const localData = res.localData
_this.fileList = _this.fileList.concat(localData)
resolve('done!')
}
});
})
},
//上传图片
uploadImage(callback) {
let { fileList } = this;
if (!fileList.length && !this.required) return callback('');
if (!fileList.length) {
uni.showToast({
title: `请选择${this.uploadTitle}`,
icon: 'error',
duration: 3000
});
return;
}
let images = [];
fileList.forEach(item => {
const file = this.fileDetailList.find(file => file.url === item)
uploadImg(item, file.type).then(res => { //微信小程序仅支持单文件上传,传多个文件需要反复调用本API。所以跨端的写法就是循环调用本API。
uni.hideLoading();
let data = JSON.parse(res).data;
images.push(data.path);
if (images.length === fileList.length) {
return callback(images.join('|'));
}
})
});
},
// 上传文件回调
uploadAfterRead(info) {
let { file } = info;
const newFile = file.map(item => item.url);
this.fileList = [...this.fileList, ...newFile]
this.fileDetailList = [...this.fileDetailList, ...file]
},
//拍照确认回调
customCameraFinish(imgSrc){
this.visible = false
this.fileList = [...this.fileList, imgSrc]
this.fileDetailList = [...this.fileDetailList, {url: imgSrc, type: 'image'}]
this.$emit('customUploadAfter', {url: imgSrc, type: 'image', cameraType: this.cameraType}) //自定义上传回调
},
// 预览图片回调
previewImage(e) {
let { index } = e.currentTarget.dataset;
uni.previewImage({
current: index,
urls: this.fileList
})
},
// 删除当前选中文件
deleteFile(index) {
uni.showModal({
title: '删除提示',
content: '是否确认删除?',
success: (res) => {
if (res.confirm) {
this.fileList = this.fileList.filter((item,idx) => idx !== index)
this.fileDetailList = this.fileDetailList.filter((item,idx) => idx !== index)
} else if (res.cancel) {}
}
});
},
}
};
{
"name": "biz-trina5-app",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"uview-ui": {
"version": "2.0.31",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.31.tgz",
"integrity": "sha512-I/0fGuvtiKHH/mBb864SGYk+SJ7WaF32tsBgYgeBOsxlUp+Th+Ac2tgz2cTvsQJl6eZYWsKZ3ixiSXCAcxZ8Sw=="
}
}
}
{
"name": "biz-trina5-app",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"image-tools": "^1.4.0",
"jweixin-module": "^1.6.0",
"uview-ui": "^2.0.31",
"vconsole": "^3.15.0"
}
}
{
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
"bs-(.*)": "@/components/baseComponents/bs-$1/bs-$1.vue"
}
},
"pages": [{
"path": "pages/login/login",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": false,
"disableScroll": true
}
}, {
"path": "pages/index/index",
"style": {
"enablePullDownRefresh": true
}
}, {
"path": "pages/user/user",
"style": {
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false,
"disableScroll": true
}
}, {
"path": "pages/order/order",
"style": {
"enablePullDownRefresh": false
}
}],
"subPackages": [{
"root": "subpkg",
"pages": [{
"path": "editPwd/editPwd",
"style": {
"navigationBarTitleText": "修改密码",
"enablePullDownRefresh": false
}
}, {
"path": "shipmentDetail/shipmentDetail",
"style": {
"navigationBarTitleText": "运单详情",
"enablePullDownRefresh": false
}
}, {
"path": "allotDetail/allotDetail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "allotTruck/allotTruck",
"style": {
"navigationBarTitleText": "配车",
"enablePullDownRefresh": false
}
}, {
"path": "orderDetail/orderDetail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "transferChange/transferChange",
"style": {
"navigationBarTitleText": "中转换车",
"enablePullDownRefresh": false
}
}, {
"path": "transferAddressDetail/transferAddressDetail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "viewDriverTruck/viewDriverTruck",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "reserveDock/reserveDock",
"style": {
"navigationBarTitleText": "预约站点",
"enablePullDownRefresh": false
}
}, {
"path": "reserveDockTime/reserveDockTime",
"style": {
"navigationBarTitleText": "预约到站时间",
"enablePullDownRefresh": false
}
}, {
"path": "registerDriver/registerDriver",
"style": {
"navigationBarTitleText": "司机注册",
"enablePullDownRefresh": false
}
}, {
"path": "registerTruck/registerTruck",
"style": {
"navigationBarTitleText": "车辆注册",
"enablePullDownRefresh": false
}
}, {
"path": "viewDriverTruckDetail/viewDriverTruckDetail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "signFor/signFor",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"disableScroll": false
}
}, {
"path": "checkTruck/checkTruck",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "allotCars/allotCars",
"style": {
"navigationBarTitleText": "配车确认",
"enablePullDownRefresh": false
}
}, {
"path": "choiceTruck/choiceTruck",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "shipmentLbs/shipmentLbs",
"style": {
"navigationBarTitleText": "运单轨迹",
"enablePullDownRefresh": false,
"disableScroll": true
}
}]
}],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "天合光能",
"navigationBarBackgroundColor": "#2E75E6",
"backgroundColor": "#fff",
"app-plus": {
"background": "#efeff4"
},
"h5": {
"navigationStyle": "custom"
}
},
"tabBar": {
"color": "#999999",
"selectedColor": "#2E75E6",
"backgroundColor": "#fff",
"list": [{
"pagePath": "pages/index/index",
"text": "运单",
"iconPath": "static/img/tabbar/shipment.png",
"selectedIconPath": "static/img/tabbar/shipment-active.png"
}, {
"pagePath": "pages/order/order",
"text": "订单",
"iconPath": "static/img/tabbar/order.png",
"selectedIconPath": "static/img/tabbar/order-active.png"
},
{
"pagePath": "pages/user/user",
"text": "我的",
"iconPath": "static/img/tabbar/user.png",
"selectedIconPath": "static/img/tabbar/user-active.png"
}
]
}
}
<template>
<view class="shipment-order-list content_box">
<shipmentItem v-for="item in shipmentOrders" :key="item.id" :propData="item" @onReload="onReload"/>
<!-- 空状态 -->
<view class="emptyImg flex_col" v-if="!shipmentOrders.length">
<image mode="aspectFit" src="../../static/img/empty/shipmentEmpty.png" />
<text class="empty-text">暂时没有运单</text>
</view>
</view>
</template>
<script>
import { findShipmentOrders } from '@/api/apiList.js'
import { formatGMT } from '@/utils/util.js'
import { TokenPrefix } from '../../publicConfig/config.js'
const getUserLocation = require('../../mixins/getUserLocation')
export default {
mixins: [getUserLocation],
data() {
return {
shipmentOrders: [], //运输订单
pageNum: 1, //页码
pageSize: 10, //每页条数
loadMore: true, //加载更多
}
},
onLoad(options) {
const time = setInterval(() => {
let XSRFToken = uni.getStorageSync(`${TokenPrefix}_XSRFToken`)
if (XSRFToken) {
this.initData()
this.initMapService() //初始化地图
clearInterval(time)
}
}, 1000);
},
//下拉刷新
onPullDownRefresh() {
this.onReload()
},
// 触底加载更多
onReachBottom() {
if (this.loadMore) {
this.initData();
this.loadMore = false
}
},
methods: {
//初始化数据
initData() {
const { pageNum, pageSize } = this
let data = {
"args": { pageNum, pageSize }
}
findShipmentOrders(data).then(res => {
uni.stopPullDownRefresh()
const data = res.data.data.datas
if (data.length > 0) {
data.map(item => { //格式化时间
if (item.shipmentDate) {
item.shipmentDate = formatGMT(item.shipmentDate, 'D')
}
})
this.shipmentOrders = this.shipmentOrders.concat(data)
this.pageNum += 1
this.loadMore = true
}
})
},
// 刷新页面
onReload() {
this.pageNum = 1
this.shipmentOrders = []
this.initData()
},
}
}
</script>
<style lang="scss">
.shipment-order-list {
.emptyImg {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.empty-text {
font-size: 28rpx;
text-align: center;
}
}
}
</style>
<template>
<view class="content_box flex_col" :style="{backgroundImage: `url(${loginBg})`}" >
<view class="primary-description">
<view class="container-title flex_cen">天合光能运输管理系统</view>
<!-- <view class="container-subTitle flex_cen">上海运匠信息科技有限公司</view> -->
</view>
<image class="container-logo" src="../../static/img/bg/trinaLog.png"></image>
<!-- 用户信息录入 -->
<view class="user-info flex_center">
<u-form :model="formData" ref="myForm" errorType='tost'>
<template v-if="isVerifLogin">
<u-form-item prop="phone">
<u-input type="number" v-model="formData.phone" placeholder="请输入手机号" />
</u-form-item>
<u-form-item prop="password">
<u-input type="password" v-model="formData.telPassword" placeholder="请输入密码" />
</u-form-item>
<!-- <u-form-item prop="authCode">
<u-input type="number" v-model="formData.authCode" maxlength="6" border="none" placeholder="验证码" />
<u-button slot="right" @click="getAuthCode" :text="tips" type="success" size="mini" :disabled="disabled" />
</u-form-item>
<u-code ref="uCode" @change="onTipsChange" seconds="60" @start="disabled" @end="disabled" />-->
</template>
<template v-else>
<u-form-item prop="userName">
<u-input type="text" v-model="formData.userName" placeholder="请输入账号" />
</u-form-item>
<u-form-item prop="password">
<u-input type="password" v-model="formData.password" placeholder="请输入密码" />
</u-form-item>
</template>
</u-form>
<view class="login-actionBtn" @click="chooseVerifLogin">{{isVerifLogin==false ? '返回上一级' : '承运商登录'}}</view>
<!-- 登录按钮 -->
<button class="loginBtn font_bolder" @click="submitForm">登录</button>
</view>
<!-- 用户隐私协议
<bs-userPrivacy ref="userPrivacy" />-->
</view>
</template>
<script>
import { MINI, ENV_MODEL, TokenPrefix } from '../../publicConfig/config.js'
import { userLogin, SendMessage } from '../../api/apiList.js'
const loginBehavior = require('../../mixins/loginBehavior.js')
export default {
mixins: [loginBehavior],
data() {
return {
loginBg: '', //登录页面背景图
formData: {
userName: '', //用户名
password: '', //密码
phone: '', //电话号码
telPassword:'',//电话
authCode: '' //验证码
},
isVerifLogin: true, //是否为验证码登录
tips: '获取验证码',
disabled: false, //是否禁用获取验证码
}
},
onLoad() {
// #ifdef H5
this.loginBg = 'static/img/bg/loginBg.png'
// #endif
// #ifdef APP-PLUS
this.loginBg = '../../static/img/bg/loginBg.png'
// #endif
// #ifdef MP
let base64Png = uni.getFileSystemManager().readFileSync("static/img/bg/loginBg.png", 'base64');
this.loginBg = 'data:image/jpg;base64,' + base64Png
// #endif
this.projectMini = getApp().globalData.projectMini
},
methods: {
//手机验证码登录
chooseVerifLogin() {
this.isVerifLogin = !this.isVerifLogin
},
onShowTost(tostText, time=1000) {
uni.showToast({
title: tostText,
icon: 'none',
duration: time
})
},
//表单提交前规则校验
onSubmitBeforeRule(userName, password, phone, telPassword ){
let ruleFlag = true
let tostText = ''
//表单字段校验
if(this.isVerifLogin){
if(!phone && !telPassword){
tostText = '请输入手机号及密码'
} else if(!phone){
tostText = '请输入手机号'
} else if(!telPassword){
tostText = '请输入密码'
} else if(phone && !uni.$u.test.mobile(phone)){
tostText = '请输入有效手机号码'
}
} else {
if(!userName && !password){
tostText = '请输入用户名及密码'
} else if(!userName){
tostText = '请输入用户名'
} else if(!password){
tostText = '请输入密码'
}
}
if(tostText){
ruleFlag = false
this.onShowTost(tostText)
}
return ruleFlag
},
//加密
encryptedText(text){
if(!text) return ''
let newText = ''
try {
const buffer = Buffer.from(text, 'utf-8')
newText = uni.arrayBufferToBase64(buffer) //或 buffer.toString('base64');btoa(text)仅支持H5
} catch (err) { }
let encryptedText = '{encrypted}'
for (let i = 0; i < newText.length; i++) {
encryptedText += newText.charCodeAt(i).toString(16)
}
return encryptedText
},
//解密
decryptedText(encodedHexStr){
if(!encodedHexStr) return ''
const hexStr = encodedHexStr.match(/{encrypted}(\S*)/)[1]
let decryptedText = '';
for (let i = 0; i < hexStr.length; i += 2) {
decryptedText += String.fromCharCode(parseInt(hexStr.substr(i, 2), 16));
}
const buffer = uni.base64ToArrayBuffer(decryptedText);
try { return new TextDecoder('utf-8').decode(buffer)} catch (err) { return ''}
},
//确认提交
submitForm() {
const { userName, password, phone, telPassword } = this.formData
if(!this.onSubmitBeforeRule(userName, password, phone, telPassword)) return //规则校验
let {projectMini} = getApp().globalData
let loginAction = 'loginByUserInfo'
let reqData = { entryName: projectMini }
if (this.isVerifLogin) {
reqData = {...reqData, params: {phone, telPassword}}
loginAction = 'loginByCustomAuth'
} else {
const encryptedPassword = this.encryptedText(password)
reqData = {...reqData, userName, password: encryptedPassword}
}
//#ifdef MP
this.wxLogin(reqData, loginAction)
//#endif
//#ifdef H5
this.h5Login(reqData, loginAction)
//#endif
},
//小程序提交
wxLogin(reqData, loginAction) {
uni.login({
success: (res) => {
try {
reqData.code = res.code
let pagePath = getApp().globalData.backPagePath //获取回退页面
uni.setStorageSync(`${TokenPrefix}_XSRFToken`, '') //清除 XSRFToken
userLogin(loginAction, res.code, reqData).then(res => {
let token = res.data.renewedToken
if (res.header['Set-Cookie']) {
const XSRFToken = res.header['Set-Cookie'].split(';')[0].split('=')[1]
uni.setStorageSync(`${TokenPrefix}_XSRFToken`, XSRFToken);
}
uni.setStorageSync(`${TokenPrefix}_token`, token);
uni.setStorageSync('cookies', res.cookies)
if (pagePath) {
uni.reLaunch({
url: pagePath
}) //可跳转至任意页面
} else {
uni.showToast({
title: '登录成功!',
duration: 1000
})
setTimeout(() => {
uni.switchTab({
url: "/pages/index/index",
})
}, 1500)
}
}).catch(err => {
uni.showToast({
title: err.message || err,
icon: 'none',
duration: 3000
})
})
} catch (e) {
console.log(e)
}
}
})
},
//H5提交
h5Login(reqData, loginAction) {
const _this = this
const isWxBrowser = getApp().isWxBrowser()
let pagePath = getApp().globalData.backPagePath //获取回退页面
let newCode = ''
if (isWxBrowser) {
const { code } = _this.getH5Code()
newCode = code
}
userLogin(loginAction, newCode, reqData).then(res => {
let token = res.data.renewedToken
let XSRFToken = _this.getCookies('XSRF-TOKEN')
uni.setStorageSync(`${TokenPrefix}_token`, token);
uni.setStorageSync(`${TokenPrefix}_XSRFToken`, XSRFToken);
if (pagePath) {
uni.reLaunch({
url: pagePath
}) //可跳转至任意页面
} else {
uni.showToast({
title: '登录成功!',
duration: 1000
})
setTimeout(() => {
uni.switchTab({
url: "/pages/index/index",
})
}, 1500)
}
}).catch(err => {
uni.showToast({
title: err.message || err,
icon: 'none',
duration: 3000
})
})
},
//提示文本
onTipsChange(text) {
this.tips = text;
},
//获取手机验证码
getAuthCode() {
if (this.$refs.uCode.canGetCode) {
// 模拟向后端请求验证码
this.sendMessage()
} else {
uni.$u.toast('请稍候重试 !');
}
},
//获取验证码
sendMessage() {
const {projectMini} = getApp().globalData
SendMessage({
phone: this.formData.phone,
entryName: projectMini
}).then(() => {
setTimeout(() => {
uni.hideLoading();
uni.$u.toast('验证码已发送'); // 该提示会被this.start()方法中的提示覆盖
this.$refs.uCode.start(); // 开启倒计时
}, 1000);
})
},
}
}
</script>
<style lang="scss">
.content_box {
color: #FFFFFF;
letter-spacing: 6rpx;
background-size: 100%;
background-repeat: no-repeat;
padding: 0 32rpx;
justify-content: space-between;
.container-logo {
width: 400rpx;
height: 300rpx;
display: flex;
margin: -50px 0px 0px 60px;
}
.primary-description {
font-size: 28rpx;
font-weight: 400;
line-height: 40rpx;
.container-title {
font-size: 50rpx;
font-weight: 500;
line-height: 84rpx;
margin: 158rpx 0 85rpx;
}
}
.user-info {
width: 100%;
/* #ifdef MP */
margin-top: 400rpx;
/* #endif */
/* #ifdef H5 || APP-PLUS*/
margin-top: 320rpx;
/* #endif */
flex-wrap: wrap;
.loginBtn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
/* #ifdef MP */
margin-top: 212rpx;
/* #endif */
/* #ifdef H5 || APP-PLUS*/
margin-top: 160rpx;
/* #endif */
color: #FFFFFF;
font-size: 32rpx;
font-weight: bolder;
border-radius: 48rpx;
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
border: none !important;
margin-bottom: 100px;
&:after{
border: none;
}
}
.login-actionBtn {
width: 100%;
//text-align: center;
text-decoration: underline;
color: #2e75e6;
//margin-top: 40rpx;
}
/deep/.u-form {
width: 100%;
.u-form-item__body {
width: 100%;
padding: 6rpx 40rpx;
border-radius: 48rpx;
margin-bottom: 40rpx;
//background: rgba(225, 225, 225, .2);
background: rgba(139, 134, 134, .2);
.u-input {
padding: 16rpx !important;
border: none;
.u-input__content__field-wrapper__field {
letter-spacing: 2rpx !important;
}
}
.input-placeholder {
font-size: 32rpx;
}
}
}
}
.loginH5 {
/deep/.u-form-item__body {
padding: 6rpx 40rpx;
border-radius: 48rpx;
margin-bottom: 40rpx;
background: rgba(225, 225, 225, .2);
.u-input {
padding: 16rpx !important;
border: none;
}
.input-placeholder {
font-size: 32rpx;
}
}
.h5-loginBtn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
margin-top: 112rpx;
color: #FFFFFF;
font-size: 32rpx;
font-weight: bolder;
border-radius: 48rpx;
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
}
}
}
</style>
\ No newline at end of file
<template>
<view class="orderList content_box">
<orderItem v-for="( order, index ) in orderList" :propData="order" :key="index"/>
<!-- 空状态 -->
<view class="emptyImg flex_col" v-if="!orderList.length">
<image mode="aspectFit" src="../../static/img/empty/shipmentEmpty.png" />
<text class="empty-text">暂时没有订单</text>
</view>
</view>
</template>
<script>
import { getMassOrderList} from '../../api/apiList.js'
export default {
data() {
return {
pageNum: 1, //页码
pageSize: 10, //每页条数
orderList: [],
loadMore: true, //加载更多
};
},
onLoad() {
this.initData()
},
//下拉刷新
onPullDownRefresh() {
this.pageNum = 1
this.orderList = []
this.initData()
},
// 触底加载更多
onReachBottom() {
if (this.loadMore) {
this.initData()
this.loadMore = false
}
},
methods:{
initData(){
const { pageNum, pageSize } = this
let data = {
"args": { pageNum, pageSize }
}
getMassOrderList(data).then(res=>{
uni.stopPullDownRefresh()
const data = res.data.data.datas
if (data.length > 0) {
this.orderList = this.orderList.concat(data)
this.pageNum += 1
this.loadMore = true
}
})
}
}
}
</script>
<style lang="scss">
.orderList {
.emptyImg {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.empty-text {
font-size: 28rpx;
text-align: center;
}
}
}
</style>
<template>
<view class="user-content content_box">
<view class="user-header">
<image class="header-bg" src="../../static/img/bg/userBg.png" />
<view class="user-info flex">
<view class="user_photo">
<image src="../../static/img/empty/userPhoto.png"></image>
</view>
<view class="flex_col flex_cen" style="margin-left: 30rpx;">
<text class="user-name" user-select>{{userInfo.name}}</text>
<text class="user-phone" user-select>{{userInfo.mobile}}</text>
</view>
</view>
</view>
<!-- 修改密码 -->
<view class="edit-password ">
<u-cell-group :border="false">
<u-cell title-style="font-weight: bolder" rightIconStyle="font-size: 40rpx" isLink :border="false"
title="我的司机" url="/subpkg/viewDriverTruck/viewDriverTruck?action=driver">
<view slot="icon" class="t-icon t-icon-driver" />
</u-cell>
<u-line color="#F0F0F0" />
<u-cell title-style="font-weight: bolder" rightIconStyle="font-size: 40rpx" isLink :border="false"
title="我的车辆" url="/subpkg/viewDriverTruck/viewDriverTruck?action=truck">
<view slot="icon" class="t-icon t-icon-truck" />
</u-cell>
<u-line color="#F0F0F0" />
<u-cell title-style="font-weight: bolder" rightIconStyle="font-size: 40rpx" isLink :border="false"
title="修改密码" :url="'/subpkg/editPwd/editPwd?userName=' + userInfo.name">
<view slot="icon" class="t-icon t-icon-lock" />
</u-cell>
</u-cell-group>
</view>
<button class="exit-login flex_cen" @click="exitLog">退出登录</button>
</view>
</template>
<script>
import { userMobileOperation } from '../../api/apiList.js'
import { TokenPrefix } from '../../publicConfig/config.js'
export default {
options: { styleIsolation: 'shared' },
data() {
return {
userInfo: {}
}
},
onLoad: function(options) {
this.getUserInfo()
},
methods: {
//获取用户信息
getUserInfo() {
userMobileOperation('getUserInfo').then(res => {
let data = res.data.data
data.mobile = data.userExt.mobile || '暂无'
this.userInfo = { ...data }
})
},
//退出登录
exitLog() {
const _this = this
uni.showModal({
content: '确定退出当前用户吗?',
success: (res) => {
if (res.confirm) {
// #ifdef H5
const isWxBrowser = getApp().isWxBrowser()
if(!isWxBrowser){ //非微信环境跳出
_this.customTost()
return
}
// #endif
const { projectMini } = getApp().globalData
const openId = this.userInfo.userExt?.openid
const data = {openId, entryName: projectMini}
userMobileOperation('logout', data).then(res => {
if (res.data.messageType === 'success') {
_this.customTost()
}
})
} else if (res.cancel) {}
}
})
},
customTost(){
uni.showToast({
title: '退出成功!',
duration: 1000
})
uni.removeStorageSync(`${TokenPrefix}_token`)
uni.removeStorageSync(`${TokenPrefix}_XSRFToken`)
uni.removeStorageSync('cookies')
setTimeout(() => {
uni.reLaunch({
url: '/pages/login/login',
})
}, 1500)
}
}
}
</script>
<style lang="scss" scoped>
.user-content {
.user-header {
height: 288rpx;
.header-bg {
width: 100%;
height: 100%;
}
.user-info {
position: absolute;
top: 5%;
left: 4%;
font-size: 36rpx;
color: #FFFFFF;
.user_photo{
width: 160rpx;
height: 160rpx;
border: 2rpx solid #EDF5FF;
border-radius: 50%;
background-color: #DBE2FB;
image{
width: 158rpx;
height: 158rpx;
background-size: 100%;
background-position: center;
background-repeat: repeat;
}
}
.user-name {
margin-bottom: 10rpx;
}
}
}
/deep/.edit-password {
background: #FFFFFF;
padding: 40rpx;
.u-cell__body {
padding: 0;
background-color: #FFFFFF !important;
}
.u-line{
margin: 16rpx 0 !important;
}
.t-icon {
width: 60rpx;
height: 60rpx;
margin-right: 20rpx;
}
}
.exit-login {
color: #8C8C8C;
position: fixed;
/* #ifdef H5 */
bottom: 140rpx;
/* #endif */
/* #ifdef MP */
bottom: 40rpx;
/* #endif */
width: 686rpx;
height: 96rpx;
left: 50%;
transform: translateX(-50%);
border-radius: 48rpx;
border: 2rpx solid #8C8C8C;
line-height: 96rpx;
}
}
</style>
/*
BASEURL: 说明
1. 本地开发调试: 小程序修改该url即可;H5则无需关心,H5修改manifest.json中h5相关Proxy配置即可
2. 打包生产模式: 小程序切换url; H5切换ENV_MODEL
*/
let BASEURL = {
url: "http://127.0.0.1:8080", //TMS
}
//当使用多域名代理服务时生效,用于统一添加API前缀以区分服务代理地址。本地开发H5注意修改manifest.json中Proxy代理规则
// const APIPrefix = '' //TMS项目
const APIPrefix = '' //体验版测试环境: Test Master
// const APIPrefix = '/tmsdemo' //正式版环境: TMS Demo
// const APIPrefix = '/sandtable' //沙盘演示项目
// const APIPrefix = '/tmsca' //三方物流项目
//H5打包环境区分:打包时手动切换,添加新的环境变量时,注意同步修改APP.vue 和loginBehavior.js中环境判断逻辑
const ENV_MODEL = {
model: 'UAT', //测试环境
//model: 'PROD', //生产环境
}
//用于数据请求时替换所有API接口的{mini}
let MINI = {
'h5Prod': 'biz-trina5-app', //生产项目名
'h5Uat': 'biz-trina5-app', //测试项目名
'h5Dev': 'biz-trina5-app', //开发项目名
'web': 'biz-trina5-app',
'wxApp': 'biz-trina5-app', //小程序项目名
}
//仅用于H5换取用户授权Code使用,后端可用此Code换取用户OpenId等信息
let APP_ID = {
'h5Prod': 'wxd7383e6db760127c' ,//生产公众号appid
'h5Uat': 'wxd7383e6db760127c' ,//测试公众号appid
'h5Dev': 'wxd7383e6db760127c' //开发公众号appid
}
const TokenPrefix = 'carrier' // Token && XSRFToken 前缀, 避免运行于WEB端时,打开多端Token覆盖、混淆问题
module.exports = {
BASEURL,
MINI,
APP_ID,
ENV_MODEL,
TokenPrefix,
APIPrefix
}
.t-icon {
display: inline-block;
width: 16px;
height: 16px;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
.t-icon-driver {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-driver%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M530.285714%20493.714286c124.928%200%20236.562286%2056.941714%20310.345143%20146.285714H768a36.571429%2036.571429%200%200%200-32.877714%2052.626286l-60.726857%2060.708571a164.077714%20164.077714%200%200%201%2034.048%2066.870857l23.003428%200.036572L731.428571%20841.142857a36.571429%2036.571429%200%200%200%2033.828572%2036.48L768%20877.714286h164.169143c0.182857%203.858286%200.292571%207.734857%200.365714%2011.629714L932.571429%20896H128c0-6.125714%200.128-12.214857%200.402286-18.285714H292.571429a36.571429%2036.571429%200%200%200%2036.571428-36.571429v-22.674286c18.761143%200.182857%2038.857143%200.365714%2059.867429%200.530286a163.693714%20163.693714%200%200%201%2022.546285-50.761143l-83.364571-83.382857A36.571429%2036.571429%200%200%200%20292.571429%20640h-72.630858c73.782857-89.344%20185.417143-146.285714%20310.345143-146.285714z%20m393.142857%20164.571428c1.261714%200%202.486857%200.091429%203.712%200.256l0.713143-0.128%201.664-0.128c4.498286%200%208.777143%202.651429%2012.690286%207.442286l1.462857%201.481143c3.145143%203.437714%205.412571%207.643429%206.491429%2012.324571%207.826286%2018.395429%2012.891429%2047.085714%2012.891428%2079.323429s-5.065143%2060.928-12.928%2079.323428a27.081143%2027.081143%200%200%201-6.454857%2012.324572l-1.462857%201.462857c-3.913143%204.809143-8.192%207.460571-12.690286%207.460571a11.52%2011.52%200%200%201-2.377143-0.256c-1.225143%200.182857-2.450286%200.256-3.712%200.256h-146.285714a27.428571%2027.428571%200%200%201%200-54.857142H877.714286v-18.285715h-100.571429a27.428571%2027.428571%200%200%201%200-54.857143H877.714286v-18.285714h-100.571429a27.428571%2027.428571%200%200%201%200-54.857143h146.285714z%20m-646.089142%200a27.428571%2027.428571%200%200%201%200%2054.857143h-100.571429v18.285714h100.571429a27.428571%2027.428571%200%200%201%200%2054.857143h-100.571429v18.285715h100.571429a27.428571%2027.428571%200%200%201%200%2054.857142h-146.285715c-1.28%200-2.505143-0.091429-3.712-0.256l-1.188571%200.182858-1.206857%200.073142c-4.48%200-8.777143-2.651429-12.672-7.442285l-1.462857-1.481143a27.081143%2027.081143%200%200%201-6.473143-12.324572C96.475429%20819.785143%2091.428571%20791.094857%2091.428571%20758.857143s5.046857-60.928%2012.891429-79.323429c1.078857-4.681143%203.346286-8.886857%206.473143-12.324571l1.462857-1.462857c3.931429-4.809143%208.210286-7.460571%2012.690286-7.460572l1.682285%200.128%200.713143%200.128%201.828572-0.182857%201.883428-0.073143zM530.285714%20566.857143c-62.043429%200-120.100571%2017.170286-169.636571%2047.012571l103.972571%20103.972572A163.803429%20163.803429%200%200%201%20548.571429%20694.857143c23.771429%200%2046.372571%205.046857%2066.761142%2014.116571l91.062858-91.081143A327.606857%20327.606857%200%200%200%20530.285714%20566.857143z%20m-344.795428-9.069714a36.571429%2036.571429%200%200%201%2034.614857%2038.436571l-0.182857%203.291429a421.668571%20421.668571%200%200%200-31.908572%2040.813714l-43.337143-2.267429%202.377143-45.677714a36.571429%2036.571429%200%200%201%2038.436572-34.596571z%20m689.590857%200a36.571429%2036.571429%200%200%201%2038.436571%2034.596571l2.377143%2045.677714-43.337143%202.267429a421.668571%20421.668571%200%200%200-31.908571-40.813714l-0.182857-3.291429a36.571429%2036.571429%200%200%201%2034.614857-38.436571zM530.285714%2073.142857c111.085714%200%20201.142857%2090.057143%20201.142857%20201.142857s-90.057143%20201.142857-201.142857%20201.142857-201.142857-90.057143-201.142857-201.142857S419.2%2073.142857%20530.285714%2073.142857z%22%20fill%3D%22%233DCCB9%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-truck {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-truck%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M301.897143%20645.229714c48.585143%200%2087.954286%2039.753143%2087.954286%2088.813715%200%2049.042286-39.369143%2088.813714-87.954286%2088.813714-48.603429%200-87.990857-39.771429-87.990857-88.813714%200-49.060571%2039.387429-88.813714%2087.972571-88.813715z%20m545.462857%200c48.585143%200%2087.954286%2039.753143%2087.954286%2088.813715%200%2049.042286-39.369143%2088.813714-87.954286%2088.813714-48.603429%200-87.990857-39.771429-87.990857-88.813714%200-49.060571%2039.387429-88.813714%2087.990857-88.813715z%20m-545.462857%2044.397715c-24.32%200-43.995429%2019.894857-43.995429%2044.416%200%2024.521143%2019.693714%2044.397714%2043.977143%2044.397714%2024.301714%200%2043.995429-19.876571%2043.995429-44.397714s-19.693714-44.416-43.995429-44.416z%20m545.462857%200c-24.301714%200-43.995429%2019.894857-43.995429%2044.416%200%2024.521143%2019.693714%2044.397714%2043.995429%2044.397714%2024.283429%200%2043.977143-19.876571%2043.977143-44.397714s-19.693714-44.416-43.977143-44.416zM617.234286%20201.142857a36.571429%2036.571429%200%200%201%2036.571428%2036.571429v459.757714a36.571429%2036.571429%200%200%201-36.571428%2036.571429H407.460571c0-58.88-47.268571-106.587429-105.581714-106.587429-58.294857%200-105.563429%2047.725714-105.563428%20106.587429H109.714286a36.571429%2036.571429%200%200%201-36.571429-36.571429v-157.275429h236.507429a27.428571%2027.428571%200%200%200%2027.300571-24.777142l0.128-2.633143a27.428571%2027.428571%200%200%200-27.428571-27.428572l-236.525715-0.018285v-87.241143h166.144a27.428571%2027.428571%200%200%200%2027.300572-24.777143l0.128-2.651429a27.428571%2027.428571%200%200%200-27.428572-27.428571H73.124571L73.142857%20237.714286a36.571429%2036.571429%200%200%201%2036.571429-36.571429h507.52z%20m233.179428%20177.627429a36.571429%2036.571429%200%200%201%2030.134857%2015.853714l1.590858%202.56%20118.747428%20207.286857a36.571429%2036.571429%200%200%201%204.681143%2014.994286l0.146286%203.181714v74.825143a36.571429%2036.571429%200%200%201-34.413715%2035.931429l-2.724571%200.073142-15.670857-0.256-0.054857-3.273142c-2.121143-56.96-48.548571-102.491429-105.508572-102.491429-56.941714%200-103.350857%2045.531429-105.490285%20102.491429l-52.443429-0.786286a18.285714%2018.285714%200%200%201-17.883429-16.164572l-0.128-2.121142V397.056a18.285714%2018.285714%200%200%201%2016.146286-18.157714l2.139429-0.128h160.731428z%20m-32.914285%2053.302857h-75.026286a18.285714%2018.285714%200%200%200-18.285714%2018.285714v103.369143a18.285714%2018.285714%200%200%200%2018.066285%2018.285714l165.376%202.029715a9.984%209.984%200%200%200%2010.112-9.874286v-0.109714c0-6.601143-1.938286-13.056-5.577143-18.56l-64.164571-97.024a36.571429%2036.571429%200%200%200-30.500571-16.402286z%22%20fill%3D%22%232E75E6%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M36.571429%20493.714286m18.285714%200l256%200q18.285714%200%2018.285714%2018.285714l0%200q0%2018.285714-18.285714%2018.285714l-256%200q-18.285714%200-18.285714-18.285714l0%200q0-18.285714%2018.285714-18.285714Z%22%20fill%3D%22%232E75E6%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M0%20350.500571m18.285714%200l219.428572%200q18.285714%200%2018.285714%2018.285715l0%200q0%2018.285714-18.285714%2018.285714l-219.428572%200q-18.285714%200-18.285714-18.285714l0%200q0-18.285714%2018.285714-18.285715Z%22%20fill%3D%22%232E75E6%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-warn {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-warn%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M512%2096C282.272%2096%2096%20282.272%2096%20512s186.272%20416%20416%20416%20416-186.272%20416-416S741.728%2096%20512%2096z%20m58.496%20655.488c0%2031.456-25.728%2057.184-57.184%2057.184h-4.48a57.344%2057.344%200%200%201-57.184-57.184v-4.48c0-31.456%2025.728-57.184%2057.184-57.184h4.48c31.456%200%2057.184%2025.728%2057.184%2057.184v4.48z%20m0-179.136a58.56%2058.56%200%200%201-58.304%2058.304h-2.336a58.56%2058.56%200%200%201-58.304-58.304V272.8a58.56%2058.56%200%200%201%2058.304-58.304h2.336a58.56%2058.56%200%200%201%2058.304%2058.304v299.552z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-phone {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-phone%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M585.568%20624.96l5.76-2.816%203.04-1.504%203.04-1.504c5.12-2.496%209.024-4.384%2012.96-6.24%2010.496-4.896%2019.904-8.8%2029.6-12.16l0.256-0.064c27.584-9.152%2056-7.904%2084.48%203.52%2027.264%2011.008%2059.2%2035.68%2096.64%2074.048%2028.896%2029.568%2038.816%2065.44%2030.4%20103.36-7.2%2032.544-27.616%2065.504-58.24%2096.864-30.72%2031.488-72.192%2046.784-118.848%2047.04-39.936%200.224-82.24-10.784-118.08-29.568-1.568-0.832-42.464-21.76-55.904-28.992a779.52%20779.52%200%200%201-94.976-59.584c-38.432-28.16-77.216-61.984-117.728-103.488-39.2-40.128-70.848-78.272-97.376-116.256a826.88%20826.88%200%200%201-56.64-94.304c-2.016-3.744-26.24-51.264-33.12-63.872-47.68-86.848-44.416-180.864%2016.64-243.424C147.2%20155.52%20181.12%20135.04%20214.4%20128.192c37.12-7.68%2071.904%202.016%2098.496%2029.248%2040.096%2041.088%2065.088%2074.656%2075.072%20102.08%206.944%2019.136%208.704%2038.592%206.624%2057.376-1.12%209.92-3.424%2019.712-5.76%2025.92-2.176%209.856-6.368%2019.52-14.144%2034.56l-5.44%2010.432c-2.112%204.064-3.712%207.232-5.248%2010.304-12.832%2026.208-16.128%2043.2-9.792%2057.92%2018.08%2033.344%2043.616%2067.232%2076.704%20101.6%2032.832%2034.08%2065.664%2060.064%2098.4%2078.016%2014.944%205.856%2028.16%203.008%2056.256-10.656z%20m192.512-175.168c6.048%2019.808-4.672%2040.64-23.904%2046.528-19.232%205.92-39.744-5.344-45.76-25.152-23.808-78.08-81.984-138.72-155.968-165.344a38.144%2038.144%200%200%201-22.912-47.744%2035.84%2035.84%200%200%201%2046.272-22.816c95.872%2034.528%20171.424%20113.28%20202.272%20214.528z%20m168.512-46.72c6.016%2019.776-4.672%2040.64-23.936%2046.528-19.2%205.888-39.712-5.376-45.76-25.152-44.576-146.304-150.144-258.048-280.512-296.96a38.08%2038.08%200%200%201-25.408-46.4c5.376-19.84%2025.504-31.232%2044.928-25.408%20154.976%2046.272%20278.912%20177.44%20330.688%20347.392z%22%20fill%3D%22%233DCCB9%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-unloadStop {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-unloadStop%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M511.991018%201024c282.318596-195.188772%20423.468912-385.97614%20423.468912-572.308211C935.45993%20202.231018%20761.451789%200%20511.973053%200S88.54007%20202.231018%2088.54007%20451.691789C88.54007%20638.02386%20229.690386%20828.811228%20511.991018%201024z%22%20fill%3D%22%23F7A64A%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M510.715509%20422.175439m-314.385965%200a314.385965%20314.385965%200%201%200%20628.77193%200%20314.385965%20314.385965%200%201%200-628.77193%200Z%22%20fill%3D%22%23FFFFFF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-calling-card {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-calling-card%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M672%20519.584c132.544%200%20240%20105.632%20240%20235.936v78.656c0%2069.472-57.28%20125.824-128%20125.824H192c-70.72%200-128-56.32-128-125.824V755.52c0-130.304%20107.456-235.936%20240-235.936H672z%20m256-110.08c17.664%200%2032%2014.08%2032%2031.456a31.744%2031.744%200%200%201-32%2031.456h-64c-17.664%200-32-14.08-32-31.456a31.744%2031.744%200%200%201%2032-31.456h64zM672%2032c17.664%200%2032%2014.08%2032%2031.456v180.896c0%20117.248-96.704%20212.32-216%20212.32h-16c-119.296%200-216-95.04-216-212.32C256%20127.04%20352.704%2032%20472%2032H672z%20m256%20220.192c17.664%200%2032%2014.08%2032%2031.456a31.744%2031.744%200%200%201-32%2031.456h-128c-17.664%200-32-14.08-32-31.456a31.744%2031.744%200%200%201%2032-31.456h128z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-loadStop {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-loadStop%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M511.991018%201024c282.318596-195.188772%20423.468912-385.97614%20423.468912-572.308211C935.45993%20202.231018%20761.451789%200%20511.973053%200S88.54007%20202.231018%2088.54007%20451.691789C88.54007%20638.02386%20229.690386%20828.811228%20511.991018%201024z%22%20fill%3D%22%232E75E6%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M510.715509%20422.175439m-314.385965%200a314.385965%20314.385965%200%201%200%20628.77193%200%20314.385965%20314.385965%200%201%200-628.77193%200Z%22%20fill%3D%22%23FFFFFF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-picture {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-picture%22%20viewBox%3D%220%200%201076%201024%22%3E%3Cpath%20d%3D%22M535.309017%20775.671322c-121.560949%200-220.368271-97.19322-220.368271-216.775593%200-119.582373%2098.807322-216.775593%20220.368271-216.775593%20121.578305%200%20220.368271%2097.19322%20220.368271%20216.775593%200%20119.460881-98.789966%20216.775593-220.368271%20216.775593z%20m0-357.323932c-78.813288%200-142.874034%2063.002034-142.874034%20140.548339%200%2077.546305%2064.04339%20140.548339%20142.874034%20140.548339s142.89139-63.002034%20142.89139-140.548339c0-77.528949-64.060746-140.548339-142.89139-140.548339z%20m331.290034-79.559593h-92.021153c-21.313085%200-38.755797-17.147661-38.755796-38.113628%200-20.965966%2017.442712-38.113627%2038.755796-38.113627h92.021153c21.313085%200%2038.738441%2017.147661%2038.738441%2038.113627%200%2020.965966-17.425356%2038.113627-38.738441%2038.113628z%20m170.730305%20480.360135h-92.038509V728.602034c0-20.965966-17.425356-38.113627-38.73844-38.113627-21.313085%200-38.738441%2017.147661-38.738441%2038.113627v90.528542h-92.021152c-21.313085%200-38.755797%2017.147661-38.755797%2038.113627%200%2020.94861%2017.442712%2038.113627%2038.755797%2038.113628H867.79661v90.511186C867.79661%201006.852339%20885.239322%201024%20906.552407%201024c21.313085%200%2038.738441-17.147661%2038.73844-38.113627v-90.511187h92.038509c21.295729%200%2038.738441-17.165017%2038.738441-38.113627%200-20.965966-17.442712-38.113627-38.738441-38.113627z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M657.685695%20933.905356c0-20.792407-17.217085-37.575593-38.53017-37.575593H192.581424a116.215322%20116.215322%200%200%201-81.607593-33.132475c-21.903186-21.365153-33.948203-49.672678-33.948204-79.611661V320.859119c0-29.956339%2012.045017-58.263864%2033.948204-79.629017a116.215322%20116.215322%200%200%201%2081.607593-33.115119h83.169627l44.188203-120.502237c2.776949-7.515119%209.979661-12.444203%2018.171661-12.444204h399.967458c8.070508%200%2015.412068%205.03322%2018.171661%2012.444204l44.066712%20120.380746h83.169627c30.685288%200%2059.704407%2011.749966%2081.607593%2033.115118%2021.903186%2021.486644%2033.948203%2049.811525%2033.948203%2079.750509V552.786441c0%2020.792407%2017.199729%2037.575593%2038.512814%2037.575593%2021.295729%200%2038.512814-16.783186%2038.512814-37.575593V320.859119C1076.067797%20217.035932%20989.878237%20132.946441%20883.486373%20132.946441h-28.897627l-25.756204-70.586577C815.242847%2025.009898%20778.760678%200%20738.199864%200h-400.227796c-40.664949%200-77.025627%2025.009898-90.615322%2062.359864L221.461695%20132.946441h-28.897627C86.189559%20132.946441%200%20217.035932%200%20320.859119v462.709152c0%20103.823186%2086.189559%20187.912678%20192.581424%20187.912678h426.574101c21.174237%200%2038.530169-16.904678%2038.53017-37.575593z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-address {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-address%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M128%20912a384%2048%200%201%200%20768%200%20384%2048%200%201%200-768%200Z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M496%20199.424c76.544%200%20138.56%2062.816%20138.56%20140.288%200%2077.504-62.016%20140.32-138.56%20140.32-76.544%200-138.56-62.816-138.56-140.32%200-77.472%2062.016-140.288%20138.56-140.288z%20m304%20140.352c0-131.424-82.464-248.352-205.216-291.072C472%206.016%20335.968%2046.944%20256.192%20150.624a310.88%20310.88%200%200%200-14.816%20357.312l227.424%20306.976A30.4%2030.4%200%200%200%20496%20832a30.4%2030.4%200%200%200%2027.232-17.088l227.84-306.976A313.248%20313.248%200%200%200%20800%20339.776z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-cargoQty {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-cargoQty%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M928%20304V832a64%2064%200%200%201-64%2064H160a64%2064%200%200%201-64-64V304h832zM512%20704H256a32%2032%200%200%200%200%2064h256a32%2032%200%200%200%200-64z%20m-58.176-128H256a32%2032%200%200%200%200%2064h197.824a32%2032%200%200%200%200-64zM748.032%2096a64%2064%200%200%201%2050.624%2024.832L915.616%20272H526.976V96z%20m-253.056%200v176H108.416l116.928-151.168a64%2064%200%200%201%2045.248-24.608L275.968%2096h219.008z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-success {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-success%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M512%20512m-512%200a512%20512%200%201%200%201024%200%20512%20512%200%201%200-1024%200Z%22%20fill%3D%22%2327C488%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M411.426133%20603.025067L262.3744%20480.580267%20196.266667%20536.0896%20454.024533%20810.666667c44.637867-118.877867%20185.1392-351.3856%20356.872534-516.6336L795.170133%20256c-187.101867%20120.004267-322.6624%20270.9504-383.744%20347.025067z%22%20fill%3D%22%23FFFFFF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-navigation {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-navigation%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M66.016%20505.344l311.264%20141.376%20141.376%20311.264a32%2032%200%200%200%2058.56-0.64l351.296-819.84a32%2032%200%200%200-42.048-42.016L66.624%20446.784a32%2032%200%200%200-0.608%2058.56z%22%20fill%3D%22%235798F2%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-fold-blue {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-fold-blue%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M538.624%20760.064L862.848%20273.76A32%2032%200%200%200%20836.16%20224H187.84a32%2032%200%200%200-26.656%2049.76l324.224%20486.304a32%2032%200%200%200%2053.248%200z%22%20fill%3D%22%232E75E6%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-rightArrow {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-rightArrow%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M402.095635%20875.537544a48%2048%200%201%201-67.882251-67.882251L648.146168%20493.72251l-314.113803-314.113803a48%2048%200%200%201%2067.882251-67.882251L749.562251%20459.374091c5.634227%205.634227%209.594025%2012.309315%2011.811511%2019.414323%205.52109%2016.653779%201.651801%2035.819201-11.630492%2049.101495l-347.647635%20347.647635z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-fold {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-fold%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M538.624%20760.064L862.848%20273.76A32%2032%200%200%200%20836.16%20224H187.84a32%2032%200%200%200-26.656%2049.76l324.224%20486.304a32%2032%200%200%200%2053.248%200z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-cancel {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-cancel%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M881.024%20825.376L584.32%20528.64l296.704-296.736c9.664-9.664%2014.976-22.528%2014.976-36.192%200-13.664-5.312-26.464-14.944-36.064a50.688%2050.688%200%200%200-36.128-15.008c-13.696%200-26.56%205.312-36.192%2014.976L512%20456.32%20215.264%20159.616a50.784%2050.784%200%200%200-36.16-14.976c-13.632%200-26.464%205.312-36.128%2014.976C133.312%20169.28%20128%20182.08%20128%20195.712c0%2013.664%205.312%2026.528%2014.976%2036.192l296.768%20296.736-296.768%20296.736A50.784%2050.784%200%200%200%20128%20861.536c0%2013.632%205.312%2026.464%2014.976%2036.128%209.664%209.664%2022.496%2014.976%2036.16%2014.976%2013.632%200%2026.464-5.312%2036.16-14.976L512%20600.96l296.704%20296.704c9.664%209.664%2022.496%2014.976%2036.16%2014.976a51.2%2051.2%200%200%200%2036.128-87.264z%22%20fill%3D%22%238C8C8C%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-unfold-blue {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-unfold-blue%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M538.624%20263.936l324.224%20486.304A32%2032%200%200%201%20836.16%20800H187.84a32%2032%200%200%201-26.656-49.76L485.376%20263.936a32%2032%200%200%201%2053.248%200z%22%20fill%3D%22%232E75E6%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-unfold {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-unfold%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M538.624%20263.936l324.224%20486.304A32%2032%200%200%201%20836.16%20800H187.84a32%2032%200%200%201-26.656-49.76L485.376%20263.936a32%2032%200%200%201%2053.248%200z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-order {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-order%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M640%2064a64%2064%200%200%201%2063.893333%2060.245333L704%20128h85.312a64%2064%200%200%201%2064%2064v703.978667a64%2064%200%200%201-64%2064H234.666667a64%2064%200%200%201-64-64V192a64%2064%200%200%201%2064-64h106.666666a64%2064%200%200%201%2064-64h234.666667z%20m0%20149.333333H405.333333a64.021333%2064.021333%200%200%201-60.352-42.666666H245.333333a32%2032%200%200%200-31.850666%2028.928L213.333333%20202.666667v682.666666a32%2032%200%200%200%2028.928%2031.850667L245.333333%20917.333333h533.333334a32%2032%200%200%200%2031.850666-28.928L810.666667%20885.333333v-682.666666A32%2032%200%200%200%20778.666667%20170.666667h-78.314667A64.021333%2064.021333%200%200%201%20640%20213.333333z%20m0.661333-106.666666h-234.666666a21.333333%2021.333333%200%200%200-21.184%2018.837333L384.661333%20128v21.333333a21.333333%2021.333333%200%200%200%2018.858667%2021.184L405.973333%20170.666667h234.666667a21.333333%2021.333333%200%200%200%2021.205333-18.837334L661.973333%20149.333333V128a21.333333%2021.333333%200%200%200-21.333333-21.333333z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M522.666667%20682.666667a32%2032%200%200%201%200%2064h-234.666667a32%2032%200%200%201%200-64h234.666667z%20m213.333333-170.666667a32%2032%200%200%201%200%2064h-448a32%2032%200%200%201%200-64h448z%20m0-170.666667a32%2032%200%200%201%200%2064h-448a32%2032%200%200%201%200-64h448z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-leftArrow {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-leftArrow%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M590.031165%20907.540441a48%2048%200%201%200%2067.882251-67.882251L343.980632%20525.725407l314.113803-314.113803a48%2048%200%200%200-67.882251-67.882251L242.564549%20491.376988c-5.634227%205.634227-9.594025%2012.309315-11.811511%2019.414323-5.52109%2016.653779-1.651801%2035.819201%2011.630492%2049.101495l347.647635%20347.647635z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-clock {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-clock%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M512%2096c229.76%200%20416%20186.24%20416%20416a416%20416%200%200%201-416%20416C282.24%20928%2096%20741.76%2096%20512S282.24%2096%20512%2096z%20m-3.296%20151.296c-22.08%200-40%2017.92-40%2040v236c0%2010.688%204.16%2020.384%2011.04%2027.584%207.264%207.744%2017.6%2012.576%2029.12%2012.576h184a40%2040%200%201%200%200-80l-144.16-0.032V287.296c0-22.08-17.92-40-40-40z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-user-photo {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-user-photo%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M0%200h1024v1024H0z%22%20fill%3D%22%232E75E6%22%20fill-opacity%3D%220%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M501.967238%20318.537143c103.972571%200%20191.567238%2073.033143%20218.026667%20172.513524%201.755429-0.121905%203.535238-0.182857%205.321143-0.182857%2039.533714%200%2071.588571%2030.86019%2071.588571%2068.924952%200%2038.070857-32.054857%2068.937143-71.588571%2068.937143-2.907429%200-5.77219-0.170667-8.594286-0.493715-23.326476%2073.264762-80.292571%20130.578286-151.838476%20152.100572v40.338286c0%2015.481905%2023.887238%2030.006857%2071.667809%2043.562666-40.880762%2065.097143-87.015619%2097.65181-138.398476%2097.65181s-100.693333-30.439619-147.943619-91.306667c50.602667-21.723429%2075.904-38.357333%2075.904-49.907809v-44.678096c-65.438476-24.246857-116.992-78.969905-138.910476-147.766857-2.80381%200.329143-5.668571%200.493714-8.582095%200.493715-39.533714%200-71.582476-30.86019-71.582477-68.931048%200-38.064762%2032.048762-68.931048%2071.582477-68.931048%201.792%200%203.565714%200.060952%205.321142%200.188953%2026.465524-99.474286%20114.054095-172.513524%20218.026667-172.513524z%22%20fill%3D%22%23FFFFFF%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M496.158476%20900.059429c67.523048%200%20123.196952-17.450667%20131.029334-39.960381l-5.778286-1.603048c56.484571%2015.451429%20109.257143%2035.669333%20158.311619%2060.647619-92.611048%2085.638095-213.717333%2094.445714-285.854476%2094.445714-72.143238%200-218.209524-21.955048-263.92381-94.445714%2018.724571-20.967619%2063.670857-41.039238%20134.826667-60.196571%206.302476%2023.064381%2062.72%2041.112381%20131.388952%2041.112381z%22%20fill%3D%22%234282E8%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M295.009524%20639.573333c-19.08419-12.501333-61.519238-79.847619-74.648381-170.715428C207.238095%20377.99619%20263.375238%20256.512%20379.062857%20205.549714c115.675429-50.95619%20243.474286-33.621333%20260.815238%2017.615238%2075.056762%2019.260952%20125.257143%2076.422095%20141.190095%20152.880762%2015.932952%2076.458667-11.702857%20196.358095-80.66438%20275.657143%2020.736-51.139048%2012.635429-173.921524-60.525715-253.177905-34.224762%2075.654095-141.433905%2087.30819-178.517333%2087.308191-37.089524%200-154.544762%2028.452571-166.351238%20153.74019z%22%20fill%3D%22%236C9EED%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-warning {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-warning%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M512%2096C282.272%2096%2096%20282.272%2096%20512s186.272%20416%20416%20416%20416-186.272%20416-416S741.728%2096%20512%2096z%20m58.496%20655.488c0%2031.456-25.728%2057.184-57.184%2057.184h-4.48a57.344%2057.344%200%200%201-57.184-57.184v-4.48c0-31.456%2025.728-57.184%2057.184-57.184h4.48c31.456%200%2057.184%2025.728%2057.184%2057.184v4.48z%20m0-179.136a58.56%2058.56%200%200%201-58.304%2058.304h-2.336a58.56%2058.56%200%200%201-58.304-58.304V272.8a58.56%2058.56%200%200%201%2058.304-58.304h2.336a58.56%2058.56%200%200%201%2058.304%2058.304v299.552z%22%20fill%3D%22%23F7A64A%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-platform {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-platform%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M519.36%20166.4l358.144%20166.592a32%2032%200%200%201%2018.496%2029.024V864a32%2032%200%200%201-32%2032H160a32%2032%200%200%201-32-32V361.728a32%2032%200%200%201%2018.144-28.832l345.824-166.336a32%2032%200%200%201%2027.392-0.16z%20m-94.656%20581.28H288V864h136.704v-116.32z%20m155.872%200h-136.704V864h136.704v-116.32z%20m155.424%200h-136.704V864H736v-116.32zM490.688%20608h-136.704v116.32h136.704V608z%20m158.24%200h-136.704v116.32h136.704V608z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-a-yundan-012x {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-a-yundan-012x%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M274.285714%20658.285714a91.428571%2091.428571%200%201%201%200%20182.857143%2091.428571%2091.428571%200%200%201%200-182.857143z%20m566.857143%200a91.428571%2091.428571%200%201%201%200%20182.857143%2091.428571%2091.428571%200%200%201%200-182.857143z%20m-566.857143%2045.714286a45.714286%2045.714286%200%201%200%200%2091.428571%2045.714286%2045.714286%200%200%200%200-91.428571z%20m566.857143%200a45.714286%2045.714286%200%201%200%200%2091.428571%2045.714286%2045.714286%200%200%200%200-91.428571zM603.428571%20201.142857a36.571429%2036.571429%200%200%201%2036.571429%2036.571429v475.428571a36.571429%2036.571429%200%200%201-36.571429%2036.571429H384a109.714286%20109.714286%200%201%200-219.428571%200H73.142857a36.571429%2036.571429%200%200%201-36.571428-36.571429V237.714286a36.571429%2036.571429%200%200%201%2036.571428-36.571429h530.285714z%20m241.828572%20182.857143a36.571429%2036.571429%200%200%201%2030.043428%2015.725714l1.609143%202.541715%20123.885715%20214.272a36.571429%2036.571429%200%200%201%204.772571%2015.104l0.146286%203.2v77.732571a36.571429%2036.571429%200%200%201-34.395429%2036.516571l-2.742857%200.054858-17.737143-0.292572-0.054857-3.254857a109.714286%20109.714286%200%200%200-219.282286-0.091429l-55.222857-0.822857a18.285714%2018.285714%200%200%201-17.865143-16.182857L658.285714%20726.4V402.285714a18.285714%2018.285714%200%200%201%2016.146286-18.157714L676.571429%20384h168.685714z%20m-34.267429%2054.857143H731.428571a18.285714%2018.285714%200%200%200-18.285714%2018.285714v107.483429a18.285714%2018.285714%200%200%200%2018.066286%2018.285714l172.672%202.102857a10.294857%2010.294857%200%200%200%2010.404571-10.276571c0-6.802286-2.011429-13.44-5.778285-19.090286l-67.108572-100.516571a36.571429%2036.571429%200%200%200-30.409143-16.274286z%22%20fill%3D%22%23BFBFBF%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-lock {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-lock%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M493.714286%20146.285714c100.992%200%20182.857143%2081.883429%20182.857143%20182.875429a30.482286%2030.482286%200%200%201-60.946286%200%20121.910857%20121.910857%200%200%200-243.657143-6.089143l-0.164571%206.089143V384h351.104L493.714286%20653.385143%20471.113143%20731.428571l8.96%2016.768c2.834286%202.56%2015.634286%206.345143%2021.211428%206.710858l1.572572-0.018286%2084.004571-30.592L841.142857%20425.398857V841.142857a36.571429%2036.571429%200%200%201-36.571428%2036.571429H201.142857a36.571429%2036.571429%200%200%201-36.571428-36.571429V420.571429a36.571429%2036.571429%200%200%201%2036.571428-36.571429h109.714286v-54.838857C310.857143%20228.169143%20392.722286%20146.285714%20493.714286%20146.285714z%20m341.394285%20195.364572l2.450286%202.011428c7.68%205.668571%2012.507429%2014.482286%2013.184%2024.100572a33.042286%2033.042286%200%200%201-9.6%2025.782857L575.451429%20704.694857l-71.259429%2026.642286a13.275429%2013.275429%200%200%201-10.477714-3.328v-3.346286l23.954285-66.523428%20265.691429-311.149715a38.290286%2038.290286%200%200%201%2051.748571-5.339428z%22%20fill%3D%22%23F7A64A%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-correct {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-correct%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M380.342857%20801.645714a53.394286%2053.394286%200%200%201-36.571428-16.091428l-218.331429-217.234286a55.588571%2055.588571%200%200%201%200-77.165714%2054.125714%2054.125714%200%200%201%2076.8%200l178.102857%20179.2L835.291429%20272.091429a53.394286%2053.394286%200%200%201%2076.434285%200%2054.125714%2054.125714%200%200%201%200%2076.8L418.742857%20785.554286a54.491429%2054.491429%200%200%201-38.4%2016.091428z%22%20fill%3D%22%234C73FD%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-search {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-search%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M812.137931%20406.068966C812.137931%20181.803269%20630.334658%200%20406.068966%200%20181.803273%200%200%20181.803269%200%20406.068966%200%20630.334662%20181.803273%20812.137931%20406.068966%20812.137931%20630.334658%20812.137931%20812.137931%20630.334662%20812.137931%20406.068966ZM70.62069%20406.068966C70.62069%20220.805999%20220.806003%2070.62069%20406.068966%2070.62069%20591.331928%2070.62069%20741.517241%20220.805999%20741.517241%20406.068966%20741.517241%20591.331932%20591.331928%20741.517241%20406.068966%20741.517241%20220.806003%20741.517241%2070.62069%20591.331932%2070.62069%20406.068966ZM963.201748%201013.13812C976.991303%201026.927667%20999.348577%201026.927667%201013.138114%201013.13812%201026.927669%20999.348572%201026.927669%20976.991299%201013.138114%20963.201751L713.519916%20663.583539C699.730361%20649.793993%20677.373087%20649.793993%20663.583532%20663.583539%20649.793995%20677.373087%20649.793995%20699.730361%20663.583532%20713.519909L963.201748%201013.13812Z%22%20fill%3D%22%23929292%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-show_password {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-show_password%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M511.5%20746c168.708%200%20321.167-90.915%20402.8-234-81.633-143.085-234.092-234-402.8-234s-321.167%2090.915-402.8%20234c81.633%20143.085%20234.092%20234%20402.8%20234zM19.504%20492.075C112.844%20308.295%20301.634%20190%20511.5%20190c209.867%200%20398.655%20118.296%20491.996%20302.075l10.12%2019.925-10.12%2019.925C910.156%20715.705%20721.366%20834%20511.5%20834c-209.867%200-398.655-118.296-491.996-302.075L9.384%20512l10.12-19.925zM512%20671c-87.813%200-159-71.187-159-159s71.187-159%20159-159%20159%2071.187%20159%20159-71.187%20159-159%20159z%20m0-88c39.212%200%2071-31.788%2071-71s-31.788-71-71-71-71%2031.788-71%2071%2031.788%2071%2071%2071z%22%20%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-hide_password {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-hide_password%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M816.735%20392.609c23.948-16.884%2048.504-34.194%2073.666-51.93%2045.496%2043.008%2083.948%2094.01%20113.095%20151.396l10.12%2019.925-10.12%2019.925C910.156%20715.705%20721.366%20834%20511.5%20834c-85.629%200-167.748-19.693-241.308-55.493a126426.42%20126426.42%200%200%201%2084.456-59.764C403.996%20736.477%20456.897%20746%20511.5%20746c168.708%200%20321.167-90.915%20402.8-234a464.333%20464.333%200%200%200-97.565-119.391z%20m-139.41-84.022C625.44%20288.718%20569.427%20278%20511.5%20278c-168.708%200-321.167%2090.915-402.8%20234a464.315%20464.315%200%200%200%20103.832%20124.777%2065416.053%2065416.053%200%200%200-73.757%2052.294c-48.197-44.187-88.815-97.18-119.27-157.146L9.384%20512l10.12-19.925C112.844%20308.295%20301.632%20190%20511.5%20190c88.831%200%20173.886%2021.194%20249.525%2059.577a862427.371%20862427.371%200%200%200-83.7%2059.01zM443.857%20655.699A429587.844%20429587.844%200%200%201%20670.2%20495.944c0.53%205.28%200.801%2010.636%200.801%2016.056%200%2087.813-71.187%20159-159%20159-24.386%200-47.49-5.49-68.143-15.301z%20m-89.033-119.54A160.242%20160.242%200%200%201%20353%20512c0-87.813%2071.187-159%20159-159%2027.292%200%2052.977%206.876%2075.419%2018.99-40.078%2028.27-77.89%2054.947-113.456%2080.048a71.196%2071.196%200%200%200-5.619%203.965%20321235.405%20321235.405%200%200%200-113.52%2080.155zM115.39%20851.515c-19.018%2015.127-46.698%2011.973-61.825-7.045-15.127-19.018-11.973-46.698%207.045-61.825%2016.64-13.236%20299.253-213.08%20864.8-611.613%2019.864-13.998%2047.314-9.242%2061.312%2010.622%2013.998%2019.864%209.242%2047.314-10.622%2061.312-553.782%20390.242-846.339%20597.118-860.71%20608.549z%22%20%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-a-zhuang2x1 {
background-image: url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M511.99 1024c282.32-195.19 423.47-385.98 423.47-572.31C935.46 202.23 761.45 0 511.97 0S88.54 202.23 88.54 451.69C88.54 638.02 229.69 828.81 511.99 1024z' fill='%232e75e6'/%3E%3Cpath d='M510.72 422.18m-314.39 0a314.39 314.39 0 1 0 628.77 0 314.39 314.39 0 1 0-628.77 0Z' fill='%23ffffff'/%3E%3Cpath d='M669.88 383.80v-25.69h-71.91v-58.49h82.00v-25.69h-82.00v-45.85H569.10v45.85h-84.18v25.69h84.18v58.49h-71.93v25.69h172.71z m-209.06 23.32v-177.85h-28.85v93.67c-27.67 15.81-60.47 30.04-98.02 41.89l11.07 25.69c33.20-12.25 62.05-25.69 86.95-39.92v56.52h28.85z m-57.70-99.60l14.62-22.53a304.67 304.67 0 0 0-62.05-39.13l-15.02 22.13c21.34 9.49 41.89 22.53 62.45 39.52z m268.76 284.56l16.20-24.90c-33.59-10.28-62.84-24.11-87.74-42.29a290.26 290.26 0 0 0 57.70-45.45l-20.16-17.79c-15.81 17.39-35.18 33.20-57.70 47.03a225.98 225.98 0 0 1-43.08-53.36h147.42v-26.09h-151.77a245.89 245.89 0 0 0-22.13-37.94l-26.09 8.70c7.11 9.09 13.44 18.97 18.97 29.25h-169.16v26.09H480.18c-31.62 27.67-80.63 50.59-147.82 68.37l14.62 24.11a641.06 641.06 0 0 0 73.12-28.85v33.20c0 6.32-4.35 11.07-12.65 14.23l5.93 24.50c48.61-9.49 90.11-18.97 124.50-29.25l-4.74-25.29a792.34 792.34 0 0 1-86.95 22.92V505.53c26.09-15.41 47.43-32.01 64.03-50.19 33.20 65.61 86.95 111.06 161.65 136.75z' fill='%232e75e6'/%3E%3C/svg%3E");
}
.t-icon-a-xie2x1 {
background-image: url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M511.99 1024c282.32-195.19 423.47-385.98 423.47-572.31C935.46 202.23 761.45 0 511.97 0S88.54 202.23 88.54 451.69C88.54 638.02 229.69 828.81 511.99 1024z' fill='%23f7a64a'/%3E%3Cpath d='M510.72 422.18m-314.39 0a314.39 314.39 0 1 0 628.77 0 314.39 314.39 0 1 0-628.77 0Z' fill='%23ffffff'/%3E%3Cpath d='M338.31 572.72c67.98-9.88 131.22-22.13 189.71-36.76V509.48c-23.71 5.53-47.82 11.07-72.33 15.81v-66.40h60.47v-26.09h-60.47v-47.03h69.56v-27.27h-69.56v-64.03h62.05V268.40h-118.96c3.95-9.88 7.51-20.55 11.07-32.01l-24.90-9.88c-11.46 41.10-28.46 73.51-50.59 98.02l20.55 17.79c11.86-13.04 22.53-28.85 32.01-47.82h40.31v64.03h-92.48v27.27h92.48v144.65c-13.83 2.37-27.67 4.35-41.89 6.72v-116.99h-27.27v120.54l-26.88 3.16 7.11 28.85z m237.14 16.20V288.95h65.61v207.89c0 12.25-5.14 18.58-15.41 18.58l-32.41-1.19 7.90 28.06h33.59c22.53 0 33.99-13.44 33.99-39.52V262.07h-122.13v326.85h28.85z' fill='%23f7a64a'/%3E%3C/svg%3E");
}
.t-icon-start-sddress {
background-image: url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M512 512m-460.8 0a460.8 460.8 0 1 0 921.6 0 460.8 460.8 0 1 0-921.6 0Z' fill='%232e75e6'/%3E%3Cpath d='M314.60 735.08c13.31-29.70 23.55-61.44 31.74-95.74 19.46 30.72 42.50 52.74 68.61 65.02 28.75 13.39 100.30 20.56 213.66 20.99h123.75l6.14-35.84c-25.93 1.46-64.90 2.43-116.48 2.56h-10.50c-93.70 0-156.67-4.61-188.42-13.31v-96.26h72.70v-33.79h-72.70v-72.19h78.85v-33.79h-88.58v-75.26h81.92v-33.79h-81.92v-69.12h-36.86v69.12h-84.48v33.79h84.48v75.26h-93.70v33.79h104.96v184.83c-20.48-14.34-37.89-35.84-53.25-64.51 4.10-26.62 6.66-54.27 7.68-83.46l-33.28-4.10c-2.56 74.24-16.90 141.31-42.50 200.70l28.16 25.09z m368.64-93.18c24.06 0 39.94-6.66 47.62-18.94 8.19-12.29 14.34-39.42 17.41-80.90l-34.82-11.78c-2.05 29.70-4.61 49.66-8.19 59.39-4.61 10.75-14.34 16.38-28.67 16.38h-69.63c-14.34-0.51-21.50-7.68-21.50-21.50v-117.76h138.24v-168.45h-183.81v34.30h147.97v98.82h-139.26v166.4c0 29.18 14.34 44.03 43.52 44.03h91.14z' fill='%23ffffff'/%3E%3C/svg%3E");
}
.t-icon-end-sddress {
background-image: url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M512 512m-460.8 0a460.8 460.8 0 1 0 921.6 0 460.8 460.8 0 1 0-921.6 0Z' fill='%23f7a64a'/%3E%3Cpath d='M306.92 605.03c40.96-6.14 84.48-17.92 129.54-34.82v-33.28c-28.67 11.26-57.86 20.48-86.53 27.65 29.70-38.91 67.07-104.96 112.64-198.14l-32.26-11.78c-11.26 23.55-22.02 46.08-32.26 67.07-22.02 4.10-44.03 7.68-66.05 10.24 26.62-38.91 52.22-90.11 77.31-154.62l-34.30-13.31c-20.48 59.39-44.03 111.62-71.68 157.70-4.10 6.66-9.22 11.26-14.85 13.31l8.70 33.79c28.16-4.10 56.32-9.22 84.48-14.34-26.62 50.18-49.15 85.50-68.10 106.50-4.61 4.10-10.24 7.68-16.38 10.24l9.73 33.79z m158.21-45.06c56.32-19.46 105.47-46.59 147.97-81.92 38.4 29.70 81.41 55.30 128.51 75.78l18.94-33.28c-45.06-18.43-85.50-40.96-121.86-66.56 30.72-31.23 56.83-67.58 78.85-109.57v-30.21h-146.94c5.63-14.34 10.75-29.70 15.36-45.57l-37.38-4.61a303.87 303.87 0 0 1-90.11 146.43l23.04 30.21c15.36-14.34 29.70-29.70 42.50-46.08 18.43 21.50 38.91 41.98 60.93 60.42-39.94 31.74-85.50 55.81-137.73 72.19l17.92 32.77z m145.41-127.49c-24.58-19.97-47.10-41.47-67.07-65.02 3.07-5.63 6.66-11.26 10.24-17.41h121.86c-18.94 30.72-40.45 58.37-65.02 82.43z m73.22 193.02l18.43-28.16c-41.98-22.53-89.09-41.98-140.29-57.86l-18.94 28.16c48.13 14.34 94.72 33.28 140.8 57.86z m20.99 109.57l19.46-30.72c-67.58-30.72-142.34-56.32-224.26-77.82l-20.48 30.72c76.8 18.94 152.06 45.06 225.28 77.82z m-408.58-20.99c59.90-11.26 113.66-25.6 160.77-43.01v-37.38c-47.62 17.41-102.91 31.74-165.89 41.98l5.12 38.4z' fill='%23ffffff'/%3E%3C/svg%3E");
}
.t-icon-baocun {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-baocun%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M888%20104a32%2032%200%200%201%2032%2032v752a32%2032%200%200%201-32%2032H136a32%2032%200%200%201-32-32V136a32%2032%200%200%201%2032-32h752z%20m-32%2064H168v688h688V168z%20m-152.636%20181.612a8%208%200%200%201%206.868%2012.104l-0.36%200.552-213.132%20298.044h-0.168a31.976%2031.976%200%200%201-26.912%2014.688%2031.92%2031.92%200%200%201-23.984-10.816l-3.628-5-0.492-0.876-1.812-2.52h-0.168L313.468%20482.08a8%208%200%200%201%206.976-12.68l63.268%203.976a8%208%200%200%201%205.968%203.28l80.232%20110.32%20170.24-234.068a8%208%200%200%201%205.772-3.264l0.696-0.032h56.744z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-bianji {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-bianji%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M492.2%20120a32%2032%200%200%201%201%2063.984l-1%200.016H164a16%2016%200%200%200-16%2016v664a16%2016%200%200%200%2016%2016h664a16%2016%200%200%200%2016-16v-325.336a32%2032%200%200%201%2031-31.984l1-0.016a32%2032%200%200%201%2031.984%2031.004l0.016%201v343.528c0%2033.712-26.992%2061.12-60.544%2061.792l-1.26%200.012H145.804c-33.712%200-61.12-26.992-61.792-60.544L84%20882.2V181.804c0-33.712%2026.992-61.12%2060.544-61.792L145.8%20120h346.4z%20m289.164%204.112l115.964%20115.964a16%2016%200%200%201%200%2022.628L474.924%20685.112a16%2016%200%200%201-11.316%204.684h-115.96a16%2016%200%200%201-16-16v-115.964a16%2016%200%200%201%204.68-11.312L758.74%20124.112a16%2016%200%200%201%2022.628%200z%20m-11.316%2079.192l-374.4%20374.408v48.08h48.08l374.404-374.4-48.08-48.088z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-quxiao {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-quxiao%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M888%20104a32%2032%200%200%201%2032%2032v752a32%2032%200%200%201-32%2032H136a32%2032%200%200%201-32-32V136a32%2032%200%200%201%2032-32h752z%20m-48%2064H184a16%2016%200%200%200-16%2016v656a16%2016%200%200%200%2016%2016h656a16%2016%200%200%200%2016-16V184a16%2016%200%200%200-16-16z%20m-225.876%20180.028l63.392%200.44a8%208%200%200%201%206.476%2012.62l-0.4%200.52-128.152%20152.828%20128.028%20152.42a8%208%200%200%201-6.128%2013.144h-64.212a8%208%200%200%201-6.128-2.86l-94-112.096-93.988%20112.096a8%208%200%200%201-5.424%202.828l-0.708%200.032H348.668a8%208%200%200%201-6.524-12.624l0.4-0.52%20128.024-152.424-128.148-152.824a8%208%200%200%201%206.076-13.14l63.392-0.44a8%208%200%200%201%206.18%202.852l94.936%20113.028%2094.94-113.028a8%208%200%200%201%205.468-2.828l0.712-0.024z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-view-track {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-view-track%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M224.044%20647.88c20.688%200%2037.452%2016.912%2037.452%2037.772%200%2020.864-16.764%2037.772-37.452%2037.772H140.572c-18.252%200-33.672%2012.92-33.672%2028.22v2.316c0%2015.296%2015.42%2028.216%2033.672%2028.216h130.08c0.272-0.008%200.544-0.008%200.816-0.008h611.96c59.868%200%20108.572%2046.544%20108.572%20103.76v2.312c0%2057.224-48.712%20103.76-108.572%20103.76H271.468c-20.684%200-37.448-16.908-37.448-37.772%200-20.86%2016.76-37.768%2037.448-37.768h611.96c18.252%200%2033.672-12.92%2033.672-28.22v-2.316c0-15.296-15.42-28.216-33.672-28.216h-130.08a37.84%2037.84%200%200%201-0.816%200.008H140.572C80.704%20857.72%2032%20811.172%2032%20753.96v-2.312c0-57.212%2048.704-103.76%20108.572-103.76h83.472zM512%2032c37.904%200%2074.86%208.132%20109.836%2024.152%2033.08%2015.16%2062.912%2036.668%2088.664%2063.92a299.268%20299.268%200%200%201%2059.416%2091.88c14.536%2035.3%2021.92%2072.124%2021.92%20109.456%200%2037.376-14.056%2079.864-42.968%20129.892-21.22%2036.704-50.54%2077.348-87.14%20120.784-31.96%2037.92-63.68%2071.148-87.12%2094.636l-2.672%202.668c-20.16%2020.108-33.612%2032.44-34.784%2033.512a37.224%2037.224%200%200%201-25.152%209.788%2037.148%2037.148%200%200%201-25.152-9.788c-2.552-2.328-63.1-57.9-124.576-130.816-36.612-43.436-65.932-84.068-87.14-120.784-28.912-50.04-42.968-92.52-42.968-129.892%200-37.32%207.372-74.148%2021.92-109.452a299.448%20299.448%200%200%201%2059.416-91.88c25.752-27.256%2055.584-48.764%2088.664-63.92C437.14%2040.12%20474.096%2032%20512%2032z%20m0%2075.54c-109.176%200-204.936%2099.944-204.936%20213.868%200%2025.596%2014.584%2085.848%20112.28%20201.756%2029.9%2035.472%2059.944%2066.956%2082.208%2089.296l3.128%203.128c2.56%202.556%205.004%204.976%207.32%207.256%2022.836-22.48%2058.196-58.72%2093.168-100.28%2097.252-115.536%20111.776-175.62%20111.776-201.156-0.008-113.936-95.768-213.868-204.944-213.868z%20m0%2065.5c67.08%200%20121.66%2055.048%20121.66%20122.704%200%2067.66-54.576%20122.696-121.66%20122.696-67.08%200-121.66-55.044-121.66-122.704S444.916%20173.04%20512%20173.04z%20m0%2075.544c-25.78%200-46.76%2021.16-46.76%2047.16%200%2026%2020.98%2047.164%2046.76%2047.164%2025.78%200%2046.76-21.16%2046.76-47.16%200-26.004-20.98-47.164-46.76-47.164z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
.t-icon-location {
background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20version%3D%221.1%22%20width%3D%27100%25%27%20height%3D%27100%25%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20id%3D%22t-icon-location%22%20viewBox%3D%220%200%201024%201024%22%3E%3Cpath%20d%3D%22M431.168%20512a80.832%2080.832%200%201%200%20161.664%200%2080.832%2080.832%200%200%200-161.664%200z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M989.856%20477.856h-35.84C937.312%20260.48%20763.52%2086.656%20546.112%2070.016V34.144a34.144%2034.144%200%200%200-68.288%200v35.84C260.48%2086.688%2086.656%20260.48%2070.016%20477.888H34.144a34.144%2034.144%200%200%200%200%2068.288h35.84c16.672%20217.408%20190.464%20391.2%20407.872%20407.84v35.872a34.144%2034.144%200%200%200%2068.288%200v-35.84c217.408-16.672%20391.2-190.464%20407.84-407.872h35.872a34.144%2034.144%200%200%200%200-68.288zM546.144%20885.76V819.2a34.144%2034.144%200%200%200-68.288%200v66.528C298.048%20869.44%20154.56%20725.952%20138.272%20546.144H204.8a34.144%2034.144%200%200%200%200-68.288H138.272C154.56%20298.048%20298.048%20154.56%20477.856%20138.272V204.8a34.144%2034.144%200%200%200%2068.288%200V138.272c179.808%2016.32%20323.296%20159.776%20339.584%20339.584H819.2a34.144%2034.144%200%200%200%200%2068.288h66.528c-16.288%20179.808-159.776%20323.296-339.584%20339.584z%22%20fill%3D%22%23434343%22%20%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
}
<template>
<view class="allotCars content_box">
<view class=" flex_center flex_sb allotCarsHeader">
<view>订单号:{{orderNo}}</view>
<template v-if="allotType !== 'record'">
<u-button @click="addNewCar" :disabled="orderTrucks.length || (allotType === 'multi' ? false : newTrucks.length)" text="添加新车辆"/>
</template>
</view>
<!-- 待分配车辆 -->
<template v-if="newTrucks.length">
<view style="padding: 24rpx;">
<orderTruckCard :ref='`allotTruck${newOrderTruck.id}`' v-for="(newOrderTruck, index) in newTrucks" :key="index"
:propData="newOrderTruck" :isNewAllot="true" />
</view>
</template>
<!-- 已分配车辆 -->
<template v-if="orderTrucks.length">
<view style="padding: 24rpx;">
<orderTruckCard :ref='`allotTruck${orderTruck.id}`' v-for="(orderTruck, index) in orderTrucks" :key="index" :propData="orderTruck" />
</view>
</template>
<view class="operation-btn">
<button v-if="allotType === 'record' ? orderTrucks.length === 0 : newTrucks.length === 0" :class="['submitBtn common_btn', 'disabledBtn' ]"
disabled @click="onConfirmAllot">确认分配</button>
<button v-else :class="['submitBtn common_btn']"
@click="onConfirmAllot">确认分配</button>
<!-- <button :class="['submitBtn common_btn']"
@click="onConfirmAllot">确认分配</button> -->
</view>
</view>
</template>
<script>
import { getMassOrderTruckList, massAssignTruck, updateMassAssignTruck} from '../../api/apiList.js'
export default {
data() {
return {
orderId: '', //订单Id
orderNo: '', //订单号
allotType: 'unMulti', //配车类型 单辆车:unMulti 多辆车:multi 分配记录:record
orderTrucks: [], //订单已分配车辆
deleteTruckIds: [], //订单删除已分配车辆ID列表
newTrucks: [], //新增分配车辆
pageNum: 1, //页码
pageSize: 20, //每页条数
loadMore: true, //加载更多
};
},
onLoad(option) {
const { orderId, orderNo, allotType } = option
this.orderNo = orderNo
this.orderId = orderId
this.allotType = allotType
this.onAddListener() //添加事件监听
if(allotType === 'record'){
this.initTruckList()
}
},
onUnload(){
this.onRemoveListener() //移除事件监听
},
//下拉刷新
onPullDownRefresh() {
if(this.orderTrucks.length){
this.pageNum = 1
this.orderTrucks = []
this.initTruckList()
}
},
// 触底加载更多
onReachBottom() {
if (this.loadMore && this.orderTrucks.length) {
this.initTruckList()
this.loadMore = false
}
},
methods: {
initTruckList() {
const reqData = {
"args": {
pageNum: this.pageNum,
pageSize: this.pageSize,
"restrictions": [{
"field": 'orderCarrier.massOrder.orderNo',
"type": "EQ",
"value": this.orderNo
}]
}
}
getMassOrderTruckList(reqData).then(res => {
uni.stopPullDownRefresh()
const data = res.data.data.datas
if (data.length > 0) {
const newList = this.orderTrucks.concat(data)
this.orderTrucks = [...newList]
this.pageNum += 1
this.loadMore = true
}
})
},
//新增分配车辆
addNewCar() {
const data = {
allotTrucks: this.newTrucks,
isMulti: this.allotType === 'multi'
}
uni.navigateTo({
url: `/subpkg/choiceTruck/choiceTruck?data=${JSON.stringify(data)}`
})
},
onAddListener(){
uni.$on('onAddMassAssignTruck', this.onAddMassAssignTruck) //监听大宗订单车辆分配
uni.$on('onRemoveMassAssignTruck', this.onRemoveMassAssignTruck) //监听大宗订单车辆分配
},
onRemoveListener(){
uni.$off('onAddMassAssignTruck', this.onAddMassAssignTruck)
uni.$off('onRemoveMassAssignTruck', this.onRemoveMassAssignTruck)
},
//添加分配车辆
onAddMassAssignTruck(truckInfo){
let truckList = this.newTrucks.concat(truckInfo)
const newList = []
truckList.map(item => { //数组去重
const flag = newList.find(itm => itm.id === item.id)
if(!flag){
newList.push(item)
}
})
this.newTrucks = [...newList]
},
//移除分配车辆
onRemoveMassAssignTruck(truckId){
if(this.allotType === 'record'){
const list = this.orderTrucks.filter(item => item.id !== truckId)
this.deleteTruckIds = this.deleteTruckIds.concat(truckId)
this.orderTrucks = [...list]
} else {
const list = this.newTrucks.filter(item => item.id !== truckId)
this.newTrucks = [...list]
}
},
//确认分配
onConfirmAllot(){
const _this = this
if(_this.allotType === 'record'){ //更新订单配车
_this.onUpdateAllot()
return
}
let allotData = []
_this.newTrucks.map(item => {
const minShipments = _this.$refs[`allotTruck${item.id}`][0].minFrequency
const maxShipments = _this.$refs[`allotTruck${item.id}`][0].maxFrequency
const capacity = _this.$refs[`allotTruck${item.id}`][0].alloutQty
allotData.push({
truckId: item.id, //车辆ID
driverId: item['driver1.id'] ,//司机ID
minShipments: Number(minShipments), //最少趟数
maxShipments: Number(maxShipments), //最多趟数
capacity: Number(capacity), //核定装运量
})
})
const assignType = _this.allotType === 'multi' ? 'service.mobileAssignTrucks' : 'operation.assignTruck'
const reqData = {
'aux': _this.allotType === 'multi' ? {trucks:allotData} : allotData[0],
'args': {"selectedIds": [_this.orderId]}
}
massAssignTruck(reqData, assignType).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '分配成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
},
onUpdateAllot(){
const _this = this
let allotData = []
this.orderTrucks.map(item => {
const minShipments = _this.$refs[`allotTruck${item.id}`][0].minFrequency
const maxShipments = _this.$refs[`allotTruck${item.id}`][0].maxFrequency
const capacity = _this.$refs[`allotTruck${item.id}`][0].alloutQty
allotData.push({
truckId: item.id, //车辆ID
driverId: item['driver1.id'] ,//司机ID
minShipments: Number(minShipments), //最少趟数
maxShipments: Number(maxShipments), //最多趟数
capacity: Number(capacity), //核定装运量
})
})
const reqData = {
'aux': {
'trucks': [...allotData],
'delete': [...this.deleteTruckIds]
},
}
updateMassAssignTruck(reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '分配成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
}
},
}
</script>
<style lang="scss">
.allotCars {
padding-top: 120rpx;
.allotCarsHeader {
background-color: #FFFFFF;
height: 120rpx;
width: 100vw;
padding: 40rpx 24rpx;
font-size: 28rpx;
font-weight: 400;
color: #8C8C8C;
position: fixed;
top: 0;
z-index: 999;
button {
width: 220rpx;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #2E75E6;
background-color: rgba(46, 117, 230, .1);
margin: 0;
font-size: 28rpx;
font-weight: 500;
}
}
.operation-btn {
padding-bottom: 40rpx;
margin-bottom: 0;
position: fixed;
bottom: 0;
z-index: 999;
background-color: #FFFFFF;
.submitBtn {
width: 90%;
border: none;
font-weight: 500;
color: #FFFFFF;
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
box-shadow: 1rpx -3rpx 12rpx 0rpx rgba(0,0,0,0.04);
border-radius: 48rpx;
}
.disabledBtn{
background: linear-gradient(90deg, rgba(46, 117, 230, .3) 0%, rgba(94, 88, 238, .3) 100%);
}
}
}
</style>
\ No newline at end of file
<template>
<view class="allotDetail content_box">
<view class="search-input flex_center">
<u-search searchIconSize="50" searchIconColor="#FFFFFF" placeholderColor='#FFFFFF' color="#FFFFFF"
:showAction="false" :placeholder="isAllotTruck ? '请输入车牌号' : '请输入司机姓名'" v-model="searchValue"
@clickIcon="onSearch" @search="onSearch" @clear="onSearch" />
</view>
<view class="select-options">
<u-empty mode="data" textSize='32' iconSize="160" text="暂无数据" v-if="!datas.length" />
<!-- 分配车辆 -->
<template v-if="isAllotTruck">
<bs-customCell v-for="item in datas" :key="item.id" :label="item['driver1.name']"
:value="item['driver1.tel']" labelCol="4" wrapCol="7"
:class="['truck-custom-cell', {'active-class': item.id === currentAllot.truckId}]" @click.native="onSelect(item)">
<view slot="label" class="custom-cell"> {{item.name}}</view>
<view slot="value" class="custom-cell"> {{item['facilityMode.name'] || ''}}
</view>
<view slot="right-icon">
<u-radio-group :value="currentAllot.truckId" placement="column" iconPlacement="right">
<u-radio :size="40" :iconSize="32" :name="item.id" @change="onSelect(item)" />
</u-radio-group>
</view>
</bs-customCell>
</template>
<!-- 分配司机 -->
<template v-else>
<bs-customCell v-for="item in datas" :key="item.id" :label="item.name" :value="item.tel || '暂无'"
labelCol="3.5" wrapCol="7.5" :class="{'active-class': item.id === currentAllot.driver1Id}"
@click.native="onSelect(item)">
<view slot="right-icon">
<u-radio-group :value="currentAllot.driver1Id" placement="column" iconPlacement="right">
<u-radio :size="40" :iconSize="32" :name="item.id" @change="onSelect(item)" />
</u-radio-group>
</view>
</bs-customCell>
</template>
</view>
<view class="operation-btn">
<button class="submitBtn common_btn" @click="onConfirm">分配{{isAllotTruck ? '车辆' : '司机'}}</button>
</view>
</view>
</template>
<script>
import { searchDriverList, searchTruckList } from '../../api/apiList'
export default {
options: { styleIsolation: 'shared' },
data() {
return {
datas: [], //候选项列表
searchValue: "", //搜索值
currentAllot: {}, //当前分配信息
isAllotTruck: false, //是否为分配车辆
pageNum: 1, //页码
pageSize: 20, //每页条数
loadMore: true, //加载更多
}
},
onLoad(options) {
const isAllotTruck = options.action === 'allotTruck' //判断是否为分配车辆
const title = isAllotTruck ? '分配车辆' : '分配司机'
this.setNavTitle(title)
this.isAllotTruck = isAllotTruck
this.initData()
},
onReachBottom() {
if (this.loadMore) {
this.initData();
this.loadMore = false
}
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({
title: title,
})
},
//初始化数据
initData() {
const { pageNum, pageSize } = this
const reqData = {
args: { pageNum, pageSize }
}
if(this.searchValue){
reqData.args.restrictions = [{
"field": 'name',
"type": "LK", //EQ精准匹配,LK模糊匹配
"value": this.searchValue
}]
}
const requestFun = this.isAllotTruck ? searchTruckList : searchDriverList
requestFun(reqData).then(res => {
const datas = res.data.data.datas
if (datas.length) {
const newData = this.datas.concat(datas)
this.datas = [...newData]
this.pageNum += 1
this.loadMore = true
}
})
},
//确认选择
onConfirm() {
const app = getApp()
const { currentAllot, isAllotTruck } = this
if (!Object.keys(currentAllot).length) {
uni.showToast({
title: `请选择分配${isAllotTruck ? '车辆' : '司机'}`,
icon: 'none',
duration: 1500
})
return
}
app.globalData.allotInfo = currentAllot
uni.navigateBack()
},
//当前选择项
onSelect(info) {
let newInfo = {}
newInfo.allotMode = this.isAllotTruck ? 'allotTruck' : 'allotDriver'
if (this.isAllotTruck) {
newInfo.truckId = info.id
newInfo.truckName = info.name
newInfo.truckMode = info['facilityMode.name']
newInfo.driver1Id = info['driver1.id']
newInfo.driverName = info['driver1.name']
newInfo.driverTel = info['driver1.tel']
} else {
newInfo.driver1Id = info.id
newInfo.driverName = info.name
newInfo.driverTel = info.tel
}
this.currentAllot = newInfo
},
// 搜索功能
onSearch() {
this.pageNum = 1
this.datas = []
this.initData()
},
}
}
</script>
<style lang="scss">
.allotDetail {
.search-input {
width: 100%;
position: fixed;
top: 0;
z-index: 999;
height: 128rpx;
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
/deep/.u-search__content {
height: 80rpx;
margin: 24rpx;
background-color: rgba(240, 240, 240, .5) !important;
.u-search__content__input {
letter-spacing: 4rpx;
background-color: transparent !important;
}
.uicon-close{
font-size: 28rpx !important;
}
}
}
/deep/.select-options {
margin: 130rpx 0 15vh;
background-color: #fff;
min-height: 600rpx;
.custom-cell-row {
border-bottom: 2rpx solid #F0F0F0;
margin-top: 0;
padding: 20rpx;
.custom-cell {
margin-bottom: 10rpx;
color: #434343;
}
}
.truck-custom-cell{
color: #8C8C8C;
}
.active-class {
color: #2E75E6;
.custom-cell {
color: #2E75E6;
}
}
}
.u-radio {
background-color: #fff;
}
.operation-btn {
position: fixed;
bottom: 0;
.submitBtn {
width: 90%;
}
}
}
</style>
<template>
<view class="allotTruck content_box">
<bs-pageHeader-orderNo :shipmentNo="shipmentNo" />
<view class="allot-detail">
<u--form>
<u-form-item required label="车牌号" labelWidth="20%">
<view @click="onNavAllotDetail('allotTruck')">
<u-input border="none" readonly placeholder="选择车辆" placeholderClass="input-tip"
v-model="truckName" />
</view>
<view slot="right" class="t-icon t-icon-rightArrow" @click="onNavAllotDetail('allotTruck')" />
</u-form-item>
<u-form-item label="车型" labelWidth="20%" v-if="truckMode">
<u-input border="none" readonly v-model="truckMode" />
</u-form-item>
<u-form-item required label="司机名" labelWidth="20%">
<view @click="onNavAllotDetail('allotDriver')">
<u-input border="none" readonly placeholder="选择司机" placeholderClass="input-tip"
v-model="driverName" />
</view>
<view slot="right" class="t-icon t-icon-rightArrow" @click="onNavAllotDetail('allotDriver')" />
</u-form-item>
<u-form-item label="手机号" labelWidth="20%" v-if="driverTel">
<u-input border="none" readonly v-model="driverTel" />
</u-form-item>
</u--form>
</view>
<view class="operation-btn">
<button class="submitBtn common_btn" @click="onConfirmAllot">确认分配</button>
</view>
</view>
</template>
<script>
import { reportInfo } from '../../api/apiList'
const app = getApp()
export default {
data() {
return {
driver1Id: "", //司机ID
truckId: '', //车辆id
driverName: "", //司机姓名
driverTel: "", //司机电话
truckName: "", //车牌
truckMode: "", //车型
shipmentNo: '', //运单号
shipmentId: '', //运单ID
}
},
onLoad(options) {
const { shipmentData } = JSON.parse(options.data)
const { shipmentNo, shipmentId } = app.globalData.shipmentInfo
this.onSetGlobalData(shipmentData)
this.shipmentNo = shipmentNo
this.shipmentId = shipmentId
},
onShow() { //自定义分配信息
const { allotMode, truckId, truckName, truckMode, driver1Id, driverName, driverTel } = app.globalData.allotInfo
if (allotMode === 'allotDefault') {
this.truckId = truckId
this.truckName = truckName
this.truckMode = truckMode
this.driver1Id = driver1Id
this.driverName = driverName
this.driverTel = driverTel
return
}
if (allotMode === 'allotDriver') { //分配司机
this.driver1Id = driver1Id
this.driverName = driverName
this.driverTel = driverTel || '暂无'
} else {
this.truckId = truckId
this.truckName = truckName
this.truckMode = truckMode || '暂无'
this.driver1Id = driver1Id
this.driverName = driverName
this.driverTel = driverTel || '暂无'
}
},
methods: {
//重置分配信息
onSetGlobalData(shipmentData) {
app.globalData.allotInfo = {
'allotMode': 'allotDefault', //分配模式
'truckId': shipmentData.header['truck.id'],
'truckName': shipmentData.header['truck.name'],
'truckMode': shipmentData.header['truck.facilityMode.name'],
'driver1Id': shipmentData.header['driver1.id'],
'driverName': shipmentData.header['driver1.name'],
'driverTel': shipmentData.header['driver1.tel'],
}
},
//确认分配
onConfirmAllot() {
const { driver1Id, truckId } = this
if (!driver1Id || !truckId) {
uni.showToast({
title: '请完善必填信息',
icon: 'error',
duration: 3000
})
return
}
const data = {
"aux": { driver1Id, truckId },
'args': {
"selectedIds": [this.shipmentId]
}
}
reportInfo('assign', data).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '分配成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
},
//跳转分配明细
onNavAllotDetail(action) {
uni.navigateTo({
url: `/subpkg/allotDetail/allotDetail?action=${action}`,
})
},
}
}
</script>
<style lang="scss">
.allotTruck {
/deep/.allot-detail {
padding: 0 40rpx;
background-color: #ffffff;
margin: 25rpx 0;
.input-tip {
font-size: 28rpx;
color: #BFBFBF;
}
.u-form-item__body__left__content__label {
color: #8C8C8C;
font-size: 28rpx;
}
.u-form-item__body {
padding: 30rpx 0;
}
.u-icon {
margin-left: 20rpx;
}
}
.submitBtn {
width: 90%;
}
}
</style>
<template>
<view class="view-driver-truck content_box">
<view class="queueSubscribeTitle">
<u--input placeholder="请输入司机姓名" border="surround" prefixIcon="search" shape="circle" color="#ffffff"
placeholderStyle="color:#ffffff" @blur="searchText" v-model="searchValue"></u--input>
</view>
<view class="content-list" style="margin-bottom: 120rpx;">
<u-empty mode="data" textSize='32' iconSize="160" text="暂无数据" v-if="!datas.length" />
<bs-customCell v-for="item in datas" :key="item.id" :label="item.name" labelCol='4' wrapCol="7.2"
:value="isDriver ? item.tel : item['facilityMode.name']" @click.native="onNavDetail(item.id, item.name)">
</bs-customCell>
</view>
</view>
</template>
<script>
import {
searchDriverList,
searchTruckList
} from '../../api/apiList'
export default {
options: {
styleIsolation: 'shared'
},
data() {
return {
datas: [], //候选项列表
isDriver: true, //是否查看司机
pageNum: 1, //页码
pageSize: 20, //每页条数
loadMore: true, //加载更多
searchValue: ''
}
},
onLoad: function() {},
onShow() {
this.pageNum = 1
this.datas = []
this.initData(this.isDriver)
},
onReachBottom() {
if (this.loadMore) {
this.initData(this.isDriver);
this.loadMore = false
}
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({
title: title,
searchValue: ''
})
},
//初始化数据
initData(isDriver) {
const {
pageNum,
pageSize
} = this
const reqData = {
args: {
pageNum,
pageSize,
"restrictions": [{
"field": "name",
"type": "LK",
"value": this.searchValue
}]
}
}
searchDriverList(reqData).then(res => {
const datas = res.data.data.datas
if (datas.length) {
const newData = this.datas.concat(datas)
this.datas = [...newData]
this.pageNum += 1
this.loadMore = true
}
})
},
searchText(searchValue) {
this.searchValue = searchValue
this.pageNum = 1
this.datas = []
this.initData(this.isDriver)
},
onNavDetail(id, name){
let pages = getCurrentPages(); // 当前页面
if (pages.length > 1) {
var beforePage = pages[pages.length - 2]; // 前一个页面
beforePage.$vm.setTruckDriver(id, name) //clear 是你要调用上个页面的方法,$vm 是必须要有的
}
uni.navigateBack()
}
}
}
</script>
<style lang="scss">
.view-driver-truck {
.queueSubscribeTitle {
width: 100%;
height: 128rpx;
background-color: #2E75E6;
display: flex;
align-items: center;
padding: 0 25rpx;
.u-input {
background-color: rgba(240, 240, 240, .5);
height: 80rpx;
}
.u-icon__icon {
font-size: 48rpx !important;
color: #FFFFFF !important;
}
}
/deep/.content-list {
background-color: #fff;
padding: 0 32rpx;
.custom-cell-row {
padding: 40rpx 0;
margin-top: 0;
border-bottom: 2rpx solid #dadada;
&:last-child {
border-bottom: none;
}
}
}
.submitBtn {
width: 90%;
}
.add_driver_btn {
position: fixed;
bottom: 40rpx;
left: 50%;
transform: translateX(-50%);
margin-bottom: 0;
}
}
</style>
<template>
<view style="padding-top: 128rpx;">
<view class="queueSubscribeTitle">
<u--input placeholder="请输入车牌号" border="surround" prefixIcon="search" shape="circle" color="#ffffff"
placeholderStyle="color:#ffffff" @blur="change"></u--input>
</view>
<view v-for="(truck, index) in truckList" :key="index" style="padding: 0 24rpx;">
<view class="flex_center flex_sb" style="height: 130rpx;">
<view class="">
<view style="color: #262626;font-size: 28rpx;font-weight: bolder;">
{{truck.name || ''}}{{' '}}{{truck['facilityMode.name'] || ''}}
</view>
<view style="color: #8C8C8C;font-size: 24rpx; margin-top: 24rpx;">
{{truck['driver1.name'] || ''}}{{' '}}{{truck['driver1.tel'] || ''}}
</view>
</view>
<view @click="choiceTruck(truck.id)"
:class="['queueSubscribeNoChoice', currentDriver.includes(truck.id) ?'queueSubscribeChoice':'']">
</view>
</view>
<u-line></u-line>
</view>
<view v-if="truckList.length" @click="onConfirm" class="queueSubscribeConfirm">
<button>选择车辆</button>
</view>
</view>
</template>
<script>
import { searchTruckList } from '../../api/apiList.js'
export default {
data() {
return {
isMulti: false, //是否分配多辆车, 分配多辆车时支持多选
truckList: [],
currentDriver: '', //单辆车为字符串,多辆车为数组
searchValue: '',
pageNum: 1, //页码
pageSize: 20, //每页条数
loadMore: true, //加载更多
}
},
//下拉刷新
onPullDownRefresh() {
this.pageNum = 1
this.truckList = []
this.getTruckList()
},
// 触底加载更多
onReachBottom() {
if (this.loadMore) {
this.getTruckList()
this.loadMore = false
}
},
onLoad(option) {
const {isMulti, allotTrucks} = JSON.parse(option.data)
const pageTitle = isMulti ? '分配多辆车' : '分配车辆'
this.isMulti = isMulti
this.setNavTitle(pageTitle)
this.getTruckList()
this.initSelect(isMulti, allotTrucks)
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({ title })
},
//多选车辆时设置默认值
initSelect(isMulti, allotTrucks){
if(isMulti){
this.currentDriver = allotTrucks.map(item => item.id) || []
}
},
getTruckList() {
searchTruckList({
"args": {
pageNum: this.pageNum,
pageSize: this.pageSize,
"restrictions": [{
"field": 'name',
"type": "LK",
"value": this.searchValue
}]
}
}).then(res => {
uni.stopPullDownRefresh()
const data = res.data.data.datas
if (data.length > 0) {
this.truckList = this.truckList.concat(data)
this.pageNum += 1
this.loadMore = true
}
})
},
change(value) {
this.searchValue = value
this.truckList = []
this.pageNum = 1
this.getTruckList()
},
choiceTruck(truckId) {
if(this.isMulti){
const isSelect = this.currentDriver.find(item => item === truckId)
if(isSelect){
const newList = this.currentDriver.filter(item => item !== truckId) //取消选择
this.currentDriver = [...newList]
} else {
this.currentDriver = this.currentDriver.concat(truckId) //选择
}
} else {
this.currentDriver = truckId
}
},
onConfirm() {
const _this = this
const flag = _this.isMulti ? _this.currentDriver.length : _this.currentDriver
if(flag){
let truckInfo = {}
if(_this.isMulti){ //分配多车
const datas = []
_this.currentDriver.map(truckId => {
const info = _this.truckList.find(item => item.id === truckId)
datas.push(info)
})
truckInfo = [...datas]
} else {
truckInfo = _this.truckList.find(item => item.id === _this.currentDriver)
}
uni.$emit('onAddMassAssignTruck', truckInfo)
uni.navigateBack()
} else {
uni.showToast({
title: '请选择车辆',
icon:'none',
duration: 1500
})
}
}
}
}
</script>
<style lang="scss">
.queueSubscribeTitle {
width: 100%;
height: 128rpx;
background-color: #2E75E6;
display: flex;
align-items: center;
padding: 0 25rpx;
position: fixed;
top: 0;
z-index: 1;
.u-input {
background-color: rgba(240, 240, 240, .5);
height: 80rpx;
border: none;
}
.u-icon__icon {
font-size: 48rpx !important;
color: #FFFFFF !important;
}
}
.queueSubscribeNoChoice {
border: 2rpx solid #BFBFBF;
width: 40rpx;
height: 40rpx;
border-radius: 20rpx;
line-height: 40rpx;
text-align: center;
color: #FFFFFF;
font-weight: bolder;
}
.queueSubscribeChoice {
border: none;
background-color: #2E75E6;
}
.queueSubscribeConfirm {
position: sticky;
background-color: #FFFFFF;
padding: 24rpx;
bottom: 0;
button {
width: 686rpx;
height: 88rpx;
border-radius: 44rpx;
line-height: 88rpx;
background-image: linear-gradient(90deg, #2E75E6, #5E58EE);
color: #FFFFFF;
font-weight: bolder;
font-size: 32rpx;
}
}
</style>
<template>
<view class="editUserCode content_box">
<u-toast ref="uToast" />
<view class="form-header font_bolder flex">
<!-- <view class="vertical-separate" /> -->
<text class="form-title">修改密码</text>
</view>
<view class="myForm-detail">
<u--form :model="formData" :rules="rules" ref="myForm" errorType='none'>
<u-form-item prop="oldPassword" required borderBottom label="旧密码 :" labelWidth="20%">
<u-input border="none" clearable password placeholder="请输入旧密码" placeholderClass="input-placeholder"
v-model="formData.oldPassword" />
</u-form-item>
<u-form-item prop="newPassword" required borderBottom label="新密码 :" labelWidth="20%">
<u-input border="none" clearable password placeholder="新密码不少于6位"
placeholderClass="input-placeholder" v-model="formData.newPassword" />
</u-form-item>
<u-form-item prop="confirmPassword" required label="密码确认 :" labelWidth="25%">
<u-input border="none" clearable password placeholder="请再次输入密码" placeholderClass="input-placeholder"
v-model="formData.confirmPassword" />
</u-form-item>
</u--form>
</view>
<view class="input-tip flex_center">
<view class="t-icon t-icon-warning" style="margin-right: 10rpx;"/>
<text>密码至少含2种以上字符</text>
</view>
<view class="operation-btn">
<button class="submitBtn" @click="onSubmitForm">确 定</button>
</view>
</view>
</template>
<script>
import { userMobileOperation } from '../../api/apiList.js'
export default {
data() {
return {
formData: {
oldPassword: "", //旧密码
newPassword: "", //新密码
confirmPassword: "", //确认密码
},
userName: '', //用户名
rules: {
'oldPassword': { required: true },
'newPassword': { required: true },
'confirmPassword': { required: true }
}
}
},
onLoad: function(options) {
this.userName = options.userName
},
methods: {
//提交表单、
onSubmitForm() {
this.$refs.myForm.validate().then(res => {
const { confirmPassword, newPassword, oldPassword } = this.formData
if (oldPassword === newPassword) {
uni.showToast({
title: '新密码与旧密码相同!请重新输入',
icon: 'none',
duration: 1000
})
return
}
if (confirmPassword.length < 6 || newPassword.length < 6) {
uni.showToast({
title: '密码长度不应小于6位!请重新输入',
icon: 'none',
duration: 1000
})
return
}
if (confirmPassword !== newPassword) {
uni.showToast({
title: '确认密码与新密码不一致!请重新输入!',
icon: 'none',
duration: 1000
})
return
}
const data = {
args: {
userName: this.userName,
password: oldPassword,
newPassword: confirmPassword
}
}
userMobileOperation('changePassword', data).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '密码修改成功!',
duration: 1000
})
setTimeout(() => {
uni.reLaunch({
url: '/pages/login/login',
})
}, 1500)
}
})
}).catch(errors => {
this.$refs.uToast.show({
message: '内容不可为空!',
})
})
}
}
}
</script>
<style lang="scss">
.editUserCode {
.form-header {
padding: 40rpx 0 20rpx 30rpx;
.vertical-separate {
border-left: 6rpx solid #2E5BFA;
margin-right: 10rpx;
}
}
/deep/.myForm-detail {
background-color: #fff;
padding-left: 45rpx;
.u-form-item__body {
margin: 20rpx 0;
}
.u-form-item__body__left__content__label{
font-size: 28rpx !important;
color: #8c8c8c;
}
.input-placeholder {
color: #999999;
font-size: 28rpx;
}
}
.input-tip {
font-size: 24rpx;
margin: 24rpx 20rpx;
padding-left: 20rpx;
}
.submitBtn{
width: 90%;
border-radius: 48px;
}
}
</style>
<template>
<view class="orderDetail-list content_box">
<u-empty mode="data" textSize='32' iconSize="160" text="暂无订单详细数据" v-if="isEmpty" />
<view class="orderDetail-item">
<view class="detail-title flex_center">
<view class="t-icon t-icon-order" />
订单号: {{orderList.orderNo}}
</view>
<!-- 订单明细" -->
<view style="height: 80rpx;padding-left: 4rpx;">
<bs-customCell label="货量" :value="`${orderList.qty}件/${orderList.weight}千克/${orderList.volume}方`"
labelCol="3" wrapCol="7" />
<bs-customCell label="运输要求" :value="orderList.transportRequest" labelCol="3" wrapCol="9" />
</view>
<u-line color="#E5E5E5" margin="40rpx 2% 20rpx" />
<view style="height: 200rpx;padding-left: 4rpx;">
<bs-customCell label="发货地址" :value="orderList['originalAddress.name']" labelCol="3" wrapCol="9" />
<bs-customCell label="发货人" :value="orderList['originalContact.name']" labelCol="3" wrapCol="9" />
<bs-customCell label="联系方式" :value="orderList['originalContact.tel']" labelCol="3" wrapCol="9" />
<!-- <bs-customCell label="发货人备注:" :value="orderList['originalContact.remark']" labelCol="3" /> -->
<bs-customCell label="提货要求" :value="orderList['originalRequirement']" labelCol="3" wrapCol="9" />
</view>
<u-line color="#E5E5E5" margin="40rpx 2% 20rpx" />
<view style="padding-left: 4rpx;">
<bs-customCell label="收货地址" :value="orderList['destinationAddress.name']" labelCol="3" wrapCol="9" />
<bs-customCell label="收货人" :value="orderList['destinationContact.name']" labelCol="3" wrapCol="9" />
<bs-customCell label="联系方式" :value="orderList['destinationContact.tel']" labelCol="3" wrapCol="9" />
<!-- <bs-customCell label="卸货人备注:" value="orderList['destinationContact.remark']" labelCol="3" /> -->
<bs-customCell label="配送要求" :value="orderList['destinationRequirement']" labelCol="3" wrapCol="9" />
</view>
<!-- 货物明细 -->
<uni-collapse v-model="activeNames" @change="onChange">
<view class="outer-frame">
<uni-collapse-item :show-arrow="false" title-border="none" :name="orderList.id">
<!-- 自定义标题栏 -->
<template v-slot:title>
<view class="foldPanel-title flex_center">
<text style="flex-grow: 1">货物详情</text>
<!-- 自定义标题栏右侧图标 -->
<view :class="['foldPanel-right-icon', 't-icon', activeNames.includes(orderList.id) ? 't-icon-unfold-blue' :'t-icon-fold-blue']" />
</view>
</template>
<!-- 货物详情 -->
<view class="cargo-detail-table">
<view class="detail-row-title">
<u-row>
<u-col textAlign="center" span="4">名称</u-col>
<u-col textAlign="end" span="7">数量</u-col>
</u-row>
</view>
<u-empty mode="data" textSize='32' iconSize="160" text="暂无货物明细"
v-if="!cargoDetails.length" />
<view class="detail-col-item" v-for="itm in cargoDetails" :key="itm.id">
<u-row>
<u-col span="7" class="cargo-title">
<view class="cargo-title">{{itm['goods.name']}}</view>
</u-col>
<u-col span="4" textAlign="end">{{itm.qty}}</u-col>
</u-row>
</view>
</view>
</uni-collapse-item>
</view>
</uni-collapse>
</view>
</view>
</template>
<script>
import { OMOrderDetail, OROrderDetail } from '../../api/apiList.js'
export default {
name: 'orderDetail',
options: { styleIsolation: 'shared' },
data() {
return {
orderList: '', //订单列表,当默认为{}时,小程序会自动转结构
cargoDetails: [], //货量明细
isEmpty: true, //是否为空
activeNames: [], //当前展开面板 names => orderIds
}
},
onLoad(options) {
const data = JSON.parse(options.data)
const isEmpty = !Object.keys(data).length
this.orderList = data
this.isEmpty = isEmpty
if (!isEmpty) {
this.activeNames = [data.id]
this.getOrderDetail(data.id)
}
},
methods: {
// 折叠面板
onChange(values) {
this.activeNames = values
},
//获取订单货物明细
getOrderDetail(orderId) {
const { shipmentBizName } = getApp().globalData.shipmentInfo
let shipmentMode = ''
switch (shipmentBizName) { //根据shipmentBizName 判断运输模式
case 'tm.MovementShipment':
case 'tm.SectionShipment': //暂时走OM逻辑
shipmentMode = 'OM'
break
case 'tm.MassShipment':
shipmentMode = 'MS'; //大宗运输
break
default:
shipmentMode = 'OR';
}
if(shipmentMode !== 'MS'){ //大宗模式无需查询货物明细
const isShipmentOM = shipmentMode === 'OM' //判断是否为OM模式
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": isShipmentOM ? 'orderMovement.id' : 'orderRelease.id',
"type": "EQ",
"value": orderId
}]
}
}
const requestFun = isShipmentOM ? OMOrderDetail : OROrderDetail
requestFun(reqData).then(res => {
const datas = res.data.data.datas
const newData = []
datas.map(item => {
if (isShipmentOM) { //自定义数据字段 转换为简洁的OR模式字段名
newData.push({
'id': item.id,
'goods.name': item['goods.name'],
'qty': item.shipQty,
})
} else {
newData.push({ ...item })
}
})
this.cargoDetails = [...newData]
})
}
},
}
}
</script>
<style lang="scss">
.orderDetail-list {
.orderDetail-item {
padding: 32rpx;
margin-bottom: 24rpx;
background: #FFFFFF;
.detail-title {
font-size: 28rpx;
padding: 8rpx 0 30rpx;
border-bottom: 1rpx solid #E5E5E5;
.t-icon-order {
width: 50rpx;
height: 50rpx;
margin-right: 20rpx;
}
}
/deep/.custom-cell-row {
margin-top: 16rpx;
.custom-cell-label {
color: #8C8C8C;
}
}
.outer-frame {
margin-top: 32rpx;
border-radius: 16rpx;
border: 2rpx solid #F0F0F0;
overflow: hidden;
.foldPanel-title {
color: #2E75E6;
font-size: 28rpx;
padding-left: 20rpx;
height: 96rpx;
background: rgba(46, 117, 230, .1);
.foldPanel-right-icon {
margin-right: 20rpx;
}
}
/deep/.cargo-detail-table {
background: #FFFFFF;
padding-bottom: 10rpx;
.detail-row-title {
color: #8C8C8C;
background: #FAFAFA;
padding: 20rpx 0;
}
.detail-col-item {
margin: 20rpx;
.cargo-title {
font-size: 28rpx;
padding-left: 20rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
.snapshoot image {
margin: 20rpx 15rpx;
width: 140rpx;
height: 140rpx;
}
}
</style>
<template>
<view class="registerDriver content_box">
<u-toast ref="uToast" />
<!-- 注册内容 -->
<u--form :model="formData" :rules="rules" ref="myForm" errorType='none'>
<!-- 基本信息 -->
<view class="module-title flex">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">基本信息</text>
</view>
<view class="basicInfo">
<u-form-item prop="name" required label="姓名" labelWidth="20%" borderBottom>
<u-input border="none" placeholder="请输入姓名" v-model="formData.name" />
</u-form-item>
<u-form-item prop="gender" label="性别" labelWidth="20%" borderBottom>
<view @click="onVisible('gender')">
<u-input border="none" readonly placeholder="请选择性别" :value="genderViewEnums[formData.gender]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index="gender" />
</u-form-item>
<u-form-item prop="age" label="年龄" labelWidth="20%" borderBottom>
<u-input border="none" placeholder="请输入年龄" v-model="formData.age" />
</u-form-item>
<u-form-item prop="tel" required label="联系方式" labelWidth="20%">
<u-input border="none" placeholder="请输入联系方式" v-model="formData.tel" />
</u-form-item>
<u-form-item prop="ownerId" label="承运商" labelWidth="20%">
<view @click="onVisible('ownerId')">
<u-input border="none" readonly placeholder="请选择承运商" :value="carrierViewEnums[formData.ownerId]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index="ownerId" />
</u-form-item>
</view>
<!-- 身份证 -->
<view class="module-title flex">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">身份证</text>
</view>
<view class="driverLicense">
<u-form-item required prop="idCard.code" label="身份证号" labelWidth="25%" borderBottom>
<u-input border="none" placeholder="请输入身份证号" v-model="formData.idCard.code" @blur="onBlur"/>
</u-form-item>
<u-form-item required prop="idCard.effectiveDate" label="生效日期" labelWidth="25%" borderBottom>
<view @click="onVisibleDate('idCard.effectiveDate')">
<u-input border="none" readonly placeholder="请选择生效日期" :value="convertTime(formData.idCard.effectiveDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index="idCard.effectiveDate" />
</u-form-item>
<u-form-item required prop="idCard.expirationDate" label="失效日期" labelWidth="25%" borderBottom>
<view @click="onVisibleDate('idCard.expirationDate')">
<u-input border="none" readonly placeholder="请选择失效日期" :value="convertTime(formData.idCard.expirationDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index="idCard.expirationDate" />
</u-form-item>
<u-form-item required label="证件照片" labelWidth="25%" />
<view class="driverLicense-uploader-img">
<bs-uploader btnTitle="身份证正面照片" maxCount="1" ref="idcardFaceImage" cameraType="idCardFace" @customUploadAfter="onUploadOCR" />
<bs-uploader btnTitle="身份证反面照片" maxCount="1" ref="idcardBackImage" cameraType="idCardBack" @customUploadAfter="onUploadOCR"/>
</view>
</view>
<!-- 驾驶证 -->
<view class="module-title flex">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">驾驶证</text>
</view>
<view class="driverLicense">
<u-form-item prop="driverLicense.code" label="驾驶证号" labelWidth="25%" borderBottom>
<u-input border="none" placeholder="请输入驾驶证号" v-model="formData.driverLicense.code" />
</u-form-item>
<u-form-item prop="driverLicense.quasiDrivingType" label="准驾车型" labelWidth="25%" borderBottom>
<view @click="onVisible('driverLicense.quasiDrivingType')">
<u-input border="none" readonly placeholder="请选择准驾车型" :value="viewEnums[formData.driverLicense.quasiDrivingType]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index="driverLicense.quasiDrivingType" />
</u-form-item>
<u-form-item prop="driverLicense.effectiveDate" label="生效日期" labelWidth="25%" borderBottom>
<view @click="onVisibleDate('driverLicense.effectiveDate')">
<u-input border="none" readonly placeholder="请选择生效日期" :value="convertTime(formData.driverLicense.effectiveDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index="driverLicense.effectiveDate" />
</u-form-item>
<u-form-item prop="driverLicense.expirationDate" label="失效日期" labelWidth="25%" borderBottom>
<view @click="onVisibleDate('driverLicense.expirationDate')">
<u-input border="none" readonly placeholder="请选择失效日期" :value="convertTime(formData.driverLicense.expirationDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index="driverLicense.expirationDate" />
</u-form-item>
<u-form-item label="证件照片" labelWidth="25%" />
<view class="driverLicense-uploader-img">
<bs-uploader btnTitle="驾驶证正面照片" maxCount="1" ref="driverLicenseFaceImage" cameraType="driveCardFace" @customUploadAfter="onUploadOCR"/>
<bs-uploader btnTitle="驾驶证反面照片" maxCount="1" ref="driverLicenseBackImage" cameraType="driveCardBack" @customUploadAfter="onUploadOCR"/>
</view>
</view>
<!-- 从业资格证 -->
<view class="module-title flex">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">从业资格证</text>
</view>
<view class="driverJobCertificate">
<u-form-item prop="driverLicense.code" label="从业资格证号" labelWidth="35%" borderBottom>
<u-input border="none" placeholder="请输入从业资格证号" v-model="formData.driverJobCertificate.code" />
</u-form-item>
<u-form-item prop="driverJobCertificate.quasiDrivingType" label="准驾车型" labelWidth="35%" borderBottom>
<view @click="onVisible('driverJobCertificate.quasiDrivingType')">
<u-input border="none" readonly placeholder="请选择准驾车型" :value="viewEnums[formData.driverJobCertificate.quasiDrivingType]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index='driverJobCertificate.quasiDrivingType' />
</u-form-item>
<!-- <u-form-item prop="driverJobCertificate.test" label="从业资格类别" labelWidth="35%">
<u-input border="none" readonly placeholder="请选择资格类别"
:value="viewEnums[formData.driverJobCertificate.test]" />
<u-icon slot="right" name="arrow-right" @click="onVisible" />
</u-form-item> -->
<u-form-item prop="driverJobCertificate.effectiveDate" label="生效日期" labelWidth="35%" borderBottom>
<view @click="onVisibleDate('driverJobCertificate.effectiveDate')">
<u-input border="none" readonly placeholder="请选择生效日期" :value="convertTime(formData.driverJobCertificate.effectiveDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index='driverJobCertificate.effectiveDate' />
</u-form-item>
<u-form-item prop="driverJobCertificate.expirationDate" label="失效日期" labelWidth="35%" borderBottom>
<view @click="onVisibleDate('driverJobCertificate.expirationDate')">
<u-input border="none" readonly placeholder="请选择失效日期" :value="convertTime(formData.driverJobCertificate.expirationDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index="driverJobCertificate.expirationDate" />
</u-form-item>
<u-form-item label="证件照片" labelWidth="25%" />
<bs-uploader :maxCount="1" btnTitle="从业资格证件照" ref="driverJobCertificateFaceImage" />
</view>
</u--form>
<!-- 底部按钮 -->
<view class="operation-btn flex_sb">
<button class="backBtn common_btn" @click="onNavBack">返回</button>
<button class="submitBtn common_btn" @click="onSubmitForm">注册</button>
</view>
<!-- 类型选择动作面板 -->
<bs-selectPicker ref="mySelectPicker" :pickerEnums="optionEnums" :visible="visible" @onVisible="onVisible"
@onConfirm="onConfirmPicker" />
<!-- 时间选择 -->
<bs-datetimePicker ref="myTimePicker" :visible="showPopup" @onVisible="onVisibleDate"
@onSelsectDate="onSelsectDate" />
</view>
</template>
<script>
import { serviceRegister, queryDrivingType,GetCarrierList, uploadImg, OCRService} from '../../api/apiList'
import { formatTime } from '../../utils/util.js'
export default {
options: { styleIsolation: 'shared' },
data() {
return {
formData: {
name: "", //姓名
gender: "", //性别
age: "", //年龄
tel: "", //电话
ownerId: '',
idCard:{
code:"",
effectiveDate: '', //生效日期
expirationDate: '', //失效日期
faceImage: '', //正面照片
backImage: '', //背面照片
},
driverLicense: { // 驾驶证信息
code: '', //证件号码
quasiDrivingType: '', //准驾车型
effectiveDate: '', //生效日期
expirationDate: '', //失效日期
faceImage: '', //正面照片
backImage: '', //背面照片
},
driverJobCertificate: { // 从业资格证信息
code: '', //证件号码
quasiDrivingType: '', //准驾车型
effectiveDate: '', //生效日期
expirationDate: '', //失效日期
faceImage: '', //证件照片
},
},
rules: {
'name': { required: true },
'tel': { required: true },
'idCard.code': { required: true },
'idCard.effectiveDate': { required: true },
'idCard.expirationDate': { required: true },
'idCard.faceImage': { required: true },
'idCard.backImage': { required: true },
},
visibleKey: '', //当前显示字段的key
optionEnums: [], //候选项枚举
genderViewEnums: [{ label: '男', value: 'MALE' }, { label: '女', value: 'FEMALE' }],//性别枚举
viewEnums: [], //视图枚举
visible: false, //类型选择
showPopup: false, //时间选择
carrierList: [],
carrierViewEnums: []
}
},
onShow() {
this.getCarrierList()
},
methods: {
//返回上一级页面
onNavBack() {
uni.navigateBack()
},
// 提交表单数据
onSubmitForm() {
this.$refs.myForm.validate().then(res => {
this.getUploadImgs().then(imgs => {
if(!(imgs[0] && imgs[1])){
this.$refs.uToast.show({
message: '请完善必填信息',
})
return
}
let reqData = { "aux": { ...this.formData } }
reqData.aux.idCard.faceImage = imgs[0]
reqData.aux.idCard.backImage = imgs[1]
reqData.aux.idCard.effectiveDate = reqData.aux.idCard.effectiveDate ? formatTime(new Date(reqData.aux.idCard.effectiveDate)) : ""
reqData.aux.idCard.expirationDate = reqData.aux.idCard.expirationDate ? formatTime(new Date(reqData.aux.idCard.expirationDate)) : ""
reqData.aux.driverLicense.faceImage = imgs[2]
reqData.aux.driverLicense.backImage = imgs[3]
reqData.aux.driverLicense.effectiveDate = reqData.aux.driverLicense.effectiveDate ? formatTime(new Date(reqData.aux.driverLicense.effectiveDate)) : ""
reqData.aux.driverLicense.expirationDate = reqData.aux.driverLicense.expirationDate ? formatTime(new Date(reqData.aux.driverLicense.expirationDate)) : ""
reqData.aux.driverJobCertificate.faceImage = imgs[4]
reqData.aux.driverJobCertificate.effectiveDate = reqData.aux.driverJobCertificate.effectiveDate ? formatTime(new Date(reqData.aux.driverJobCertificate.effectiveDate)) : ""
reqData.aux.driverJobCertificate.expirationDate = reqData.aux.driverJobCertificate.expirationDate ? formatTime(new Date(reqData.aux.driverJobCertificate.expirationDate)) : ""
serviceRegister('Driver', reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '注册成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
})
}).catch(errors => {
console.warn(errors)
this.$refs.uToast.show({
message: '请完善必填信息',
})
})
},
getUploadImgs() {
return new Promise((reslove, reject) => {
let promisesArr = [
new Promise((res, rej) => {
this.$refs.idcardFaceImage.uploadImage(imgs => res(imgs))
}),
new Promise((res, rej) => {
this.$refs.idcardBackImage.uploadImage(imgs => res(imgs))
}),
new Promise((res, rej) => {
this.$refs.driverLicenseFaceImage.uploadImage(imgs => res(imgs))
}),
new Promise((res, rej) => {
this.$refs.driverLicenseBackImage.uploadImage(imgs => res(imgs))
}),
new Promise((res, rej) => {
this.$refs.driverJobCertificateFaceImage.uploadImage(imgs => res(imgs))
})
]
Promise.all(promisesArr).then(res => {
reslove(res)
})
})
},
//类型选择
async onVisible(type) {
if (this.visible) {
this.visible = false
} else {
let optionEnums = []
let setKey = 'viewEnums' //要设置的字段Key
let isRequest = type === 'driverLicense.quasiDrivingType' || type ===
'driverJobCertificate.quasiDrivingType'
if (type === 'ownerId') {
setKey = 'carrierViewEnums'
optionEnums = this.carrierList
}else if (isRequest) {
const res = await queryDrivingType()
optionEnums = res.data.data.datas
}
this.setViewEnums(optionEnums, setKey)
this.optionEnums = optionEnums
this.visibleKey = type
this.visible = true
}
},
//设置显示枚举
setViewEnums(optionEnums, key) {
let viewEnums = {}
optionEnums.map(item => {
viewEnums[item.value] = item.label
})
this[key] = viewEnums
},
//确认选择
onConfirmPicker(value) {
this.setFormData(value)
this.visible = false
},
// 时间选择
onSelsectDate(dateInfo) {
const { timestamp } = dateInfo
this.setFormData(timestamp)
this.showPopup = false
},
//设置formData
setFormData(value) {
const key = this.visibleKey
if (key.includes('.')) {
const keys = key.split('.');
let target = this.formData;
for (let i = 0; i < keys.length - 1; i++) {
target = target[keys[i]];
}
target[keys[keys.length - 1]] = value;
} else {
this.formData[key] = value
}
},
//关闭时间选择框
onVisibleDate(type) {
if(type){
this.visibleKey = type
}
this.showPopup = !this.showPopup
},
//页面展示时间戳转换为日期
convertTime(timestamp) {
if (!timestamp) return
const nowDate = new Date(timestamp)
var year = nowDate.getFullYear();
var month = nowDate.getMonth() + 1;
var date = nowDate.getDate();
return `${year}-${ month}-${date}`
},
getCarrierList(){
this.carrierList = []
GetCarrierList({ "args": { pageNum:1, pageSize:100 }}).then(res=>{
res.data.data.datas.map(data=>{
this.carrierList.push({ label: data.name, value: data.id})
})
})
},
onBlur(){
if(!this.formData.idCard.code){
this.$refs.uToast.show({
message: '身份证号不能为空',
})
}
},
async onUploadOCR(fileInfo){
const {url, cameraType} = fileInfo
const ocrService = {
'idCardFace': {service: 'idCard', imageType: 'front'}, //身份证正面
'idCardBack': {service: 'idCard', imageType: 'back'}, //身份证反面
'driveCardFace': {service: 'drivingLicense', imageType: 'front'}, //驾驶证正页
'driveCardBack': {service: 'drivingLicense', imageType: 'back'}, //驾驶证副页
'vehicleCardFace': {service: 'vehicleLicense', imageType: 'front'}, //行驶证正页
'vehicleCardBack': {service: 'vehicleLicense', imageType: 'back'}, //行驶证副页
}
if(!ocrService[cameraType]) return //OCR服务不存在则跳出
const {service, imageType} = ocrService[cameraType]
const uploadRes = await uploadImg(url) //获取文件ID
const fileId = JSON.parse(uploadRes).data?.path;
const reqData = {'aux': {document: fileId, imageType}}
const res = await OCRService(service, reqData)
this.onOcrCallback(res.data.data, cameraType)
},
//OCR回显
onOcrCallback(data, cameraType){
const {idCard, driverLicense} = this.formData
switch(cameraType){
case 'idCardFace': //身份证正面
this.formData = Object.assign(this.formData, {
name: data.name,
gender: this.genderViewEnums.find(item => item.label === data.gender)?.value,
idCard: Object.assign(idCard, {code: data.idCardNumber})
});
break;
case 'idCardBack': //身份证反面
this.formData = Object.assign(this.formData, {
idCard: Object.assign(idCard, {
effectiveDate: data.issuingDate, //生效日期
expirationDate: data.expiryDate, //失效日期
})
});
break;
case 'driveCardFace': //驾驶证正面
this.formData = Object.assign(this.formData, {
name: data.name,
gender: this.genderViewEnums.find(item => item.label === data.gender)?.value,
driverLicense: Object.assign(driverLicense, {
code: data.idCardNumber, //证件号码
quasiDrivingType: data.driverType, //准驾车型
effectiveDate: data.effectiveStartTime, //生效日期
expirationDate: data.expiryDate, //失效日期
})
})
break;
case 'driveCardBack': //驾驶证反面
this.formData = Object.assign(this.formData, {
name: data.name,
driverLicense: Object.assign(driverLicense, {code: data.idCardNumber})
})
break;
}
}
}
}
</script>
<style lang="scss">
.registerDriver {
.module-title {
padding: 32rpx 32rpx 16rpx;
.vertical-separate {
height: 40rpx;
border-left: 7rpx solid #797979;
margin-right: 20rpx;
}
}
/deep/.basicInfo,
/deep/.driverLicense,
/deep/.driverJobCertificate {
padding: 0 40rpx;
background-color: #ffffff;
.input-tip {
font-size: 28rpx;
color: #BFBFBF;
}
.u-form-item__body__left__content__label {
color: #8C8C8C;
font-size: 28rpx;
}
.u-form-item__body {
padding: 40rpx 0;
}
.u-icon {
margin-left: 20rpx;
}
}
/deep/.driverLicense-uploader-img,
/deep/.driverJobCertificate {
.u-upload__wrap>view {
width: 100%;
}
.previewImages {
width: 100%;
.previewImg {
width: 100% !important;
height: 240rpx !important;
}
}
.uploadeBtn {
width: 100% !important;
height: 240rpx !important;
margin-bottom: 30rpx;
margin-left: 0 !important;
}
.orderTotal {
display: none;
}
}
}
</style>
<template>
<view class="registerTruck content_box">
<u-toast ref="uToast" />
<!-- 注册内容 -->
<u--form :model="formData" :rules="rules" ref="myForm" errorType='none'>
<!-- 基本信息 -->
<view class="module-title flex">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">基本信息</text>
</view>
<view class="basic-info">
<u-form-item prop="name" required label="车牌号" labelWidth="20%" borderBottom>
<u-input border="none" placeholder="请输入车牌号" v-model="formData.name" />
</u-form-item>
<u-form-item prop="facilityModeId" label="车型" labelWidth="20%" borderBottom>
<view @click="onVisible('facilityModeId')">
<u-input border="none" readonly placeholder="请选择车型" :value="facilityViewEnums[formData.facilityModeId]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index="facilityModeId" />
</u-form-item>
<u-form-item prop="driver1Id" label="主驾" labelWidth="20%">
<view @click="onVisible('driver1Id')">
<u-input border="none" readonly placeholder="请选择主驾" :value="driverViewEnums[formData.driver1Id]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index="driver1Id" />
</u-form-item>
<u-form-item prop="ownerId" label="承运商" labelWidth="20%">
<view @click="onVisible('ownerId')">
<u-input border="none" readonly placeholder="请选择承运商" :value="ownerIdViewEnums[formData.ownerId]" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisible" index="ownerId" />
</u-form-item>
</view>
<!-- 行驶证 -->
<view class="module-title flex">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">行驶证</text>
</view>
<view class="driving-license">
<u-form-item prop="code" label="行驶证号" labelWidth="25%" borderBottom>
<u-input border="none" placeholder="请输入行驶证号" v-model="formData.code" />
</u-form-item>
<u-form-item prop="effectiveDate" label="生效日期" labelWidth="25%" borderBottom>
<view @click="onVisibleDate('effectiveDate')">
<u-input border="none" readonly placeholder="请选择生效日期" :value="convertTime(formData.effectiveDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index='effectiveDate' />
</u-form-item>
<u-form-item prop="expirationDate" label="失效日期" labelWidth="25%" borderBottom>
<view @click="onVisibleDate('expirationDate')">
<u-input border="none" readonly placeholder="请选择失效日期" :value="convertTime(formData.expirationDate)" />
</view>
<u-icon slot="right" name="arrow-right" @click="onVisibleDate" index="expirationDate" />
</u-form-item>
<u-form-item label="证件照片" labelWidth="25%" />
<bs-uploader maxCount="1" btnTitle="上传行驶证件" ref="faceImage" cameraType="vehicleCardFace" @customUploadAfter="onUploadOCR" />
</view>
</u--form>
<!-- 底部按钮 -->
<view class="operation-btn flex_sb">
<button class="backBtn common_btn" @click="onNavBack">返回</button>
<button class="submitBtn common_btn" @click="onSubmitForm">注册</button>
</view>
<!-- 类型选择动作面板 -->
<bs-selectPopup ref="selectPopup" :popTitle="popTitle" :selectEnum="optionEnums" :visible="visible"
@onVisible="onVisible" @onConfirm="onConfirmPicker" />
<!-- 时间选择 -->
<bs-datetimePicker ref="myTimePicker" :visible="showPopup" @onVisible="onVisibleDate"
@onSelsectDate="onSelsectDate" />
</view>
</template>
<script>
import { serviceRegister, queryTruckType, searchDriverList,GetCarrierList, uploadImg, OCRService} from '../../api/apiList'
import { formatTime } from '../../utils/util.js'
export default {
options: { styleIsolation: 'shared' },
data() {
return {
formData: {
name: "", //车牌
facilityModeId: "", //车型id
driver1Id: "", //司机id
code: "", //证件号码
effectiveDate: "", //生效日期
expirationDate: "", //失效日期
faceImage: "", //证件照片
ownerId: ''
},
rules: {
'name': { required: true },
},
visibleKey: '', //当前显示字段的key
optionEnums: [], //候选项枚举
popTitle: '', //弹窗标题
facilityViewEnums: [], //车型视图枚举
driverViewEnums: [], //主驾视图枚举
visible: false, //类型选择
showPopup: false, //时间选择
ownerIdViewEnums: []
}
},
methods: {
//返回上一级页面
onNavBack() {
uni.navigateBack()
},
// 提交表单数据
onSubmitForm() {
this.$refs.myForm.validate().then(res => {
this.$refs.faceImage.uploadImage(imgs => {
let reqData = { "aux": { ...this.formData } }
reqData.aux.faceImage = imgs
reqData.aux.effectiveDate = formatTime(new Date(reqData.aux.effectiveDate))
reqData.aux.expirationDate = formatTime(new Date(reqData.aux.expirationDate))
serviceRegister('Truck', reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '注册成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
})
}).catch(errors => {
this.$refs.uToast.show({
message: '请完善必填信息',
})
})
},
//类型选择
async onVisible(type) {
if (this.visible) {
this.visible = false
} else {
let optionEnums = []
let setKey = '' //要设置的字段Key
let resData = '' //响应数据
const reqData = {
args: { pageNum: 1, pageSize: 1000 }
}
if (type === 'facilityModeId') {
setKey = 'facilityViewEnums'
resData = await queryTruckType(reqData)
this.popTitle = '请选择车型'
} else if (type === 'ownerId') {
setKey = 'ownerIdViewEnums'
resData = await GetCarrierList(reqData)
this.popTitle = '请选择承运商'
}else if (type === 'driver1Id') {
setKey = 'driverViewEnums'
resData = await searchDriverList(reqData)
this.popTitle = '请选择主驾'
}
resData.data.data.datas.map(item => {
optionEnums.push({ 'label': item.name, 'value': item.id })
})
this.setViewEnums(optionEnums, setKey)
this.$refs.selectPopup.setSelect('')
this.optionEnums = optionEnums
this.visibleKey = type
this.visible = true
}
},
//转换显示枚举
setViewEnums(optionEnums, key) {
let viewEnums = {}
optionEnums.map(item => {
viewEnums[item.value] = item.label
})
this[key] = viewEnums
},
//确认选择
onConfirmPicker(value) {
this.setFormData(value)
this.visible = false
},
// 时间选择
onSelsectDate(dateInfo) {
const { timestamp } = dateInfo
this.setFormData(timestamp)
this.showPopup = false
},
//设置formData
setFormData(value) {
const key = this.visibleKey
if (key.includes('.')) { //对象特殊处理
const keys = key.split('.')
this.formData[keys[0]][keys[1]] = value
} else {
this.formData[key] = value
}
},
//关闭时间选择框
onVisibleDate(type) {
if(type){
this.visibleKey = type
}
this.showPopup = !this.showPopup
},
//页面展示时间戳转换为日期
convertTime(timestamp) {
if (!timestamp) return
const nowDate = new Date(timestamp)
var year = nowDate.getFullYear();
var month = nowDate.getMonth() + 1;
var date = nowDate.getDate();
return `${year}-${ month}-${date}`
},
async onUploadOCR(fileInfo){
const {url, cameraType} = fileInfo
const ocrService = {
'vehicleCardFace': {service: 'vehicleLicense', imageType: 'front'}, //行驶证正页
'vehicleCardBack': {service: 'vehicleLicense', imageType: 'back'}, //行驶证副页
}
if(!ocrService[cameraType]) return //OCR服务不存在则跳出
const {service, imageType} = ocrService[cameraType]
const uploadRes = await uploadImg(url) //获取文件ID
const fileId = JSON.parse(uploadRes).data?.path;
const reqData = {'aux': {document: fileId, imageType}}
const res = await OCRService(service, reqData)
this.onOcrCallback(res.data.data, cameraType)
},
//OCR回显
onOcrCallback(data, cameraType){
switch(cameraType){
case 'vehicleCardFace': //行驶证正面
this.name = data.licenseNumber //车牌号
this.code = data.vehicleIdentificationNumber //车辆识别代码
this.effectiveDate = data.issuingDate //生效日期
break;
case 'vehicleCardBack': //行驶证反面
this.name = data.licenseNumber //车牌号
break;
}
}
}
}
</script>
<style lang="scss">
.registerTruck {
.module-title {
padding: 32rpx 32rpx 16rpx;
.vertical-separate {
height: 40rpx;
border-left: 7rpx solid #797979;
margin-right: 20rpx;
}
}
/deep/.basic-info,
/deep/.driving-license {
padding: 0 40rpx;
background-color: #ffffff;
.input-tip {
font-size: 28rpx;
color: #BFBFBF;
}
.u-form-item__body__left__content__label {
color: #8C8C8C;
font-size: 28rpx;
}
.u-form-item__body {
padding: 40rpx 0;
}
.u-icon {
margin-left: 20rpx;
}
.u-upload__wrap>view {
width: 100%;
}
.previewImages {
width: 100%;
.previewImg {
width: 100% !important;
height: 240rpx !important;
}
}
.uploadeBtn {
width: 100% !important;
height: 240rpx !important;
margin-bottom: 30rpx;
margin-left: 0 !important;
}
.orderTotal {
display: none;
}
}
}
</style>
<template>
<view class="reserveDock content_box">
<view class="consumer_code">
<text user-select>运单号:{{shipmentNo}}</text>
</view>
<view class="stops-list">
<view class="panel-title font_bolder">预约到站时间</view>
<u-empty mode="data" textSize='32' iconSize="160" text="暂无可预约站点" v-if="!stopsDatas.length" />
<view class="routine_radius_card" v-for="item in stopsDatas" :key="item.stopsId">
<u--form>
<u-form-item :label="item.locationName" labelWidth="40%">
<u-input border="none" readonly inputAlign="right" placeholder="选择时间" placeholderClass="input-tip"
:value="item.arrivalTime ? `${item.arrivalTime}-${item.departureTime}` : ''"/>
<u-icon slot="right" name="arrow-right" @click="onNavReserveDetail" :index="item" />
</u-form-item>
<u-form-item label="道口" labelWidth="40%" v-if="item.dockId">
<u-input border="none" readonly inputAlign="right" :value="item.dockName" />
<u-icon slot="right" name="1" color="#fff" />
</u-form-item>
</u--form>
</view>
</view>
</view>
</template>
<script>
import { findShipmentStops } from '../../api/apiList'
import { formatGMT } from '../../utils/util'
const app = getApp()
export default {
data() {
return {
stopsDatas: [], //站点列表
shipmentNo: '', //运单号
shipmentId: '', //运单ID
}
},
onLoad(options) {
const { shipmentData } = JSON.parse(options.data)
const { shipmentNo, shipmentId } = app.globalData.shipmentInfo
this.shipmentNo = shipmentNo
this.shipmentId = shipmentId
},
onShow() {
this.initStops()
},
methods: {
//初始化站点列表
initStops() {
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": "shipment.id",
"type": "EQ",
"value": this.shipmentId
}]
}
}
findShipmentStops(reqData).then(res => {
let stopsDatas = res.data.data.datas
let ArrData = []
// stopsDatas.sort((a, b) => (a.stopNumber - b.stopNumber || b.loadStop - a.loadStop)) //站点排序
stopsDatas.map(stop => {
ArrData.push({
stopsId: stop.id,
locationName: stop['location.name'],
locationId: stop['location.id'],
dockId: stop['dock.id'],
dockName: stop['dock.name'],
arrivalTime: formatGMT(stop['planArrivalTime'], 'H'),
departureTime: formatGMT(stop['planDepartureTime'], 'H')
})
})
this.stopsDatas = ArrData
})
},
//跳转预约到站时间
onNavReserveDetail(stopInfo) {
const {stopsId, locationId} = stopInfo
const data = { stopsId, locationId }
uni.navigateTo({
url: `/subpkg/reserveDockTime/reserveDockTime?data=${JSON.stringify(data)}`,
})
}
}
}
</script>
<style lang="scss">
.reserveDock {
.stops-list {
margin-top: 50rpx;
.panel-title {
margin: 0 10rpx 20rpx;
}
.routine_radius_card {
margin-bottom: 40rpx;
.input-tip {
font-size: 28rpx;
color: #999999;
}
.u-form-item__body {
padding: 4rpx;
.u-form-item__body__left__content__label {
font-size: 28rpx;
font-weight: bolder;
}
.u-icon {
margin-left: 20rpx;
}
}
}
}
}
</style>
<template>
<view class="reserveDock content_box">
<shipmentBriefInfo />
<view class="select-date flex_sb">
<view class="prevDate" :class="{forbidClick:isToday}" @click="onPrev">前一天</view>
<view class="currentDate">{{convertTime(timestamp)}}</view>
<view class="nextDate" @click="onNext">后一天</view>
</view>
<!-- 道口选择 -->
<view class="selectDock" v-if="dockList.length">
<bs-customCell label="月台" labelCol="2" wrapCol="9.5">
<text slot="value" @click="onVisible" style="display: block;">{{showEnums[dockId]}}</text>
<u-icon slot="right-icon" name="arrow-right" size="36" @click="onVisible" />
</bs-customCell>
</view>
<!-- 可选日期列表 -->
<view class="dock-time-table">
<view class="table-title flex flex_center">
<!-- <view class="vertical-separate" /> -->
<text class="font_bolder">选择时段</text>
</view>
<view class="table-label">
<u-row>
<u-col span="6"> 时段</u-col>
<u-col span="4">可预约</u-col>
<u-col span="2" textAlign="center">选择</u-col>
</u-row>
</view>
<view class="table-value-list">
<u-empty mode="data" textSize='32' iconSize="160" text="暂无可预约时间" v-if="!dockTimes.length" />
<view :class="['table-value-item', reserveTimeId === item.id ? 'activeClass' : '']"
v-for="item in dockTimes" :key="item.id" @click="onSelectTime(item.id)">
<u-row>
<!-- 可预约时间 -->
<u-col span="6"> {{item.startTime}} - {{item.endTime}}</u-col>
<u-col span="4.3">
<!-- 可预约量 -->
<template>
<!-- 可预约车次 -->
<!-- <text>{{item.shipmentCapacity - item.actualShipments}}</text> -->
<!-- 可预约件数 -->
<!-- <text>{{item.qtyCapacity - item.actualQty}}</text> -->
<!-- 可预约重量 -->
<!-- <text>{{item.weightCapacity - item.actualWeight}}千克</text> -->
<!-- 可预约体积 -->
<text :style="{'color': item.volumeCapacity - item.actualVolume > 0 ? '' : '#AAAAAA'}">
{{item.volumeCapacity - item.actualVolume}}
</text>
</template>
</u-col>
<u-col span="2" textAlign="center">
<u-radio-group :value="reserveTimeId" placement="column">
<u-radio checked="true" :size="40" :iconSize="32" :name="item.id" @change="onSelectTime(item.id)" :disabled="item.volumeCapacity - item.actualVolume < 0"/>
</u-radio-group>
</u-col>
</u-row>
</view>
</view>
</view>
<!-- 预约按钮 -->
<view class="operation-btn flex_sb">
<button class="backBtn common_btn" @click="openCancelPop">取消预约</button>
<button class="submitBtn common_btn" :style="reserveTimeId === ''?'background-color:#f8f8f8;color: #8c8c8c;background: none;':''" :disabled="reserveTimeId === ''" @click="onConfirm">预约</button>
</view>
<!-- 类型选择动作面板 -->
<bs-selectPicker ref="mySelectPicker" :pickerEnums="dockList" :visible="visible" @onVisible="onVisible"
@onConfirm="onConfirmPicker" />
<view class="reservePop">
<u-popup :show="cancelPop" mode="center">
<view>
<view class="cancel_pop_header">取消预约</view>
<view class="cancel_pop_content">{{`是否取消 ${reserveTime.arrivalDay} ${reserveTime.arrivalTime}-${reserveTime.departureTime} ${showEnums[dockId]?"在":''}${ showEnums[dockId] || ''} 的预约`}}</view>
<view class="cancel_pop_foot flex_sb">
<button @click="cancelPop = false">取消</button>
<button class="submitBtn" @click="onCancel">确认</button>
</view>
</view>
</u-popup>
</view>
</view>
</template>
<script>
import { searchDockList, searchDockTime, loadDockBooking, dockBookingCancel } from '../../api/apiList';
import { formatTime, formatGMT } from '../../utils/util';
export default {
data() {
return {
dockTimes: [], //道口可预约时间列表
dockId: "", //道口id
addressId: '', //地址id
stopsId: '', //站点id
reserveTimeId: '', //当前可预约时间表id
timestamp: new Date().getTime(), //当前日期时间
dockList: [], //道口地址枚举
showEnums: {}, //页面显示使用
visible: false,
cancelPop: false,
reserveTime:{}
}
},
computed: {
listenChange() {
const { dockId, timestamp } = this
return { dockId, timestamp }
},
isToday() {
return new Date(this.timestamp).toDateString() === new Date().toDateString() || new Date(this.timestamp) < new Date()
},
},
watch: {
listenChange(val) {
this.onReloadDockTime()
}
},
onLoad(options) {
const { stopsId, locationId, arrivalDay, arrivalTime, departureTime, dockId } = JSON.parse(options.data)
this.stopsId = stopsId
this.addressId = locationId
this.reserveTime = {
arrivalDay,arrivalTime,departureTime
}
this.getDockList()
if(dockId){
this.dockId = dockId
}
},
methods: {
//获取道口枚举
getDockList() {
const _this = this
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": "address.id",
"type": "EQ",
"value": this.addressId
}]
}
}
searchDockList(reqData).then(res => {
const datas = res.data.data.datas
let optionEnums = []
let showEnums = {}
datas.map(item => {
showEnums[item.id] = item.name
optionEnums.push({ label: item.name, value: item.id })
})
if (optionEnums.length && !_this.dockId) {
const dockId = optionEnums[0].value
_this.dockId = dockId
}
_this.setPickerValue(_this.dockId)
this.dockList = [...optionEnums]
this.showEnums = showEnums
})
},
//Picker弹窗
onVisible() {
const { visible, dockId } = this
if (visible) {
this.visible = false
} else {
this.setPickerValue(dockId)
this.visible = true
}
},
setPickerValue(dockId) {
const mySelectPicker = this.$refs.mySelectPicker
const index = this.dockList.findIndex(item => item.value === dockId)
mySelectPicker.setDefaultValue(index)
},
//确认选择
onConfirmPicker(value) {
const isReload = this.dockId !== value
if (isReload) { //仅切换道口时刷新道口可预约时间
this.dockId = value
}
this.visible = false
},
//刷新道口预约时间
onReloadDockTime() {
const { dockId, addressId, timestamp } = this
const workDate = formatTime(new Date(timestamp), 'D') //格式化时间
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": "address.id",
"type": "EQ",
"value": addressId
}, {
"field": "dock.id",
"type": "EQ",
"value": dockId
}, {
"field": "workDate",
"type": "EQ",
"value": workDate
}]
}
}
searchDockTime(reqData).then(res => {
const that = this
const datas = res.data.data.datas
const dateArr = []
datas.map(date => { //格式化后台返回时间
date.startTime = formatGMT(date.startTime, 'H')
date.endTime = formatGMT(date.endTime, 'H')
that.reserveTimeId = !that.reserveTimeId &&
formatGMT(timestamp,'D') === that.reserveTime.arrivalDay &&
date.startTime === that.reserveTime.arrivalTime &&
date.endTime === that.reserveTime.departureTime ? date.id : that.reserveTimeId
dateArr.push(date)
})
this.dockTimes = [...dateArr]
})
},
//选择预约时间
onSelectTime(id) {
const currentTime = this.dockTimes.find(item => item.id === id)
if (currentTime.volumeCapacity - currentTime.actualVolume > 0) { // 判断是否可选
this.reserveTimeId = id
} else {
uni.showToast({
title: '所选时段已约满,请选择其它时段',
icon: 'none',
duration: 3000
})
}
},
//确认预约
onConfirm() {
const { stopsId, reserveTimeId } = this
const reqData = {
"args": {
"selectedIds": [stopsId],
"additionalIds": {
"": {
"bizName": "md.DockTimeTable",
"selectedIds": [reserveTimeId]
}
}
}
}
loadDockBooking(reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '预约成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
},
//取消预约
onCancel() {
this.cancelPop = false
const { stopsId } = this
const reqData = {
"args":
{
"selectedIds":
[
stopsId
]
}
}
dockBookingCancel(reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '预约取消成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
},
openCancelPop(){
if(this.reserveTime.arrivalDay){
this.cancelPop = true
}else{
uni.showToast({
title:"暂无预约时间",
icon:'none',
duration: 2000
})
}
},
//前一天 24h转时间戳 24*60*60*1000
onPrev() {
this.timestamp -= 86400000
},
//后一天
onNext() {
this.timestamp += 86400000
},
//页面展示时间戳转换为日期
convertTime(timestamp) {
if (!timestamp) return
const nowDate = new Date(timestamp)
const year = nowDate.getFullYear();
const month = nowDate.getMonth() + 1;
const date = nowDate.getDate();
const day = nowDate.getDay();
const dayList = { //转换为大写星期
'0': '日',
'1': '一',
'2': '二',
'3': '三',
'4': '四',
'5': '五',
'6': '六',
}
return `${year}${ month}${date}日 周${dayList[day]}`
},
}
}
</script>
<style lang="scss">
.reserveDock {
font-size: 28rpx;
/deep/.u-empty__text{
margin-bottom: 24rpx;
}
.select-date {
background-color: #FFFFFF;
padding: 40rpx 32rpx;
font-weight: bolder;
.prevDate,
.nextDate {
color: #5B8BFC
}
.forbidClick{
pointer-events: none;
color: #BFBFBF;
}
}
.selectDock {
margin-top: 24rpx;
background-color: #FFFFFF;
padding: 40rpx 32rpx;
/deep/.custom-cell-row {
margin-top: 0;
.custom-cell-label {
color: #8C8C8C;
}
}
}
.dock-time-table {
margin-top: 40rpx;
background-color: #FFFFFF;
.table-title {
padding: 32rpx;
.vertical-separate {
height: 40rpx;
border-left: 7rpx solid #797979;
margin-right: 20rpx;
}
}
.table-label {
padding: 10rpx 32rpx;
color: #8C8C8C;
background-color: #FAFAFA;
}
/deep/.table-value-list {
padding: 0 32rpx;
.table-value-item {
margin: 40rpx 0;
padding-right: 10rpx;
.u-radio {
justify-content: center;
}
}
.activeClass {
color: #2E5BFB;
}
}
}
.reservePop{
/deep/.u-popup{
flex: none !important;
.u-popup__content{
width: 620rpx;
height: 378rpx;
border-radius: 24rpx;
padding: 32rpx;
.cancel_pop_header{
width: 144rpx;
height: 50rpx;
font-size: 36rpx;
line-height: 50rpx;
}
.cancel_pop_content{
margin-top: 40rpx;
width: 556rpx;
height: 80rpx;
text-align: center;
font-size: 28rpx;
}
.cancel_pop_foot{
margin-top: 64rpx;
button{
width: 262rpx;
height: 80rpx;
font-size: 32rpx;
color: #2e75e6;
border-radius: 40rpx;
border: 2rpx solid #2e75e6;
background-color: #FFFFFF;
}
.submitBtn{
background-color: #2e75e6 !important;
color: #FFFFFF !important;
border: none !important;
}
}
}
}
}
}
</style>
<template>
<scroll-view class="shipmentDetail content_box">
<shipmentCard :propData="shipmentData" />
<view class="operation-btn" style="margin-top: 10rpx;margin-bottom: 0;">
<button class="common_btn" @click="onNavTransfer" data-action="transferAndChangeTruck">中转换车</button>
<button class="common_btn" @click="onNavTransfer" data-action="transferAndUnload">中转卸货</button>
<button class="common_btn" @click="onNavAllot" data-path="/subpkg/allotTruck/allotTruck">配车</button>
<button class="common_btn" @click="onNavAllot" data-path="/subpkg/signFor/signFor">纸质签收</button>
<view style="width: 370rpx" />
</view>
<!-- 预约站点 -->
<view class="module-title flex_sb">
<text>预约站点</text>
<view class="flex_center" @click="onNavShipmentLbs" data-path="/subpkg/shipmentLbs/shipmentLbs">
<view class="t-icon t-icon-view-track"></view>
<text style="margin-left: 10rpx; color: #434343; font-weight: 400;">查看轨迹</text>
</view>
</view>
<view class="station-list">
<view class="station-item flex_center flex_sb" v-for="item in stopsDatas" :key="item.stopsId"
@click.capture="onClickStops(item)">
<view class="station-type" :style="{'background-color': item.loadStop ? '#2E75E6' : '#F7A64A'}">
{{item.loadStop ? '装' : '卸'}}
</view>
<view class="station-detail flex_col" @click="onNavReserveDetail(item)">
<view class="flex_sb" :style="[{'margin-top': item.dockId ? '50rpx': '0'} ]">
<view class="station-title font_bolder" @click.stop>{{item.locationName}}</view>
<template v-if="!item.dockId">
<view class="station-item-right flex_center" data-path="/subpkg/reserveDock/reserveDock">
<view class="station-time">
{{item.arrivalTime ? `${item.arrivalDay} ${item.arrivalTime}-${item.departureTime}` : '选择时间'}}
</view>
<view class="t-icon t-icon-rightArrow" />
</view>
</template>
</view>
<!-- 道口存在时展示样式,反之采用默认展示 -->
<template v-if="item.dockId">
<view style="padding-bottom: 24rpx;">
<bs-customCell :label="item.dockName" labelCol="4.4" wrapCol="7"
:value="`${item.arrivalDay} ${item.arrivalTime}-${item.departureTime}`">
<view slot="right-icon" class="t-icon t-icon-rightArrow" />
</bs-customCell>
</view>
</template>
</view>
</view>
</view>
<view class="module-title">订单列表</view>
<view class="order-list">
<orderCard v-for="item in orderDetails" :key="item.id" :propData="item" />
<view class="order-empty flex_cen" v-if="!orderDetails.length">
<u-empty mode="data" textSize='32' iconSize="160" text="暂无订单" />
</view>
</view>
</scroll-view>
</template>
<script>
import {
findShipmentDetail,
ordermovementOM,
ordermovementOR,
ordermovementMASS,
findShipmentStops
} from '../../api/apiList.js'
import { formatGMT } from '../../utils/util.js'
const appInstance = getApp()
export default {
data() {
return {
shipmentData: '', //运单简要信息
orderDetails: [], //订单明细
shipmentId: '', //运单id
stopsDatas: [], //站点列表
}
},
onLoad(options) {
const shipmentId = options.id
const { shipmentBizName } = appInstance.globalData.shipmentInfo
this.shipmentId = shipmentId
this.initOrderDetail(shipmentId, shipmentBizName)
},
onShow() {
this.initData(this.shipmentId)
this.initStops(this.shipmentId)
appInstance.globalData.transferAddress = {} //清除中转数据缓存
},
methods: {
//初始化运单信息
initData(shipmentId) {
const data = {
"aux": {
"id": shipmentId
}
}
findShipmentDetail(data).then(res => {
const data = res.data.data
data.header.shipmentDate = formatGMT(data.header.shipmentDate, 'D') //格式化时间
data.header.loadRate = (data.header.loadRate * 100).toFixed() //装载率格式化
this.shipmentData = JSON.stringify(data)
})
},
//初始化站点列表
initStops(shipmentId) {
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": "shipment.id",
"type": "EQ",
"value": shipmentId
}]
}
}
findShipmentStops(reqData).then(res => {
let stopsDatas = res.data.data.datas
let ArrData = []
stopsDatas.sort((a, b) => (a.stopNumber - b.stopNumber || b.loadStop - a.loadStop)) //站点排序
stopsDatas.map(stop => {
ArrData.push({
stopsId: stop.id,
locationName: stop['location.name'],
locationId: stop['location.id'],
dockId: stop['dock.id'],
dockName: stop['dock.name'],
loadStop: stop['loadStop'],
unloadStop: stop['unloadStop'],
arrivalTime: formatGMT(stop['planArrivalTime'], 'M'),
departureTime: formatGMT(stop['planDepartureTime'], 'M'),
arrivalDay: formatGMT(stop['planArrivalTime'], 'D'),
locationAddress: this.getLocationCity(stop), //站点地址
locationOrders: stop.loadOrders || stop.unloadOrders, //订单数
locationQty: stop.planLoadQty || stop.planUnloadQty, //件数数
locationWeight: stop.planLoadWeight || stop.planUnloadWeight, //重量
locationVolume: stop.planLoadVolume || stop.planUnloadVolume, //体积
})
})
this.stopsDatas = ArrData
})
},
//初始化订单信息
initOrderDetail(shipmentId, shipmentBizName) {
const _this = this
let shipmentMode = ''
switch (shipmentBizName) { //根据shipmentBizName 判断运输模式
case 'tm.MovementShipment':
case 'tm.SectionShipment': //暂时走OM逻辑
shipmentMode = 'OM'
break
case 'tm.MassShipment':
shipmentMode = 'MS'; //大宗运输
break
default:
shipmentMode = 'OR';
}
if(shipmentMode === 'MS'){
const reqData = { "aux": { "id": shipmentId } }
ordermovementMASS(reqData).then(res => {
const data = res.data.data.header
const newDetail = {
'id': data['massOrder.id'], //订单id
'orderNo': data['massOrder.orderNo'], //订单号
'qty': data['massOrder.qty'], //订单件数
'weight': data['massOrder.weight'], //订单重量
'volume': data['massOrder.volume'], //订单体积
'originalAddress.name': data['massOrder.originalAddress.name'], //发货地址
'originalContact.name': data['massOrder.originalContact.name'], //发货人
'originalContact.tel': data['massOrder.originalContact.tel'], //发货人联系方式
'originalContact.remark': data['massOrder.originalContact.remark'], //发货人备注
'destinationAddress.name': data['massOrder.destinationAddress.name'], //收货地址
'destinationContact.name': data['massOrder.destinationContact.name'], //收货人
'destinationContact.tel': data['massOrder.destinationContact.tel'], //收货人联系方式
'destinationContact.remark': data['massOrder.destinationContact.remark'], //收货人备注
'originalRequirement': data['massOrder.originalRequirement'], //提货要求
'destinationRequirement': data['massOrder.destinationRequirement'], //配送要求
'transportRequest': data['massOrder.transportRequest'], //运输要求
'actualPod.podImages': data['massOrder.actualPod.podImages'], //回单图片
}
_this.orderDetails = _this.orderDetails.concat(newDetail)
})
} else {
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": "shipment.id",
"type": "EQ",
"value": shipmentId
}]
}
}
const isOM = shipmentMode === 'OM'
const requestFun = isOM ? ordermovementOM : ordermovementOR
requestFun(reqData).then(res => {
const datas = res.data.data.datas
const newDatas = _this.convertData(isOM, datas)
_this.orderDetails = [...newDatas]
})
}
},
//转换请求数据
convertData(isOM, datas) {
let newDatas = []
if (isOM) { //OM模式时自定义数据字段名,默认使用简易的OR模式字段名
datas.map(item => {
newDatas.push({
'id': item.id, //订单id
'orderNo': item.movementNo, //订单号
'qty': item.shipQty, //订单件数
'weight': item.shipWeight, //订单重量
'volume': item.shipVolume, //订单体积
'originalAddress.name': item['originalAddress.name'], //发货地址
'originalContact.name': item['originalAddress.addressContact.name'], //发货人
'originalContact.tel': item['originalAddress.addressContact.tel'], //发货人联系方式
'originalContact.remark': item['originalAddress.addressContact.remark'], //发货人备注
'destinationAddress.name': item['destinationAddress.name'], //收货地址
'destinationContact.name': item['destinationAddress.addressContact.name'], //收货人
'destinationContact.tel': item['destinationAddress.addressContact.tel'], //收货人联系方式
'destinationContact.remark': item['destinationAddress.addressContact.remark'], //收货人备注
'originalRequirement': item['orderRelease.originalRequirement'], //提货要求
'destinationRequirement': item['orderRelease.destinationRequirement'], //配送要求
'transportRequest': item['orderRelease.transportRequest'], //运输要求
'actualPod.podImages': item['orderRelease.actualPod.podImages'], //回单图片
})
})
} else {
newDatas = [...datas]
}
return newDatas
},
//监听面板点击事件
onClickStops(data) {
appInstance.globalData.stopsInfo = data
},
//页面跳转
onNavAllot(e) {
const data = {
shipmentData: JSON.parse(this.shipmentData)
}
const path = e.currentTarget.dataset.path + `?data=${JSON.stringify(data)}`
uni.navigateTo({
url: path,
})
},
//中转操作
onNavTransfer(e) {
const action = e.target.dataset.action
const data = {
selectedId: this.shipmentId,
action
}
uni.navigateTo({
url: `/subpkg/transferChange/transferChange?data=${JSON.stringify(data)}`,
})
},
//跳转预约到站时间
onNavReserveDetail(stopInfo) {
const {stopsId, locationId, arrivalDay, arrivalTime, departureTime, dockId} = stopInfo
const data = {
stopsId,
locationId,
arrivalDay,
arrivalTime,
departureTime,
dockId
}
uni.navigateTo({
url: `/subpkg/reserveDockTime/reserveDockTime?data=${JSON.stringify(data)}`,
})
},
//跳转运单Lbs
onNavShipmentLbs(e) {
const shipmentData = JSON.parse(this.shipmentData)
const {id, shipmentNo} = shipmentData.header
const data = {shipmentId: id, shipmentNo}
const path = e.currentTarget.dataset.path + `?data=${JSON.stringify(data)}`
uni.navigateTo({
url: path,
})
},
}
}
</script>
<style lang="scss">
.shipmentDetail {
padding-bottom: 10rpx;
.module-title {
margin: 24rpx;
}
.order-empty {
min-height: 340rpx;
background-color: #FFFFFF;
}
.station-list {
margin-bottom: 24rpx;
.station-type {
color: #FFFFFF;
font-size: 32rpx;
font-weight: 500;
margin: 24rpx 24rpx 24rpx 0;
padding: 16rpx 20rpx;
text-align: center;
border-radius: 0 50% 50% 0;
}
.station-item {
margin-bottom: 24rpx;
padding-right: 32rpx;
background-color: #FFFFFF;
}
.station-detail {
flex-grow: 1;
.station-time {
font-size: 28rpx;
color: #8C8C8C;
margin-right: 8rpx;
white-space: nowrap;
}
/deep/.custom-cell-row {
color: #8C8C8C;
.custom-cell-value {
text-align: end;
white-space: nowrap;
margin-right: 8rpx;
}
}
}
/deep/.t-icon {
background-size: cover !important;
background-position: center !important;
}
}
}
</style>
<template>
<view class="order-tracks" @mouseup="onTouchend">
<!-- #ifndef MP -->
<map id="myMap" style="width: 100vw;height: 100vh;" />
<!-- #endif -->
<!-- #ifdef MP -->
<map id="myMap" style="width: 100vw;height: 100vh;" :polyline="polylines" :markers="markers" :include-points="includePoints" :enable-zoom="true">
<cover-view slot="callout" v-if="shipmentStopShowNumber">
<block v-for="(item,index) in markers" :key="index">
<cover-view class="customCallout shipment-stop-marker" :marker-id="item.id"> {{item.stopNumber}} </cover-view>
</block>
</cover-view>
</map>
<!-- #endif -->
<!--详情弹窗 -->
<view class="stops-steps-popup">
<u-popup :show="true" :overlay='false' round="60">
<view class="drag-btn" @touchstart="onTouchstart" @touchmove="onTouchmove" @touchend="onTouchend"
@mousedown="onTouchstart" @mousemove="onTouchmove" @mouseup="onTouchend">
<view class="drag-icon" />
</view>
<view class="poup-content" :style="{height: popupHeight}">
<!-- 途经站点 -->
<view class="stops-steps">
<view class="font_bolder module-title flex_sb">途经站点</view>
<view style="max-height: 500rpx;overflow-y: auto;">
<u-empty mode="data" textSize='28' iconSize="70" text="暂无详细" v-if="!stopsList.length" />
<!-- 步骤条 -->
<u-steps direction="column" v-else inactiveColor="#2E75E6">
<u-steps-item v-for="(item,index) in stopsList" :key="index">
<view class="slot-icon" slot="icon" style="position: relative;">
<image :src="stepIcon" style="width: 36rpx;height: 36rpx;">
<text class="stepIconNum">{{item.stopNumber}}</text>
</view>
<view :class="['step-desc flex']" slot="desc">
<view class="font_bolder overflowOmitRows" style="margin-right: 48rpx;width: 230rpx;">{{item.name}}</view>
<view class="flex_col">
<template v-if="item.stopNumber === 1">
<view class="flex_center">
<text class="desc-title">计划离开</text>
<text class="desc-value">{{item.planDepartureTime}} </text>
</view>
<view class="flex_center">
<text class="desc-title">实际离开</text>
<text class="desc-value" :style="[{'color': item.statusColor}]"> {{item.actualDepartureTime}} </text>
</view>
</template>
<template v-if="item.stopNumber === 2">
<view class="flex_center">
<text class="desc-title">计划到达</text>
<text class="desc-value">{{item.planArrivalTime}} </text>
</view>
<view class="flex_center">
<text class="desc-title">实际到达</text>
<text class="desc-value" :style="[{'color': item.statusColor}]">{{item.actualArrivalTime}} </text>
</view>
<view class="flex_center">
<text class="desc-title">计划离开</text>
<text class="desc-value">{{item.planDepartureTime}} </text>
</view>
<view class="flex_center">
<text class="desc-title">实际离开</text>
<text class="desc-value" :style="[{'color': item.statusColor}]">{{item.actualDepartureTime}} </text>
</view>
</template>
<template v-if="item.stopNumber === 3">
<view class="flex_center">
<text class="desc-title">计划到达</text>
<text class="desc-value">{{item.planArrivalTime}} </text>
</view>
<view class="flex_center">
<text class="desc-title">实际到达</text>
<text class="desc-value" :style="[{'color': item.statusColor}]">{{item.actualArrivalTime}} </text>
</view>
</template>
</view>
</view>
</u-steps-item>
</u-steps>
</view>
</view>
</view>
</u-popup>
</view>
</view>
</template>
<script>
import { findShipmentLbs, getMap, getMapColor } from '../../api/apiList'
export default {
options: { styleIsolation: 'shared' },
data() {
return {
stopsList: [], //途经站点
shipmentStopShowNumber: false, //运输轨迹站点是否显示数字
completeTracks: [], //补全轨迹
points: [], //实际轨迹
popupHeight: '200rpx', //弹窗高度
isMove: false, //是否可移动
currentPosition: [], //当前位置坐标
mapStyle: 0, //默认地图样式
mapStyleList: [], //地图样式列表
mapTheme: {}, //地图主题色
lbsLowSpeed: 30, //最低速
lbsOverSpeed: 80, //最高速
stepIcon: '',
polylines: [], //仅小程序地图展示数据
markers: [], //仅小程序地图展示数据
includePoints: [], //地图缩放显示所含坐标点,仅小程序地图展示数据
}
},
onLoad: function(options) { //todo 定位为定车辆位置
const { shipmentId, shipmentNo } = JSON.parse(options.data)
this.initData(shipmentId, shipmentNo) //获取LBS数据
//初始化运单事件图片
// #ifdef H5
this.stepIcon = "../../static/img/steps/stepIcon.png"
// #endif
// #ifdef MP
const base64 = 'data:image/jpg;base64,' //小程序不支持png格式,故转为base64
this.stepIcon = base64 + uni.getFileSystemManager().readFileSync("static/img/steps/stepIcon.png",'base64');
// #endif
},
methods: {
//获取地图实例
async getMapInstance() {
let mapCtx = null //MAap 上下文
let newMap = null //MAap 实例
const { serviceProvider, MapIns } = getApp().globalData
// #ifdef MP
newMap = MapIns
mapCtx = uni.createMapContext('myMap')
// #endif
// #ifdef H5
mapCtx = MapIns
newMap = new MapIns.Map('myMap');
if (serviceProvider === 'BMap') { //百度地图初始化设置
const point = new MapIns.Point(112.324224, 33.678136);
newMap.centerAndZoom(point, 5); //初始化地图,设置中心点坐标和地图级别
newMap.addControl(new MapIns.ScaleControl()) // 添加比例尺控件
newMap.enableScrollWheelZoom(); //开启鼠标滚轮缩放
}
let mapStyle = this.mapStyleList[this.mapStyle]; //设置地图样式
newMap.setMapStyle(mapStyle.value)
// #endif
return Promise.resolve({ mapCtx, newMap });
},
//获取地图主题、颜色
findMapThem() {
return new Promise(reslove => {
getMapColor({}).then(res => {
if (res) {
const { mapStyle, mapStyleList, trackColor, shipmentStopShowNumber, lowSpeed, overSpeed} = res.data.data
this.mapStyle = mapStyle
this.mapStyleList = mapStyleList
this.mapTheme = { 'light': trackColor, 'dark': trackColor }
this.shipmentStopShowNumber = shipmentStopShowNumber
this.lbsLowSpeed = lowSpeed
this.lbsOverSpeed = overSpeed
reslove('done')
}
})
})
},
//获取LBS数据
initData(shipmentId, shipmentNo) {
this.$nextTick(async () => {
await this.findMapThem() //获取地图主题色
const { newMap, mapCtx } = await this.getMapInstance() //初始化地图实例
const reqData = {"aux": {id: shipmentId, shipmentNo}} //shipmentNo||shipmentId 528807204405383168
const res = await findShipmentLbs(reqData)
const { stops, completeTracks, tracks, points } = res.data.data || {}
const message = res.data.message
if (message) {
uni.showToast({title: message, icon: 'none', duration: 3000})
}
this.initStops(stops)
this.trackAnalysis(points, newMap, mapCtx) //实际轨迹线路
this.addStopsLine(completeTracks, newMap, mapCtx) //补全轨迹线路
// this.addStopsLine(tracks, newMap, mapCtx) //标准轨迹线路
this.addStopsMarkers(stops, newMap, mapCtx) //添加站点标记
})
},
initStops(stops){
const _this = this
stops.forEach(item => { // 处理每一个经停站是否超时
item.statusColor = _this.getStatusColor(item)
})
this.stopsList = stops.reverse()
},
getStatusColor(item){
let color = '#8C8C8C'
if(item.actualDepartureTime && item.planDepartureTime){ // 实际离开是否超时
color = new Date(item.actualDepartureTime).getTime() - new Date(item.planDepartureTime).getTime() > 0 ? '#EB2F48' : '#3DCCB9'
}
if(item.actualArrivalTime && item.planArrivalTime){ // 实际到达是否超时
color = new Date(item.actualArrivalTimee).getTime() - new Date(item.planArrivalTime).getTime() > 0 ? '#EB2F48' : '#3DCCB9'
}
return color
},
trackAnalysis(points=[], newMap, mapCtx){
if(!points.length) return
let tracks = [{lbsPointList: []}]
for (let i = 0; i < points.length; i++) { //按速度将坐标点分段
let point = points[i]
//相同点去除
if (i > 0 && point.lat === points[i -1].lat && point.lng === points[i - 1].lng) {
continue
}
let status = this.getSpeedType(point)
if (tracks[tracks.length - 1].lbsPointList.length === 0) {
tracks[tracks.length - 1].status = status
} else if (tracks[tracks.length - 1].status !== status) {
tracks.push({lbsPointList: [], status})
}
tracks[tracks.length - 1].lbsPointList.push(point)
}
//分段后拼接轨迹
for (let i = 1; i < tracks.length; i++) {
tracks[i - 1].lbsPointList.push(tracks[i].lbsPointList[0])
}
this.addStopsLine(tracks, newMap, mapCtx)
},
//判断速度类型
getSpeedType(point){
let minSpeed = this.lbsLowSpeed
let maxSpeed = this.lbsOverSpeed
if (point.speed < minSpeed) {
return "LOW_SPEED"
} else if (point.speed > maxSpeed) {
return "HIGH_SPEED"
} else {
return "NORMAL_SPEED"
}
},
//添加站点连线
addStopsLine(tracks, newMap, MapInstance) { //newMap: 地图对象 MapInstance: 地图实例, 小程序中为地图上下文
for (let i in tracks) {
let track = tracks[i]
let lbsPointList = track.lbsPointList
if (lbsPointList.length === 0) {
continue;
}
this.addPolyLine(lbsPointList, track.status, newMap, MapInstance)
}
},
//添加连线
addPolyLine(points, trackStatus, newMap, MapInstance) {
if (!points.length) return
let zIndex = 10;
if (trackStatus === 'STANDARD_TRACK') {
zIndex = 11
} else if (trackStatus === 'COMPLETE_TRACK') {
zIndex = 10
} else {
zIndex = 999
}
const strokeColor = this.getPolyLineColor(trackStatus)
const { serviceProvider } = getApp().globalData
let path = [] //转换线路坐标点
points.forEach(point => {
// #ifndef MP
if (serviceProvider === 'AMap') {
path.push([point.lng, point.lat])
} else {
path.push(new MapInstance.Point(point.lng, point.lat))
}
// #endif
// #ifdef MP
path.push({ latitude: point.lat, longitude: point.lng })
// #endif
})
// #ifndef MP
let line = null
if (serviceProvider === 'AMap') {
// 创建折线实例
line = new MapInstance.Polyline({
path: path,
zIndex,
strokeWeight: 6, // 线条粗细
strokeColor: strokeColor,
showDir: true, //沿路径显示白色箭头
cursor: '', //自定义鼠标悬停时样式
strokeOpacity: 1, //去除路线透明度
});
newMap.add([line]); //添加多个覆盖物[circle, marker]
} else {
line = new MapInstance.Polyline(path, {
sequence: true,
zIndex,
showDir: true, //沿路径显示白色箭头
strokeColor: strokeColor, //连线颜色
strokeWeight: 6, // 线条粗细
strokeStyle: "solid",
strokeOpacity: 1, //去除路线透明度
});
newMap.addOverlay(line);
}
//缩放地图视野
if (serviceProvider === 'AMap') {
newMap.setFitView()
} else {
newMap.setViewport(path);
}
// #endif
// #ifdef MP
const polyline = {
points: path,
width: 6, // 线条粗细
zIndex,
color: strokeColor,
arrowLine: true, //沿路径显示白色箭头
}
this.polylines = this.polylines.concat(polyline)
this.includePoints = this.includePoints.concat(path)
// #endif
},
//添加站点标记
addStopsMarkers(stops, newMap, MapInstance) {
stops.forEach((stop, index) => {
let stopIcon = require('../../static/img/lbs/load-stop.png');
if (this.shipmentStopShowNumber) {
if (stop.unloadStop === true) {
stopIcon = require('../../static/img/lbs/unload-stop.png')
if (stop.loadStop === true) {
stopIcon = require('../../static/img/lbs/load-unload-stop.png')
}
}
} else {
stopIcon = require('../../static/img/lbs/home.png')
}
let marker = null
// #ifndef MP
if (getApp().globalData.serviceProvider === "AMap") {
const newMapIcon = new MapInstance.Icon({
image: stopIcon,// 图标的取图地址
imageSize: new MapInstance.Size(40, 40), // 图标所用图片大小
});
const mapOptions = {
position: [stop.lng, stop.lat],
anchor: 'bottom-center', //icon标记的位置
icon: newMapIcon,
map: newMap,
}
if (this.shipmentStopShowNumber) {
mapOptions.label = {
content: stop.stopNumber,
direction: 'center',
offset: new MapInstance.Pixel(-0.5, 8),
}
} else {
mapOptions.anchor = 'center'
}
marker = new MapInstance.Marker(mapOptions)
newMap.add([marker]);
} else {
const iconSize = new MapInstance.Size(40, 40)
const myIcon = new MapInstance.Icon(stopIcon, iconSize);
const point = new MapInstance.Point(stop.lng, stop.lat);
marker = new MapInstance.Marker(point, { icon: myIcon });
newMap.addOverlay(marker);
}
// #endif
// #ifdef MP
marker = {
id: Number(index), //Mark id应为数字类型
latitude: stop.lat, //纬度
longitude: stop.lng, //经度
iconPath: stopIcon, //显示的图标
stopNumber: stop.stopNumber,
width: 40,
height: 40,
customCallout: { //自定义标记点上方的气泡窗口
anchorY: 50,
anchorX: -0.4,
display: "ALWAYS"
},
}
this.markers = this.markers.concat(marker)
// #endif
})
},
//获取连线颜色
getPolyLineColor(trackStatus) {
let mapIndex = this.mapStyle
let mapStyle = this.mapStyleList[mapIndex]
let lineColor = this.mapTheme[mapStyle.type]
return lineColor[trackStatus]
},
//移动端事件监听
onTouchstart() {
this.isMove = true
},
onTouchend() {
this.isMove = false
},
onTouchmove(e) {
if (this.isMove) {
const { windowHeight } = uni.getSystemInfoSync()
let clientY
if (uni.getSystemInfoSync().platform === 'windows') {
clientY = e.clientY
} else {
clientY = e.touches[0].clientY
}
const height = windowHeight - clientY
if (height <= windowHeight * 0.88 && height >= windowHeight * 0.1) { //判断屏幕间距
this.popupHeight = `${height * 2}rpx` //转换为rpx单位
}
}
}
}
}
</script>
<style lang="scss">
.order-tracks {
//Marker样式
.shipment-stop-marker, /deep/.amap-marker-label{
height: 80rpx;
width: 80rpx;
background-repeat: no-repeat;
background-size: cover;
font-size: 38rpx ;
color: white;
font-weight: bold;
text-align: center;
}
.stops-steps-popup {
position: relative;
/deep/.u-popup__content {
padding: 0 32rpx 20rpx !important;
background: #FFFFFF;
}
.poup-content {
overflow-y: auto;
}
.drag-btn {
width: 100%;
height: 80rpx;
position: absolute;
left: 0;
z-index: 9999999;
&::after {
content: '';
width: 92rpx;
height: 8rpx;
background: #000000;
border-radius: 5rpx;
opacity: 0.6;
position: absolute;
left: 50%;
top: -15%;
transform: translateX(-50%);
}
}
.current-location {
width: 88rpx;
height: 88rpx;
background: #FFFFFF;
box-shadow: 1rpx 3rpx 8rpx 0 rgba(0, 0, 0, 0.08);
border-radius: 24rpx;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: 30rpx;
top: -130rpx;
.t-icon-location {
width: 45rpx;
height: 45rpx;
}
}
.module-title {
color: #262626;
font-size: 28rpx;
margin: 20rpx 10rpx;
}
.stops-steps {
border-radius: 32rpx 32rpx 0 0;
/deep/.u-steps-item__wrapper{
width: 50rpx !important;
}
/deep/.u-steps-item__content{
margin-top: 6rpx !important;
}
/deep/.u-text{
display: none !important;
}
.stepIconNum{
font-size: 28rpx;
color: #FFFFFF;
position: absolute;
left: 50%;
top: 40%;
transform: translate(-50%, -50%);
}
.step-desc {
font-size: 32rpx;
margin-left: 10rpx;
.desc-title,
.desc-value {
font-size: 28rpx;
color: #8C8C8C;
white-space: nowrap;
}
.desc-title {
margin-right: 24rpx;
}
}
}
}
}
</style>
\ No newline at end of file
<template>
<view class="signFor content_box">
<view class="shipmentBriefInfo">
<bs-pageHeader-orderNo :shipmentNo="shipmentInfo.header.shipmentNo" />
<view class="primary-info routine_radius_card flex_center">
<view style="width: 100%;">
<bs-customCell label="货量 :" labelCol="2" wrapCol="10"
:value="shipmentInfo.header.shipOrders + '单/' +shipmentInfo.header.shipQty+ '件/' + shipmentInfo.header.shipWeight+'千克/'+ shipmentInfo.header.shipVolume+'方'" />
</view>
</view>
</view>
<!-- 订单信息 -->
<view class="orders-total">
<view class="orderQty font_bolder">订单总数:{{orderList.length}}</view>
<scroll-view class="order-detail-list" scroll-y>
<u-empty mode="data" textSize='32' iconSize="160" text="暂无订单" v-if="!orderList.length" />
<u-checkbox-group placement="column" v-model="orderCheckeds">
<view class="order-detail-item" v-for="(item,index) in orderList" :key="index">
<view class="orderNo flex_sb">
<text>订单号 : {{item.orderNo}}</text>
<u-checkbox size='43' :disabled="item.disabled" iconSize='43' :name="item.id"/>
</view>
<u-line color="#F0F0F0" margin="20rpx 0" />
<view class="cargoQty">
<text>货量 :</text>
<text style="margin-left: 30rpx;">{{item.qty}}件 /</text>
<text style="margin-left: 20rpx;">{{item.weight}}千克 /</text>
<text style="margin-left: 20rpx;">{{item.volume}}</text>
</view>
<template v-if="orderCheckeds.some(itm => itm === item.id)">
<!-- 异常选择 -->
<view class="abnormal-select flex_sb flex_center">
<text>是否异常</text>
<switch :checked="item.abnormal" size="43" color="#EB2F48" style="transform:scale(0.8);width: 92rpx;" @change="onChange(item.id)"/>
</view>
<!-- 备注信息 -->
<view class="remark-content">
<u-textarea border="none" placeholder="请输入备注" v-model="item.content" holdKeyboard />
<!-- 图片上传 -->
<block>
<view class="uploader-imgList flex flex_wrap">
<view style="position: absolute;left: -14rpx;color: red;">
*
</view>
<view class="previewImages" v-for="(itm,idx) in item.images" :key="idx">
<image mode="aspectFill" :src="itm" @click="onPreviewImage(idx, item.images)"
class="previewImg" />
<u-icon name="close-circle-fill" class="clearIcon" size="30"
@click="deleteImage(idx, item)" />
</view>
<!-- <view v-if="!item.images.length" style=" width: 200rpx" /> -->
<template v-if="isIos">
<view class="uploadeBtn flex_col" @click="onUpLoad(item.id)">
<view class="t-icon t-icon-picture" />
<text style="margin-top:6rpx">上传照片</text>
<text class="font_bolder orderTotal">{{item.images.length}}/6)</text>
</view>
</template>
<template v-else>
<u-upload :fileList="item.images" :max-count="6" multiple :previewImage="false"
:sizeType="['compressed']" @afterRead="uploadAfterRead" :name="item.id">
<!-- 自定义上传按钮 -->
<view class="uploadeBtn flex_col">
<view class="t-icon t-icon-picture" />
<text style="margin-top:6rpx">上传照片</text>
<text class="font_bolder orderTotal">{{item.images.length}}/6)</text>
</view>
</u-upload>
</template>
</view>
</block>
</view>
</template>
</view>
</u-checkbox-group>
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="operation-btn flex_sb">
<button class="backBtn common_btn" @click="onNavBack">取消</button>
<button class="submitBtn common_btn" @click="onSubmit">确定</button>
</view>
</view>
</template>
<script>
import { signFor, uploadImg, ordermovementOM, ordermovementOR, ordermovementMASS} from '../../api/apiList'
const getUserLocation = require('../../mixins/getUserLocation')
const appInstance = getApp()
export default {
mixins: [getUserLocation],
data() {
return {
orderList: [], //订单列表
orderCheckeds: [], //已选中签收列表
isIos: false,
shipmentInfo: {},
shipmentMode: '', // 运输模式 OM、OR、MS: 大宗运输Mass
}
},
onLoad: function(options) {
let data = JSON.parse(options.data)
const { shipmentData } = data
this.shipmentInfo = shipmentData
const title = '纸质签收'
const { shipmentId, shipmentBizName } = appInstance.globalData.shipmentInfo
let shipmentMode = ''
switch (shipmentBizName) { //根据shipmentBizName 判断运输模式
case 'tm.MovementShipment':
case 'tm.SectionShipment': //暂时走OM逻辑
shipmentMode = 'OM'
break
case 'tm.MassShipment':
shipmentMode = 'MS'; //大宗运输
break
default:
shipmentMode = 'OR';
}
this.shipmentMode = shipmentMode
this.initData(shipmentId)
this.setNavTitle(title)
// #ifdef H5
const platform = uni.getSystemInfoSync().platform
if (platform === 'ios') {
// this.isIos = true
}
// #endif
this.getUserSetting()
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({
title: title,
})
},
//返回上一级页面
onNavBack() {
uni.navigateBack()
},
//初始化数据
initData(shipmentId) {
let newDatas = []
if (this.shipmentMode === 'MS') {
const reqData = { "aux": { "id": shipmentId } }
ordermovementMASS(reqData).then(res => {
const data = res.data.data.header
newDatas.push({
'id': data['massOrder.id'], //订单id
'orderNo': data['massOrder.orderNo'], //订单号
'qty': data['massOrder.qty'], //订单件数
'weight': data['massOrder.weight'], //订单重量
'volume': data['massOrder.volume'], //订单体积
'abnormal': false, //订单是否异常
'images': [], //订单图片
'content': '', //订单备注信息
'disabled': item.transportStatus === '80.POD' //已签收时禁用
})
this.orderList = [...newDatas]
})
} else {
const reqData = {
"args": {
"pageNum": 1,
"pageSize": 100,
"restrictions": [{
"field": "shipment.id",
"type": "EQ",
"value": shipmentId
}]
}
}
const isOM = this.shipmentMode === 'OM'
const requestFun = isOM ? ordermovementOM : ordermovementOR
requestFun(reqData).then(res => {
const datas = res.data.data.datas
datas.map(item => {
newDatas.push({
'id': item.id, //订单id
'orderNo': isOM ? item.movementNo : item.orderNo, //订单号
'qty': isOM ? item.shipQty : item.qty, //订单件数
'weight': isOM ? item.shipWeight : item.weight, //订单重量
'volume': isOM ? item.shipVolume : item.volume, //订单体积
'abnormal': false, //订单是否异常
'images': [], //订单图片
'content': '', //订单备注信息
'disabled': item.transportStatus === '80.POD' //已签收时禁用
})
})
this.orderList = [...newDatas]
})
}
},
// 确认
onSubmit() {
const _this = this
let {orderList, orderCheckeds} = _this
if (!orderCheckeds.length) { //校验是否存在可签收订单
this.customTost()
return
}
//校验签收订单图片是否上传
let flags = []
orderCheckeds.map(checkOrderId => {
let order = orderList.find(orderItem => orderItem.id === checkOrderId)
if (!order.images.length) {
flags.push(order.orderNo)
}
})
if(flags.length){
uni.showToast({
title: `订单${flags.join('|')}图片信息不能为空`,
icon: 'none',
duration: 3000
})
return
}
//调用接口签收订单
orderCheckeds.map(checkOrderId => {
let order = orderList.find(orderItem => orderItem.id === checkOrderId)
_this.uploadImages(order.images, imgs => {
_this.onSignFor(order, imgs) //签收选中订单
})
})
},
//订单签收
onSignFor(orderData, images) {
const { longitude, latitude, address, time } = this.locationInfo
const reqData = {
'aux': {
images: images,
content: orderData.content, //备注
abnormal: orderData.abnormal, //是否异常
eventSource: 'DriverApp',
longitude,
latitude,
address,
time
},
"args": {
"selectedIds": [orderData.id]
}
}
const signMode = { 'OM': 'OrderMovement', 'OR': 'SimpleOrder' }
signFor(signMode[this.shipmentMode], reqData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '操作成功',
duration: 3000
})
setTimeout(() => {
this.onNavBack()
}, 1500)
}
})
},
onChange(orderId){
const newList = this.orderList.map(item => {
if(item.id === orderId){
item.abnormal = !item.abnormal
}
return item
})
this.orderList = [...newList]
},
//图片上传 IOS兼容
onUpLoad(orderId) {
if (this.$jwx) {
const _this = this
const sourceType = this.isIos ? ['album'] : ['album', 'camera'] // 可以指定来源是相册还是相机, ios指定为仅相册
this.$jwx.chooseImage({
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: sourceType,
success: function(res) {
_this.onConvert(res.localIds)
_this.orderItemId = orderId
}
})
}
},
async onConvert(localIds) {
for (var i = 0; i < localIds.length; i++) {
await this.onReadImage(localIds[i]);
}
},
onReadImage(localId) {
const _this = this
return new Promise((resolve, reject) => {
_this.$jwx.getLocalImgData({
localId: localId, // 图片的localID
success: function(res) {
const localData = res.localData
let orderList = _this.orderList
orderList.forEach(order => {
if (order.id === _this.orderItemId) {
order.images = [...order.images, localData]
}
return
})
_this.orderList = [...orderList]
resolve('done!')
}
});
})
},
//上传图片
uploadImages(fileList, callback) {
let images = []
fileList.forEach(item => {
uploadImg(item).then(res => {
uni.hideLoading()
let data = JSON.parse(res).data
images.push(data.path)
if (images.length === fileList.length) {
return callback(images.join('|'))
}
}).catch(err => {
console.log(err);
})
})
},
// 自定义轻提示
customTost() {
uni.showToast({
title: '暂无可签收订单',
icon: 'none',
duration: 3000
})
},
// 上传图片回调
uploadAfterRead(info) {
const { file, name } = info
const newFile = file.map(item => item.url);
let orderList = this.orderList
orderList.forEach(order => {
if (order.id === name) {
order.images = [...order.images, ...newFile]
}
return
})
this.orderList = [...orderList]
},
// 预览图片回调
onPreviewImage(index, images) {
uni.previewImage({
current: index,
urls: images
})
},
// 删除已选图片
deleteImage(index, info) {
let orderList = this.orderList
uni.showModal({
title: '删除提示',
content: '确定删除本张图片吗?',
success: (res) => {
if (res.confirm) {
orderList.forEach(order => {
if (order.id === info.id) {
let images = [...order.images]
images.splice(index, 1)
order.images = [...images]
}
return
})
this.orderList = [...orderList]
} else if (res.cancel) {}
}
})
},
}
}
</script>
<style lang="scss">
.orders-total {
font-size: 28rpx;
background: #FAFAFA;
.orderQty {
padding: 26rpx 30rpx;
}
.order-detail-list {
height: 800rpx;
.order-detail-item {
width: 100vw;
margin-bottom: 35rpx;
padding: 30rpx;
background-color: #FFFFFF;
/deep/.orderNo {
color: #8C8C8C;
margin-bottom: 30rpx;
.u-checkbox__icon-wrap{
margin-right: 0;
}
}
.abnormal-select{
margin-top: 30rpx;
}
.remark-content {
margin-top: 30rpx;
padding: 16rpx;
background: #FAFAFA;
border-radius: 8px;
/deep/.u-textarea {
background: #FAFAFA;
}
.uploader-imgList {
padding-top: 20rpx;
position: relative;
.previewImages {
position: relative;
overflow: hidden;
.previewImg {
width: 180rpx;
height: 140rpx;
margin: 0 10rpx 20rpx;
}
/deep/.uicon-close-circle-fill {
width: 26rpx;
height: 26rpx;
border-radius: 50%;
background-color: #fff;
color: #D81E06 !important;
position: absolute;
top: 5rpx !important;
right: 15rpx;
}
}
.uploadeBtn {
position: relative;
color: #929292;
width: 180rpx;
height: 140rpx;
border: 2rpx dashed #D9D9D9;
margin: 0 0 20rpx 6rpx;
background-color: #fff;
justify-content: center;
align-items: center;
font-size: 24rpx;
.orderTotal {
color: #333333;
position: absolute;
right: -90rpx;
bottom: 0;
z-index: 999;
}
.t-icon-picture {
width: 50rpx;
height: 50rpx;
}
}
}
}
}
}
}
.primary-info {
flex-wrap: wrap;
.left-icon {
position: relative;
margin-right: 20rpx;
.leftIcon-text {
font-size: 28rpx;
display: inline-block;
position: absolute;
top: 5px;
left: 12px;
}
.t-icon {
width: 70rpx;
height: 70rpx;
}
}
/deep/.custom-cell-row {
width: 100%;
margin-top: 32rpx;
color: #8C8C8C;
}
}
</style>
<template>
<view class="content_box">
<view class="search-input flex_center">
<u-search searchIconSize="50" searchIconColor="#FFFFFF" placeholderColor='#FFFFFF' color="#FFFFFF"
:showAction="false" :placeholder="placeholder" v-model="searchValue" @clickIcon="onSearch" @search="onSearch" @clear="onSearch" />
</view>
<view class="options">
<u-radio-group v-model="currentAddressId" placement="column" iconPlacement="right">
<u-radio :customStyle="{padding: '22rpx 40rpx'}" :size="40" :iconSize="32" :labelSize="32"
:labelColor="currentAddressId === item.id ? '#2E75E6' : '#262626'"
v-for="(item, index) in datas" :key="index" :label="item.name" :name="item.id"
@change="onSelect(item.id)">
</u-radio>
</u-radio-group>
</view>
<!-- 底部按钮 -->
<view class="operation-btn flex_sb">
<button class="backBtn common_btn" @click="onNavBack">返回</button>
<button class="submitBtn common_btn" @click="onConfirm">确认</button>
</view>
</view>
</template>
<script>
import { searchTransferAddress } from '../../api/apiList'
export default {
data() {
return {
datas: [], //候选项列表
placeholder: "请输入搜索地址", //默认提示
searchValue: "", //搜索值
currentAddressId: '', // 当前地址ID
pageNum: 1, //页码
pageSize: 20, //每页条数
loadMore: true, //加载更多
}
},
onLoad(options) {
const { title, id } = JSON.parse(options.data)
this.setNavTitle(title)
this.currentAddressId = id
this.initData()
},
onReachBottom() {
if (this.loadMore) {
this.initData();
this.loadMore = false
}
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({ title })
},
//初始化数据
initData() {
const { pageNum, pageSize } = this
const reqData = {
args: { pageNum, pageSize }
}
if(this.searchValue){
reqData.args.restrictions = [{
"field": 'name',
"type": "LK", //EQ精准匹配,LK模糊匹配
"value": this.searchValue
}]
}
searchTransferAddress(reqData).then(res => {
const datas = res.data.data.datas
if (datas.length) {
const newData = this.datas.concat(datas)
this.datas = [...newData]
this.pageNum += 1
this.loadMore = true
}
})
},
onSelect(id) {
this.currentAddressId = id
},
//确认选择
onConfirm() {
const app = getApp()
const { currentAddressId, datas } = this
if (!currentAddressId) {
uni.showToast({
title: `请选择地址`,
icon: 'none',
duration: 1500
})
return
}
const info = datas.find(item => item.id === currentAddressId)
app.globalData.transferAddress = info
this.onNavBack()
},
// 搜索功能
onSearch() {
this.pageNum = 1
this.datas = []
this.initData()
},
//返回上一级页面
onNavBack() {
uni.navigateBack()
},
}
}
</script>
<style lang="scss">
.content_box {
.search-input {
width: 100%;
position: fixed;
top: 0;
z-index: 999;
height: 128rpx;
background: linear-gradient(90deg, #2E75E6 0%, #5E58EE 100%);
/deep/.u-search__content {
height: 80rpx;
margin: 24rpx;
background-color: rgba(240, 240, 240, .5) !important;
.u-search__content__input {
letter-spacing: 4rpx;
background-color: transparent !important;
}
.uicon-close{
font-size: 28rpx !important;
}
}
}
.u-radio {
background-color: #fff;
.u-radio__text{
line-height: 44rpx !important;
margin-right: 24rpx;
}
}
.options {
margin: 130rpx 0 15vh;
}
.operation-btn {
position: fixed;
bottom: 0;
}
}
</style>
<template>
<view class="transferChange content_box ">
<u-toast ref="uToast" />
<bs-pageHeader-orderNo :shipmentNo="shipmentNo" />
<!-- 中转明细-->
<view class="transfer-datail">
<u--form :model="formData" :rules="rules" ref="myForm" errorType='none'>
<u-form-item prop="stop" required label="中转地址" labelWidth="30%" :borderBottom="isTransfer">
<view @click="onNavTransferDetail">
<u-input border="none" readonly inputAlign="left" placeholder="选择中转地址"
placeholderClass="input-tip" :value="transferAddress.name" />
</view>
<u-icon slot="right" name="arrow-right" @click="onNavTransferDetail" />
</u-form-item>
<!-- 中转换车显示司机信息 -->
<template v-if="isTransfer">
<u-form-item prop="truckName" required label="车牌号" labelWidth="30%" borderBottom>
<u-input border="none" required inputAlign="left" placeholder="输入车牌号"
placeholderClass="input-tip" v-model="formData.truckName" holdKeyboard />
</u-form-item>
<u-form-item prop="driver1Name" required label="司机姓名" labelWidth="30%" borderBottom>
<u-input border="none" required inputAlign="left" placeholder="输入姓名"
placeholderClass="input-tip" v-model="formData.driver1Name" holdKeyboard />
</u-form-item>
<u-form-item prop="driver1Tel" required label="司机电话" labelWidth="30%">
<u-input border="none" required type="number" inputAlign="left" placeholder="输入手机号"
placeholderClass="input-tip" v-model="formData.driver1Tel" holdKeyboard />
</u-form-item>
</template>
</u--form>
</view>
<!-- 底部按钮 -->
<view class="operation-btn flex_sb">
<button class="backBtn common_btn" @click="onNavBack">返回</button>
<button class="submitBtn common_btn" @click="onSubmitForm">确认</button>
</view>
</view>
</template>
<script>
import { reportInfo, searchTransferAddress } from '../../api/apiList'
import { formatGMT } from '../../utils/util'
const getUserLocation = require('../../mixins/getUserLocation')
const app = getApp()
export default {
mixins: [getUserLocation],
data() {
return {
formData: {
stop: "", //中转地址id
driver1Name: "", //司机姓名
driver1Tel: "", //司机手机号
truckName: "", //车牌号
},
rules: {
'stop': { required: true },
'driver1Name': { required: true },
'driver1Tel': { required: true },
'truckName': { required: true }
},
isTransfer: false, //是否为中转换车
action: '', //当前操作类型
selectedIds: [], //当前运单id
shipmentNo: '', //运单号
transferAddress: {}, //中转地址
}
},
onLoad: function(options) {
const data = JSON.parse(options.data)
const isTransfer = data.action === 'transferAndChangeTruck' //判断是否为中转换车
this.selectedIds = [data.selectedId]
this.action = data.action
this.isTransfer = isTransfer
this.shipmentNo = app.globalData.shipmentInfo.shipmentNo
const title = isTransfer ? '中转换车' : '中转卸货'
this.setNavTitle(title)
this.getUserSetting()
},
onShow() { //自定义分配信息
const { transferAddress } = app.globalData
this.formData.stop = transferAddress.id
this.transferAddress = transferAddress
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({
title: title,
})
},
// 提交表单数据
onSubmitForm() {
this.$refs.myForm.validate().then(res => {
const { stop, driver1Name, driver1Tel, truckName } = this.formData
const { longitude, latitude, address, time } = this.locationInfo
const { isTransfer, action } = this
let baseData = {
"aux": {
stop,
longitude,
latitude,
address,
time,
eventSource: 'CarrierApp'
},
'args': {
"selectedIds": this.selectedIds
}
}
if (isTransfer) {
baseData.aux = {
...baseData.aux,
driver1Name,
driver1Tel,
truckName,
}
}
reportInfo(action, baseData).then(res => {
if (res.data.messageType === 'success') {
uni.showToast({
title: '操作成功',
duration: 3000
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
}).catch(errors => {
this.$refs.uToast.show({
message: '请完善必填信息',
})
})
},
//返回上一级页面
onNavBack() {
uni.navigateBack()
},
//跳转地址详情
onNavTransferDetail() {
const title = this.isTransfer ? '中转换车' : '中转卸货'
const data = { title, id: this.formData.stop }
uni.navigateTo({
url: `/subpkg/transferAddressDetail/transferAddressDetail?data=${JSON.stringify(data)}`,
})
}
}
}
</script>
<style lang="scss">
.transferChange {
.location {
.t-icon-current-location {
min-width: 50rpx;
min-height: 50rpx;
}
.t-icon-location {
min-width: 45rpx;
min-height: 45rpx;
}
.address {
margin: 0 20rpx
}
}
/deep/.transfer-datail {
padding: 0 40rpx;
background-color: #ffffff;
margin: 25rpx 0;
.input-tip {
font-size: 28rpx;
color: #BFBFBF;
}
.u-form-item__body__left__content__label {
color: #8C8C8C;
font-size: 28rpx;
}
.u-form-item__body {
padding: 30rpx 0;
}
.u-icon {
margin-left: 20rpx;
}
}
.operation-btn {
min-height: 500rpx;
}
/deep/.u-form-item__body__left__content__required{
left: -16rpx !important;
line-height: 150% !important;
font-size: 28rpx !important;
top: 0 !important;
}
}
</style>
<template>
<view class="view-driver-truck content_box">
<view class="content-list" style="margin-bottom: 120rpx;">
<u-empty mode="data" textSize='32' iconSize="160" text="暂无数据" v-if="!datas.length" />
<bs-customCell v-for="item in datas" :key="item.id" :label="item.name" labelCol='4' wrapCol="7.2"
:value="isDriver ? item.tel : item['facilityMode.name']" @click.native="onNavDetail(item.id)" >
<view slot="right-icon">
<span class='t-icon t-icon-bianji'></span>
</view>
</bs-customCell>
</view>
<view class="operation-btn add_driver_btn">
<button class="submitBtn common_btn" @click="onNavPage">新增{{isDriver ? '司机' : '车辆'}}</button>
</view>
</view>
</template>
<script>
import { searchDriverList, searchTruckList } from '../../api/apiList'
export default {
options: { styleIsolation: 'shared' },
data() {
return {
datas: [], //候选项列表
isDriver: true, //是否查看司机
pageNum: 1, //页码
pageSize: 20, //每页条数
loadMore: true, //加载更多
}
},
onLoad: function(options) {
const isDriver = options.action === 'driver'
const title = isDriver ? '我的司机' : '我的车辆'
this.setNavTitle(title)
this.isDriver = isDriver
},
onShow() {
this.pageNum = 1
this.datas = []
this.initData(this.isDriver)
},
onReachBottom() {
if (this.loadMore) {
this.initData(this.isDriver);
this.loadMore = false
}
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({
title: title,
})
},
//初始化数据
initData(isDriver) {
const { pageNum, pageSize } = this
const reqData = {
args: { pageNum, pageSize }
}
const requestFun = isDriver ? searchDriverList : searchTruckList
requestFun(reqData).then(res => {
const datas = res.data.data.datas
if (datas.length) {
const newData = this.datas.concat(datas)
this.datas = [...newData]
this.pageNum += 1
this.loadMore = true
}
})
},
//跳转司机、车辆注册
onNavPage() {
let path = this.isDriver ? '/subpkg/registerDriver/registerDriver' : '/subpkg/registerTruck/registerTruck'
uni.navigateTo({ url: path })
},
//跳转查看详情
onNavDetail(id) {
const data = { isDriver: this.isDriver, id }
const path = `/subpkg/viewDriverTruckDetail/viewDriverTruckDetail?data=${JSON.stringify(data)}`
uni.navigateTo({ url: path })
}
}
}
</script>
<style lang="scss">
.view-driver-truck {
/deep/.content-list {
background-color: #fff;
padding: 0 32rpx;
.custom-cell-row {
padding: 40rpx 0;
margin-top: 0;
border-bottom: 2rpx solid #dadada;
&:last-child {
border-bottom: none;
}
}
}
.submitBtn {
width: 90%;
}
.add_driver_btn{
position: fixed;
bottom: 40rpx;
left: 50%;
transform: translateX(-50%);
margin-bottom: 0;
}
}
</style>
<template>
<view class="registerTruck content_box">
<!-- 基本信息 -->
<view class="module-title flex_sb">
<text>基本信息</text>
</view>
<view class="basic-info">
<template v-if="isDriver">
<bs-customCell labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>姓名</span>
</view>
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' slot="value" border="none"
:placeholder="newEdit?'请输入姓名':''" v-model="driverInfo.name" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="性别" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisible('gender')" :style="newEdit?'':'pointer-events: none;'">
<u-input disabledColor="#FFFFFF" border="none" :disabled='!newEdit' readonly
:placeholder="newEdit?'请选择性别':''" :value="genderViewEnums[driverInfo.gender]" />
</view>
<view slot="right-icon" style="transform: translateX(-20rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisible" index="gender" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="年龄" labelCol="4" wrapCol="8">
<u-input disabledColor="#FFFFFF" slot="value" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请输入年龄':''" v-model="driverInfo.age" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>联系方式</span>
</view>
<u-input disabledColor="#FFFFFF" slot="value" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请输入联系方式':''" v-model="driverInfo.tel" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="承运商" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisible('carrier')" :style="newEdit?'':'pointer-events: none;'">
<u-input disabledColor="#FFFFFF" border="none" :disabled='!newEdit' readonly
:placeholder="newEdit?'请选择承运商':''" :value="carrierViewEnums[driverInfo.carrier] || driverInfo.carrierName" />
</view>
<view slot="right-icon" style="transform: translateX(-20rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisible" index="carrier" />
</view>
</bs-customCell>
</template>
<template v-else>
<bs-customCell labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>车牌号</span>
</view>
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' slot="value" border="none"
:placeholder="newEdit?'请输入车牌号':''" v-model="truckInfo.name" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="车型" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisible('facilityModeId')" :style="newEdit?'':'pointer-events: none;'">
<u-input disabledColor="#FFFFFF" border="none" :disabled='!newEdit' readonly
:placeholder="newEdit?'请选择车型':''" :value="truckInfo.facilityModeId" />
</view>
<view slot="right-icon" style="transform: translateX(-20rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisible" index="facilityModeId" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="主驾" labelCol="4" wrapCol="8">
<view slot="value" @click="checkDriver" :style="newEdit?'':'pointer-events: none;'">
<u-input disabledColor="#FFFFFF" border="none" :disabled='!newEdit' readonly
:placeholder="newEdit?'请选择主驾':''" :value="truckInfo.driver1Id" />
</view>
<view slot="right-icon" style="transform: translateX(-20rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="checkDriver" index="driver1Id" />
</view>
</bs-customCell>
<bs-customCell label="承运商" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisible('ownerId')" :style="newEdit?'':'pointer-events: none;'">
<u-input disabledColor="#FFFFFF" border="none" :disabled='!newEdit' readonly
:placeholder="newEdit?'请选择承运商':''" :value="truckInfo.ownerId" />
</view>
<view slot="right-icon" style="transform: translateX(-20rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisible" index="ownerId" />
</view>
</bs-customCell>
</template>
</view>
<template v-if="isDriver">
<!-- 身份证 -->
<view class="module-title flex_sb">
<text>身份证</text>
</view>
<view class="driverLicense">
<bs-customCell labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>身份证号</span>
</view>
<u-input disabledColor="#FFFFFF" slot="value" :disabled='!newEdit' border="none" :placeholder="newEdit?'请输入身份证号':''" v-model="idCard.code" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>生效日期</span>
</view>
<view slot="value" :style="newEdit?'':'pointer-events: none;'" @click="
onVisibleDate('idCard.effectiveDate')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none" readonly
:placeholder="newEdit?'请选择生效日期':''" :value="newFormatGMT(idCard.effectiveDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate"
index="idCard.effectiveDate" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>失效日期</span>
</view>
<view slot="value" :style="newEdit?'':'pointer-events: none;'"
@click="onVisibleDate('idCard.expirationDate')">
<u-input disabledColor="#FFFFFF" border="none" readonly :placeholder="newEdit?'请选择失效日期':''"
:value="newFormatGMT(idCard.expirationDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate"
index="idCard.expirationDate" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell :value="``" labelCol="4" wrapCol="8">
<view slot="label" style="position: relative;">
<span style="color: red; position: absolute;left: -14rpx;">*</span>
<span>证件照片</span>
</view>
</bs-customCell>
<view class="certification">
<template v-if="newEdit">
<bs-uploader btnTitle="身份证正面照片" :maxCount="1" ref="idcardFaceImage" cameraType="idCardFace" @customUploadAfter="onUploadOCR" />
<bs-uploader btnTitle="身份证反面照片" :maxCount="1" ref="idcardBackImage" cameraType="idCardBack" @customUploadAfter="onUploadOCR"/>
</template>
<template v-else>
<view class="previewImgs flex_col">
<image class='previewImg' v-for="item in idCard.faceImage" :key="item.index"
:src="item" alt="身份证正面照" :data-index="item.index" @click="onPreviewImage" />
<image class='previewImg' v-for="item in idCard.backImage" :key="item.index"
:src="item" alt="身份证背面照" :data-index="item.index" @click="onPreviewImage" />
</view>
</template>
</view>
</view>
<!-- 驾驶证 -->
<view class="module-title flex_sb">
<!-- <view class="vertical-separate" /> -->
<text>驾驶证</text>
</view>
<view class="driverLicense">
<bs-customCell label="驾驶证号" labelCol="4" wrapCol="8">
<u-input disabledColor="#FFFFFF" slot="value" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请输入驾驶证号':''" v-model="driverLicense.code" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="准驾车型" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisible('driverLicense.quasiDrivingType')"
:style="newEdit?'':'pointer-events: none;'">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none" readonly
:placeholder="newEdit?'请选择准驾车型':''" v-model="driverLicense.quasiDrivingType" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisible"
index="driverLicense.quasiDrivingType" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="生效日期" labelCol="4" wrapCol="8">
<view slot="value" :style="newEdit?'':'pointer-events: none;'" @click="
onVisibleDate('driverLicense.effectiveDate')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none" readonly
:placeholder="newEdit?'请选择生效日期':''" :value="newFormatGMT(driverLicense.effectiveDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate"
index="driverLicense.effectiveDate" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="失效日期" labelCol="4" wrapCol="8">
<view slot="value" :style="newEdit?'':'pointer-events: none;'"
@click="onVisibleDate('driverLicense.expirationDate')">
<u-input disabledColor="#FFFFFF" border="none" readonly :placeholder="newEdit?'请选择失效日期':''"
:value="newFormatGMT(driverLicense.expirationDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate"
index="driverLicense.expirationDate" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="证件照片" :value="``" labelCol="4" wrapCol="8" />
<view class="certification">
<template v-if="newEdit">
<bs-uploader btnTitle="驾驶证正面照片" :maxCount="1" ref="driverLicenseFaceImage" cameraType="driveCardFace" @customUploadAfter="onUploadOCR"/>
<bs-uploader btnTitle="驾驶证反面照片" :maxCount="1" ref="driverLicenseBackImage" cameraType="driveCardBack" @customUploadAfter="onUploadOCR"/>
</template>
<template v-else>
<view class="previewImgs flex_col">
<image class='previewImg' v-for="item in driverLicense.faceImage" :key="item.index"
:src="item" alt="驾驶证正面照" :data-index="item.index" @click="onPreviewImage" />
<image class='previewImg' v-for="item in driverLicense.backImage" :key="item.index"
:src="item" alt="驾驶证背面照" :data-index="item.index" @click="onPreviewImage" />
</view>
</template>
</view>
</view>
<!-- 从业资格证 -->
<view class="module-title flex_sb">
<!-- <view class="vertical-separate" /> -->
<text>从业资格证</text>
</view>
<view class="driverJobCertificate">
<bs-customCell label="从业资格证号" labelCol="4" wrapCol="8">
<u-input disabledColor="#FFFFFF" slot="value" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请输入从业资格证号':''" v-model="driverJobCertificate.code" />
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="准驾车型" labelCol="4" wrapCol="8">
<view slot="value" :style="newEdit?'':'pointer-events: none;'"
@click="onVisible('driverJobCertificate.quasiDrivingType')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none" readonly
:placeholder="newEdit?'请选择准驾车型':''" v-model="driverJobCertificate.quasiDrivingType" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisible"
index='driverJobCertificate.quasiDrivingType' />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="生效日期" labelCol="4" wrapCol="8">
<view slot="value" :style="newEdit?'':'pointer-events: none;'"
@click="onVisibleDate('driverJobCertificate.effectiveDate')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none" readonly
:placeholder="newEdit?'请选择生效日期':''"
:value="newFormatGMT(driverJobCertificate.effectiveDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate"
index='driverJobCertificate.effectiveDate' />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="失效日期" labelCol="4" wrapCol="8">
<view slot="value" :style="newEdit?'':'pointer-events: none;'"
@click="onVisibleDate('driverJobCertificate.expirationDate')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none" readonly
:placeholder="newEdit?'请选择失效日期':''"
:value="newFormatGMT(driverJobCertificate.expirationDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate"
index="driverJobCertificate.expirationDate" />
</view>
</bs-customCell>
<u-line color="#F0F0F0" margin="0" />
<bs-customCell label="证件照片" :value="``" labelCol="4" wrapCol="8" />
<view class="certification">
<template v-if="newEdit">
<bs-uploader btnTitle="从业资格证件照" :maxCount="1" ref="driverJobCertificateFaceImage" />
</template>
<template v-else>
<view class="previewImgs flex flex_wrap" style="margin-top: 20rpx;">
<image class='previewImg' v-for="item in driverJobCertificate.faceImage" :key="item.index"
:src="item" alt="从业资格证件照" :data-index="item.index" @click="onPreviewImage" />
</view>
</template>
</view>
</view>
</template>
<template v-else>
<!-- 行驶证 -->
<view class="module-title flex_sb">
<!-- <view class="vertical-separate" /> -->
<text>行驶证</text>
</view>
<view class="drivingCertificate">
<bs-customCell label="行驶证号" labelCol="4" wrapCol="8">
<u-input disabledColor="#FFFFFF" slot="value" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请输入行驶证号':''" v-model="truckInfo.code" />
</bs-customCell>
<bs-customCell label="生效日期" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisibleDate('effectiveDate')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请选择生效日期':''" :value="newFormatGMT(truckInfo.effectiveDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate" index='effectiveDate' />
</view>
</bs-customCell>
<bs-customCell label="失效日期" labelCol="4" wrapCol="8">
<view slot="value" @click="onVisibleDate('expirationDate')">
<u-input disabledColor="#FFFFFF" :disabled='!newEdit' border="none"
:placeholder="newEdit?'请选择失效日期':''" :value="newFormatGMT(truckInfo.expirationDate)" />
</view>
<view slot="right-icon" style="transform: translateX(-40rpx);">
<u-icon v-if="newEdit" name="arrow-right" @click="onVisibleDate" index="expirationDate" />
</view>
</bs-customCell>
<bs-customCell label="证件照片" :value="``" labelCol="4" wrapCol="8" />
<view class="certification">
<template v-if="newEdit">
<bs-uploader :maxCount="1" btnTitle="上传行驶证件" ref="faceImage" cameraType="vehicleCardFace" @customUploadAfter="onUploadOCR" />
</template>
<template v-else>
<view class="previewImgs flex flex_wrap" style="margin-top: 20rpx;">
<image class='previewImg' v-for="(item, index) in truckInfo.faceImage" :key="index"
:src="item" alt="行驶证件" :data-index="index" @click="onPreviewImage" />
</view>
</template>
</view>
</view>
</template>
<bs-selectPicker ref="mySelectPicker" :pickerEnums="optionEnums" :visible="visible" @onVisible="onVisible"
@onConfirm="onConfirmPicker" />
<!-- 时间选择 -->
<bs-datetimePicker ref="myTimePicker" :visible="showPopup" @onVisible="onVisibleDate"
@onSelsectDate="onSelsectDate" />
<view class="select_footer">
<button @click="cancel">取消</button>
<button @click="save">保存</button>
</view>
</view>
</template>
<script>
import {
downloadImg, uploadImg, OCRService,
searchDriverTruckDetail,
queryDrivingType,
queryTruckType,
searchDriverList,
UpdateDriverInfo,
UpdateTruckInfo,
GetCarrierList
} from '../../api/apiList'
import {
formatGMT
} from '../../utils/util'
export default {
data() {
return {
id: '',
isDriver: '', //是否为查看司机
viewData: {}, //查看数据
visibleKey: '', //当前显示字段的key
optionEnums: [], //候选项枚举
genderViewEnums: [{ label: '男', value: 'MALE' }, { label: '女', value: 'FEMALE' }],//性别枚举
viewEnums: [], //视图枚举
facilityViewEnums: [], //车型视图枚举
driverViewEnums: [], //主驾视图枚举
visible: false, //类型选择
showPopup: false, //时间选择
newEdit: true,
driverInfo: {
name: "", //姓名
gender: "", //性别
age: "", //年龄
tel: "", //电话
carrier:'',
carrierName: ''
},
idCard:{
code:"",
effectiveDate: '', //生效日期
expirationDate: '', //失效日期
faceImage: '', //正面照片
backImage: '', //背面照片
},
driverLicense: { // 驾驶证信息
code: '', //证件号码
quasiDrivingType: '', //准驾车型
effectiveDate: '', //生效日期
expirationDate: '', //失效日期
faceImage: '', //正面照片
backImage: '', //背面照片
},
driverJobCertificate: { // 从业资格证信息
code: '', //证件号码
quasiDrivingType: '', //准驾车型
effectiveDate: '', //生效日期
expirationDate: '', //失效日期
faceImage: '', //证件照片
},
updateData: null,
truckInfo: {
name: "", //车牌
facilityModeId: "", //车型id
driver1Id: "", //司机id
code: "", //证件号码
effectiveDate: "", //生效日期
expirationDate: "", //失效日期
faceImage: "", //证件照片
ownerId: ''
},
oldImage: {
idcardFaceImage:"",
idcardBackImage:"",
driverLicenseFaceImage: '',
driverLicenseBackImage: '',
driverJobCertificateFaceImage: '',
faceImage: ''
},
carrierList: [],
carrierViewEnums: [],
ownerIdViewEnums: [],
}
},
onLoad(options) {
const {
isDriver,
id
} = JSON.parse(options.data)
console.log(options)
const title = isDriver ? '司机信息' : '车辆信息'
this.isDriver = isDriver
this.id = id
this.setNavTitle(title)
this.initData(id)
this.getCarrierList()
},
methods: {
//设置页面头部标题
setNavTitle(title) {
uni.setNavigationBarTitle({
title
})
},
newFormatGMT(date) {
return formatGMT(date || '', 'D')
},
initData(id) {
const data = {
"aux": {
id
}
}
const action = this.isDriver ? 'Driver' : 'Truck'
searchDriverTruckDetail(action, data).then(async res => {
const data = res.data.data.header
let uploaders = []
if (this.isDriver) {
Object.keys(this.driverInfo).map(key => {
this.driverInfo[key] = data[key]
})
this.driverInfo.carrier = data['owner.carrier.id']
this.driverInfo.carrierName = data['owner.name']
//身份证
Object.keys(this.idCard).map(key => {
this.idCard[key] = data[`idcard.${key}`]
})
try { //不包裹则异常时,代码中断执行
this.idCard.faceImage = await this.downloadImgs(data['idcard.faceImage'])
} catch (e) {}
try {
this.idCard.backImage = await this.downloadImgs(data['idcard.backImage'])
} catch (e) {}
Object.keys(this.driverLicense).map(key => {
this.driverLicense[key] = data[`driverLicense.${key}`]
})
try { //不包裹则异常时,代码中断执行
this.driverLicense.faceImage = await this.downloadImgs(data['driverLicense.faceImage'])
} catch (e) {}
try {
this.driverLicense.backImage = await this.downloadImgs(data['driverLicense.backImage'])
} catch (e) {}
Object.keys(this.driverJobCertificate).map(key => {
this.driverJobCertificate[key] = data[`driverJobCertificate.${key}`]
})
try {
this.driverJobCertificate.faceImage = await this.downloadImgs(data['driverJobCertificate.faceImage'])
} catch (e) {}
uploaders = [
{
ref: "idcardFaceImage",
url: this.idCard.faceImage
},
{
ref:"idcardBackImage",
url: this.idCard.backImage
},
{
ref:"driverLicenseFaceImage",
url: this.driverLicense.faceImage
},
{
ref:"driverLicenseBackImage",
url: this.driverLicense.backImage
},
{
ref:"driverJobCertificateFaceImage",
url: this.driverJobCertificate.faceImage
}
]
} else {
this.truckInfo.name = data.name
this.truckInfo.facilityModeId = data['facilityMode.name']
this.truckInfo.driver1Id = data['driver1.name']
this.truckInfo.code = data['drivingCertificate.code']
this.truckInfo.effectiveDate = data['drivingCertificate.effectiveDate']
this.truckInfo.expirationDate = data['drivingCertificate.expirationDate']
this.truckInfo.ownerId = data['owner.name']
this.truckInfo.faceImage = await this.downloadImgs(data['drivingCertificate.faceImage'])
uploaders = [
{
ref: "faceImage",
url: this.truckInfo.faceImage
},
]
}
this.setUploaderImageValue(uploaders)
})
},
//照片回显
setUploaderImageValue(uploaders){
uploaders.forEach(item => {
if(Array.isArray(item.url) && item.url.length){
let imgUrl = (item.url)[0]
this.$refs[item.ref].fileDetailList.push({
url: imgUrl,
type: "image"
})
this.$refs[item.ref].fileList.push(imgUrl)
}
})
},
//图片下载
downloadImgs(paths) {
return new Promise((reslove, reject) => {
let imgs = []
let i = 0
if (paths) {
const imgPaths = paths.split('|')
imgPaths.map((path, index) => {
downloadImg(path).then(res => {
i++
imgs.push(res)
if (i === imgPaths.length) {
reslove(imgs)
}
})
})
} else {
reject()
}
})
},
//图片预览
onPreviewImage(e) {
let {
index,
source
} = e.currentTarget.dataset;
uni.isPreviewImage({
current: index,
urls: source
})
},
//类型选择
async onVisible(type) {
if (this.isDriver) {
if (this.visible) {
this.visible = false
} else {
let optionEnums = []
let setKey = 'viewEnums' //要设置的字段Key
let isRequest = type === 'driverLicense.quasiDrivingType' || type ===
'driverJobCertificate.quasiDrivingType'
if (type === 'carrier') {
setKey = 'carrierViewEnums'
optionEnums =this.carrierList
} else if (isRequest) {
const res = await queryDrivingType()
optionEnums = res.data.data.datas
}
this.setViewEnums(optionEnums, setKey)
this.optionEnums = optionEnums
this.visibleKey = type
this.visible = true
}
} else {
if (this.visible) {
this.visible = false
} else {
let optionEnums = []
let setKey = '' //要设置的字段Key
let resData = '' //响应数据
const reqData = {
args: {
pageNum: 1,
pageSize: 1000
}
}
if (type === 'facilityModeId') {
setKey = 'facilityViewEnums'
resData = await queryTruckType(reqData)
this.popTitle = '请选择车型'
} else if(type === 'ownerId') {
setKey = 'ownerIdViewEnums'
resData = await GetCarrierList(reqData)
this.popTitle = '请选择承运商'
}else if (type === 'driver1Id') {
setKey = 'driverViewEnums'
resData = await searchDriverList(reqData)
this.popTitle = '请选择主驾'
}
resData.data.data.datas.map(item => {
optionEnums.push({
'label': item.name,
'value': item.name
})
})
this.setViewEnums(optionEnums, setKey)
this.optionEnums = optionEnums
this.visibleKey = type
this.visible = true
}
}
},
//设置显示枚举
setViewEnums(optionEnums, key) {
let viewEnums = {}
optionEnums.map(item => {
viewEnums[item.value] = item.label
})
this[key] = viewEnums
},
//确认选择
onConfirmPicker(value) {
this.setFormData(value)
this.visible = false
},
// 时间选择
onSelsectDate(dateInfo) {
const {
timestamp
} = dateInfo
this.setFormData(new Date(timestamp))
this.showPopup = false
},
//设置formData
setFormData(value) {
if (this.isDriver) {
console.log(value)
const key = this.visibleKey
if (key.includes('.')) { //对象特殊处理
const keys = key.split('.')
this[keys[0]][keys[1]] = value
} else {
this.driverInfo[key] = value
}
} else {
const key = this.visibleKey
if (key.includes('.')) { //对象特殊处理
const keys = key.split('.')
this.truckInfo[keys[0]][keys[1]] = value
} else {
this.truckInfo[key] = value
}
}
},
//关闭时间选择框
onVisibleDate(type) {
if (type) {
this.visibleKey = type
}
this.showPopup = !this.showPopup
},
checkRequire(obj){
let rules
if(this.isDriver){
rules = {
'name': { required: true, message:"姓名"},
'tel': { required: true, message:"联系方式"},
'idCard.code': { required: true, message:"身份证"},
'idCard.effectiveDate': { required: true, message:"身份证生效日期" },
'idCard.expirationDate': { required: true, message:"身份证失效日期" },
'idCard.faceImage': { required: true, message:"身份证正面照片" },
'idCard.backImage': { required: true, message:"身份证反面照片" },
}
}else{
rules = {
'truckInfo.name': { required: true, message:"车牌号"},
}
}
let res = true
let message = ''
for(let key of Object.keys(rules)){
let feildArr = key.split('.')
let required = rules[key].required
let value
for(let f of feildArr){
value = value ? value[f] : obj[f]
}
if(required && (!value || !value.length)){
res = false
message = rules[key].message
break;
}
}
if(!res){
uni.showToast({
icon:'error',
title:`请完善必填项`
})
}
return res
},
getUploadImageValue(refName){
return new Promise((res, rej) => {
let fileListLength = this.$refs[refName].fileList.length
if(fileListLength){
this.$refs[refName].uploadImage(imgs =>res(imgs))
}else{
res('')
}
})
},
async save() {
if (this.isDriver) {
let aux = {...this.driverInfo}
aux.idCard = this.idCard
aux.driverLicense = this.driverLicense
aux.driverJobCertificate = this.driverJobCertificate
aux.ownerId = this.carrierList.find(i => i.label === this.driverInfo.carrierName).value
aux.idCard.faceImage = await this.getUploadImageValue('idcardFaceImage')
aux.idCard.backImage = await this.getUploadImageValue('idcardBackImage')
aux.driverLicense.faceImage = await this.getUploadImageValue('driverLicenseFaceImage')
aux.driverLicense.backImage = await this.getUploadImageValue('driverLicenseBackImage')
aux.driverJobCertificate.faceImage= await this.getUploadImageValue('driverJobCertificateFaceImage')
// 校验必填项
if(!this.checkRequire(aux)) return;
const reqData = {
aux,
"args": {
"selectedIds": [ this.id ]
}
}
UpdateDriverInfo(reqData).then(res => {
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 1500,
success() {
uni.navigateBack()
}
})
})
} else {
let aux = { ...this.truckInfo }
aux.faceImage = await this.getUploadImageValue('faceImage')
if (aux.facilityModeId) {
const res = await queryTruckType({
args: {
pageNum: 1,
pageSize: 10000
}
})
for (const data of res.data.data.datas) {
if (data.name === aux.facilityModeId) {
aux.facilityModeId = data.id
break
}
}
}
if (aux.driver1Id) {
const res = await searchDriverList({
args: {
pageNum: 1,
pageSize: 10000
}
})
for (const data of res.data.data.datas) {
if (data.name === aux.driver1Id) {
aux.driver1Id = data.id
break
}
}
}
if (aux.ownerId) {
const res = await GetCarrierList({
args: {
pageNum: 1,
pageSize: 10000
}
})
for (const data of res.data.data.datas) {
if (data.name === aux.ownerId) {
aux.ownerId = data.id
break
}
}
}
const reqData = {
aux,
"args": {
"selectedIds": [
this.id
]
}
}
UpdateTruckInfo(reqData).then(res => {
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 1500,
success() {
uni.navigateBack()
}
})
})
}
},
checkDriver() {
uni.navigateTo({
url: '/subpkg/checkTruck/checkTruck'
})
},
cancel() {
uni.navigateBack()
},
setTruckDriver(id, name){
this.truckInfo.driver1Id = name
// this.truckInfo.name = name
},
getCarrierList(){
this.carrierList = []
GetCarrierList({ "args": { pageNum:1, pageSize:100 }}).then(res=>{
res.data.data.datas.map(data=>{
this.carrierList.push({ label: data.name, value: data.id})
})
})
this.$emit()
},
async onUploadOCR(fileInfo){
const {url, cameraType} = fileInfo
const ocrService = {
'idCardFace': {service: 'idCard', imageType: 'front'}, //身份证正面
'idCardBack': {service: 'idCard', imageType: 'back'}, //身份证反面
'driveCardFace': {service: 'drivingLicense', imageType: 'front'}, //驾驶证正页
'driveCardBack': {service: 'drivingLicense', imageType: 'back'}, //驾驶证副页
'vehicleCardFace': {service: 'vehicleLicense', imageType: 'front'}, //行驶证正页
'vehicleCardBack': {service: 'vehicleLicense', imageType: 'back'}, //行驶证副页
}
if(!ocrService[cameraType]) return //OCR服务不存在则跳出
const {service, imageType} = ocrService[cameraType]
const uploadRes = await uploadImg(url) //获取文件ID
const fileId = JSON.parse(uploadRes).data?.path;
const reqData = {'aux': {document: fileId, imageType}}
const res = await OCRService(service, reqData)
this.onOcrCallback(res.data.data, cameraType)
},
//OCR回显
onOcrCallback(data, cameraType){
const {driverInfo, idCard, driverLicense, truckInfo} = this
switch(cameraType){
case 'idCardFace': //身份证正面
this.driverInfo = Object.assign(driverInfo, {
name: data.name,
gender: this.genderViewEnums.find(item => item.label === data.gender)?.value,
})
this.idCard = Object.assign(idCard, {code: data.idCardNumber})
break;
case 'idCardBack': //身份证反面
this.idCard = Object.assign(idCard, {
effectiveDate: data.issuingDate, //生效日期
expirationDate: data.expiryDate, //失效日期
})
break;
case 'driveCardFace': //驾驶证正面
this.driverInfo = Object.assign(driverInfo, {
name: data.name,
gender: this.genderViewEnums.find(item => item.label === data.gender)?.value,
})
this.driverLicense= Object.assign(driverLicense, {
code: data.idCardNumber, //证件号码
quasiDrivingType: data.driverType, //准驾车型
effectiveDate: data.effectiveStartTime, //生效日期
expirationDate: data.expiryDate, //失效日期
})
break;
case 'driveCardBack': //驾驶证反面
this.driverInfo = Object.assign(driverInfo, {name: data.name})
this.driverLicense= Object.assign(driverLicense, {code: data.idCardNumber})
break;
case 'vehicleCardFace': //行驶证正面
this.truckInfo = Object.assign(truckInfo, {
name: data.licenseNumber, //车牌号
code: data.vehicleIdentificationNumber, //车辆识别代码
effectiveDate: data.issuingDate, //生效日期
})
break;
case 'vehicleCardBack': //行驶证反面
this.truckInfo = Object.assign(truckInfo, {name: data.licenseNumber})
break;
}
}
}
}
</script>
<style lang="scss">
.registerTruck {
.module-title {
padding: 32rpx 32rpx 16rpx;
font-weight: bolder;
.vertical-separate {
height: 40rpx;
border-left: 7rpx solid #797979;
margin-right: 20rpx;
}
}
/deep/.basic-info,
/deep/.driverLicense,
/deep/.driverJobCertificate,
/deep/.drivingCertificate {
padding: 0 40rpx;
background-color: #ffffff;
.custom-cell-row {
padding: 40rpx 0;
margin-top: 0;
.custom-cell-label {
color: #8C8C8C;
}
}
}
.certification {
margin-top: -20rpx;
}
.driverLicense {
.previewImg {
width: 100%;
height: 240rpx;
margin-top: 20rpx;
}
}
.driverJobCertificate,
.drivingCertificate {
.previewImg {
width: 180rpx;
height: 140rpx;
margin: 0 0 20rpx 30rpx;
}
}
/deep/.basicInfo,
/deep/.driverLicense,
/deep/.driverJobCertificate {
background-color: #ffffff;
.input-tip {
font-size: 28rpx;
color: #BFBFBF;
}
.u-form-item__body__left__content__label {
color: #8C8C8C;
font-size: 28rpx;
}
.u-form-item__body {
padding: 40rpx 0;
}
.u-icon {
margin-left: 20rpx;
}
}
/deep/.orderTotal {
display: none;
}
/deep/.uploade-file {
.fileList {
padding-top: 20rpx;
}
.previewImages {
width: 100%;
}
.previewImg {
margin: 0 !important;
width: 100% !important;
height: 240rpx !important;
}
.uploadeBtn {
width: 100% !important;
margin: 0 !important;
height: 240rpx !important;
}
.u-upload__wrap {
&>view {
width: 100% !important;
}
}
}
.select_footer {
position: sticky;
display: flex;
justify-content: space-between;
padding: 32rpx 0;
width: 100%;
background-color: #FFFFFF;
bottom: 0;
z-index: 999;
button {
width: 339rpx;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
color: #2E75E6;
padding: 0 24rpx;
border: 3rpx solid transparent;
position: relative;
background-clip: padding-box, border-box;
background-origin: padding-box, border-box;
background-image: linear-gradient(90deg, #FAFAFA, #FAFAFA), linear-gradient(90deg, #2E75E6, #5E58EE);
&:after {
content: "";
}
&:last-child {
background-image: linear-gradient(90deg, #2E75E6, #5E58EE), linear-gradient(90deg, #2E75E6, #5E58EE);
color: #FFFFFF;
}
}
}
}
</style>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<!-- Open Graph data -->
<!-- <meta property="og:title" content="Title Here" /> -->
<!-- <meta property="og:url" content="http://www.example.com/" /> -->
<!-- <meta property="og:image" content="http://example.com/image.jpg" /> -->
<!-- <meta property="og:description" content="Description Here" /> -->
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
\ No newline at end of file
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
@import 'uview-ui/theme.scss';
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;
## 1.4.3(2022-01-25)
- 修复 初始化的时候 ,open 属性失效的bug
## 1.4.2(2022-01-21)
- 修复 微信小程序resize后组件收起的bug
## 1.4.1(2021-11-22)
- 修复 vue3中个别scss变量无法找到的问题
## 1.4.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-collapse](https://uniapp.dcloud.io/component/uniui/uni-collapse)
## 1.3.3(2021-08-17)
- 优化 show-arrow 属性默认为true
## 1.3.2(2021-08-17)
- 新增 show-arrow 属性,控制是否显示右侧箭头
## 1.3.1(2021-07-30)
- 优化 vue3下小程序事件警告的问题
## 1.3.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.2.2(2021-07-21)
- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug
## 1.2.1(2021-07-21)
- 优化 组件示例
## 1.2.0(2021-07-21)
- 新增 组件折叠动画
- 新增 value\v-model 属性 ,动态修改面板折叠状态
- 新增 title 插槽 ,可定义面板标题
- 新增 border 属性 ,显示隐藏面板内容分隔线
- 新增 title-border 属性 ,显示隐藏面板标题分隔线
- 修复 resize 方法失效的Bug
- 修复 change 事件返回参数不正确的Bug
- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法
## 1.1.7(2021-05-12)
- 新增 组件示例地址
## 1.1.6(2021-02-05)
- 优化 组件引用关系,通过uni_modules引用组件
## 1.1.5(2021-02-05)
- 调整为uni_modules目录规范
\ No newline at end of file
<template>
<view class="uni-collapse-item">
<!-- onClick(!isOpen) -->
<view @click="onClick(!isOpen)" class="uni-collapse-item__title"
:class="{'is-open':isOpen &&titleBorder === 'auto' ,'uni-collapse-item-border':titleBorder !== 'none'}">
<view class="uni-collapse-item__title-wrap">
<slot name="title">
<view class="uni-collapse-item__title-box" :class="{'is-disabled':disabled}">
<image v-if="thumb" :src="thumb" class="uni-collapse-item__title-img" />
<text class="uni-collapse-item__title-text">{{ title }}</text>
</view>
</slot>
</view>
<view v-if="showArrow"
:class="{ 'uni-collapse-item__title-arrow-active': isOpen, 'uni-collapse-item--animation': showAnimation === true }"
class="uni-collapse-item__title-arrow">
<uni-icons :color="disabled?'#ddd':'#bbb'" size="14" type="bottom" />
</view>
</view>
<view class="uni-collapse-item__wrap" :class="{'is--transition':showAnimation}"
:style="{height: (isOpen?height:0) +'px'}">
<view :id="elId" ref="collapse--hook" class="uni-collapse-item__wrap-content"
:class="{open:isheight,'uni-collapse-item--border':border&&isOpen}">
<slot></slot>
</view>
</view>
</view>
</template>
<script>
// #ifdef APP-NVUE
const dom = weex.requireModule('dom')
// #endif
/**
* CollapseItem 折叠面板子组件
* @description 折叠面板子组件
* @property {String} title 标题文字
* @property {String} thumb 标题左侧缩略图
* @property {String} name 唯一标志符
* @property {Boolean} open = [true|false] 是否展开组件
* @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线
* @property {Boolean} border = [true|false] 是否显示分隔线
* @property {Boolean} disabled = [true|false] 是否展开面板
* @property {Boolean} showAnimation = [true|false] 开启动画
* @property {Boolean} showArrow = [true|false] 是否显示右侧箭头
*/
export default {
name: 'uniCollapseItem',
props: {
// 列表标题
title: {
type: String,
default: ''
},
name: {
type: [Number, String],
default: ''
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// #ifdef APP-PLUS
// 是否显示动画,app 端默认不开启动画,卡顿严重
showAnimation: {
type: Boolean,
default: false
},
// #endif
// #ifndef APP-PLUS
// 是否显示动画
showAnimation: {
type: Boolean,
default: true
},
// #endif
// 是否展开
open: {
type: Boolean,
default: false
},
// 缩略图
thumb: {
type: String,
default: ''
},
// 标题分隔线显示类型
titleBorder: {
type: String,
default: 'auto'
},
border: {
type: Boolean,
default: true
},
showArrow: {
type: Boolean,
default: true
}
},
data() {
// TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug
const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
return {
isOpen: false,
isheight: null,
height: 0,
elId,
nameSync: 0
}
},
watch: {
open(val) {
this.isOpen = val
this.onClick(val, 'init')
}
},
updated(e) {
this.$nextTick(() => {
this.init(true)
})
},
created() {
this.collapse = this.getCollapse()
this.oldHeight = 0
this.onClick(this.open, 'init')
},
// #ifndef VUE3
// TODO vue2
destroyed() {
if (this.__isUnmounted) return
this.uninstall()
},
// #endif
// #ifdef VUE3
// TODO vue3
unmounted() {
this.__isUnmounted = true
this.uninstall()
},
// #endif
mounted() {
if (!this.collapse) return
if (this.name !== '') {
this.nameSync = this.name
} else {
this.nameSync = this.collapse.childrens.length + ''
}
if (this.collapse.names.indexOf(this.nameSync) === -1) {
this.collapse.names.push(this.nameSync)
} else {
console.warn(`name 值 ${this.nameSync} 重复`);
}
if (this.collapse.childrens.indexOf(this) === -1) {
this.collapse.childrens.push(this)
}
this.init()
},
methods: {
init(type) {
// #ifndef APP-NVUE
this.getCollapseHeight(type)
// #endif
// #ifdef APP-NVUE
this.getNvueHwight(type)
// #endif
},
uninstall() {
if (this.collapse) {
this.collapse.childrens.forEach((item, index) => {
if (item === this) {
this.collapse.childrens.splice(index, 1)
}
})
this.collapse.names.forEach((item, index) => {
if (item === this.nameSync) {
this.collapse.names.splice(index, 1)
}
})
}
},
onClick(isOpen, type) {
if (this.disabled) return
this.isOpen = isOpen
if (this.isOpen && this.collapse) {
this.collapse.setAccordion(this)
}
if (type !== 'init') {
this.collapse.onChange(isOpen, this)
}
},
getCollapseHeight(type, index = 0) {
const views = uni.createSelectorQuery().in(this)
views
.select(`#${this.elId}`)
.fields({
size: true
}, data => {
// TODO 百度中可能获取不到节点信息 ,需要循环获取
if (index >= 10) return
if (!data) {
index++
this.getCollapseHeight(false, index)
return
}
// #ifdef APP-NVUE
this.height = data.height + 1
// #endif
// #ifndef APP-NVUE
this.height = data.height
// #endif
this.isheight = true
if (type) return
this.onClick(this.isOpen, 'init')
})
.exec()
},
getNvueHwight(type) {
const result = dom.getComponentRect(this.$refs['collapse--hook'], option => {
if (option && option.result && option.size) {
// #ifdef APP-NVUE
this.height = option.size.height + 1
// #endif
// #ifndef APP-NVUE
this.height = option.size.height
// #endif
this.isheight = true
if (type) return
this.onClick(this.open, 'init')
}
})
},
/**
* 获取父元素实例
*/
getCollapse(name = 'uniCollapse') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
}
}
}
</script>
<style lang="scss">
.uni-collapse-item {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
&__title {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
transition: border-bottom-color .3s;
// transition-property: border-bottom-color;
// transition-duration: 5s;
&-wrap {
width: 100%;
flex: 1;
}
&-box {
padding: 0 15px;
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
box-sizing: border-box;
/* #endif */
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 48px;
line-height: 48px;
background-color: #fff;
color: #303133;
font-size: 13px;
font-weight: 500;
/* #ifdef H5 */
cursor: pointer;
outline: none;
/* #endif */
&.is-disabled {
.uni-collapse-item__title-text {
color: #999;
}
}
}
&.uni-collapse-item-border {
border-bottom: 1px solid #ebeef5;
}
&.is-open {
border-bottom-color: transparent;
}
&-img {
height: 22px;
width: 22px;
margin-right: 10px;
}
&-text {
flex: 1;
font-size: 14px;
/* #ifndef APP-NVUE */
white-space: nowrap;
color: inherit;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
overflow: hidden;
text-overflow: ellipsis;
}
&-arrow {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
margin-right: 10px;
transform: rotate(0deg);
&-active {
transform: rotate(-180deg);
}
}
}
&__wrap {
/* #ifndef APP-NVUE */
will-change: height;
box-sizing: border-box;
/* #endif */
background-color: #fff;
overflow: hidden;
position: relative;
height: 0;
&.is--transition {
// transition: all 0.3s;
transition-property: height, border-bottom-width;
transition-duration: 0.3s;
/* #ifndef APP-NVUE */
will-change: height;
/* #endif */
}
&-content {
position: absolute;
font-size: 13px;
color: #303133;
// transition: height 0.3s;
border-bottom-color: transparent;
border-bottom-style: solid;
border-bottom-width: 0;
&.uni-collapse-item--border {
border-bottom-width: 1px;
border-bottom-color: red;
border-bottom-color: #ebeef5;
}
&.open {
position: relative;
}
}
}
&--animation {
transition-property: transform;
transition-duration: 0.3s;
transition-timing-function: ease;
}
}
</style>
<template>
<view class="uni-collapse">
<slot />
</view>
</template>
<script>
/**
* Collapse 折叠面板
* @description 展示可以折叠 / 展开的内容区域
* @tutorial https://ext.dcloud.net.cn/plugin?id=23
* @property {String|Array} value 当前激活面板改变时触发(如果是手风琴模式,参数类型为string,否则为array)
* @property {Boolean} accordion = [true|false] 是否开启手风琴效果是否开启手风琴效果
* @event {Function} change 切换面板时触发,如果是手风琴模式,返回类型为string,否则为array
*/
export default {
name: 'uniCollapse',
emits:['change','activeItem','input','update:modelValue'],
props: {
value: {
type: [String, Array],
default: ''
},
modelValue: {
type: [String, Array],
default: ''
},
accordion: {
// 是否开启手风琴效果
type: [Boolean, String],
default: false
},
},
data() {
return {}
},
computed: {
// TODO 兼容 vue2 和 vue3
dataValue() {
let value = (typeof this.value === 'string' && this.value === '') ||
(Array.isArray(this.value) && this.value.length === 0)
let modelValue = (typeof this.modelValue === 'string' && this.modelValue === '') ||
(Array.isArray(this.modelValue) && this.modelValue.length === 0)
if (value) {
return this.modelValue
}
if (modelValue) {
return this.value
}
return this.value
}
},
watch: {
dataValue(val) {
this.setOpen(val)
}
},
created() {
this.childrens = []
this.names = []
},
mounted() {
this.$nextTick(()=>{
this.setOpen(this.dataValue)
})
},
methods: {
setOpen(val) {
let str = typeof val === 'string'
let arr = Array.isArray(val)
this.childrens.forEach((vm, index) => {
if (str) {
if (val === vm.nameSync) {
if (!this.accordion) {
console.warn('accordion 属性为 false ,v-model 类型应该为 array')
return
}
vm.isOpen = true
}
}
if (arr) {
val.forEach(v => {
if (v === vm.nameSync) {
if (this.accordion) {
console.warn('accordion 属性为 true ,v-model 类型应该为 string')
return
}
vm.isOpen = true
}
})
}
})
this.emit(val)
},
setAccordion(self) {
if (!this.accordion) return
this.childrens.forEach((vm, index) => {
if (self !== vm) {
vm.isOpen = false
}
})
},
resize() {
this.childrens.forEach((vm, index) => {
// #ifndef APP-NVUE
vm.getCollapseHeight()
// #endif
// #ifdef APP-NVUE
vm.getNvueHwight()
// #endif
})
},
onChange(isOpen, self) {
let activeItem = []
if (this.accordion) {
activeItem = isOpen ? self.nameSync : ''
} else {
this.childrens.forEach((vm, index) => {
if (vm.isOpen) {
activeItem.push(vm.nameSync)
}
})
}
this.$emit('change', activeItem)
this.emit(activeItem)
},
emit(val){
this.$emit('input', val)
this.$emit('update:modelValue', val)
}
}
}
</script>
<style lang="scss" >
.uni-collapse {
/* #ifndef APP-NVUE */
width: 100%;
display: flex;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
flex-direction: column;
background-color: #fff;
}
</style>
{
"id": "uni-collapse",
"displayName": "uni-collapse 折叠面板",
"version": "1.4.3",
"description": "Collapse 组件,可以折叠 / 展开的内容区域。",
"keywords": [
"uni-ui",
"折叠",
"折叠面板",
"手风琴"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
## Collapse 折叠面板
> **组件名:uni-collapse**
> 代码块: `uCollapse`
> 关联组件:`uni-collapse-item`、`uni-icons`。
折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-collapse)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
## 1.3.5(2022-01-24)
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.4(2022-01-24)
- 优化 size 支持其他单位
## 1.3.3(2022-01-17)
- 修复 nvue 有些图标不显示的bug,兼容老版本图标
## 1.3.2(2021-12-01)
- 优化 示例可复制图标名称
## 1.3.1(2021-11-23)
- 优化 兼容旧组件 type 值
## 1.3.0(2021-11-19)
- 新增 更多图标
- 优化 自定义图标使用方式
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
## 1.1.7(2021-11-08)
## 1.2.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.5(2021-05-12)
- 新增 组件示例地址
## 1.1.4(2021-02-05)
- 调整为uni_modules目录规范
export default {
"id": "2852637",
"name": "uniui图标库",
"font_family": "uniicons",
"css_prefix_text": "uniui-",
"description": "",
"glyphs": [
{
"icon_id": "25027049",
"name": "yanse",
"font_class": "color",
"unicode": "e6cf",
"unicode_decimal": 59087
},
{
"icon_id": "25027048",
"name": "wallet",
"font_class": "wallet",
"unicode": "e6b1",
"unicode_decimal": 59057
},
{
"icon_id": "25015720",
"name": "settings-filled",
"font_class": "settings-filled",
"unicode": "e6ce",
"unicode_decimal": 59086
},
{
"icon_id": "25015434",
"name": "shimingrenzheng-filled",
"font_class": "auth-filled",
"unicode": "e6cc",
"unicode_decimal": 59084
},
{
"icon_id": "24934246",
"name": "shop-filled",
"font_class": "shop-filled",
"unicode": "e6cd",
"unicode_decimal": 59085
},
{
"icon_id": "24934159",
"name": "staff-filled-01",
"font_class": "staff-filled",
"unicode": "e6cb",
"unicode_decimal": 59083
},
{
"icon_id": "24932461",
"name": "VIP-filled",
"font_class": "vip-filled",
"unicode": "e6c6",
"unicode_decimal": 59078
},
{
"icon_id": "24932462",
"name": "plus_circle_fill",
"font_class": "plus-filled",
"unicode": "e6c7",
"unicode_decimal": 59079
},
{
"icon_id": "24932463",
"name": "folder_add-filled",
"font_class": "folder-add-filled",
"unicode": "e6c8",
"unicode_decimal": 59080
},
{
"icon_id": "24932464",
"name": "yanse-filled",
"font_class": "color-filled",
"unicode": "e6c9",
"unicode_decimal": 59081
},
{
"icon_id": "24932465",
"name": "tune-filled",
"font_class": "tune-filled",
"unicode": "e6ca",
"unicode_decimal": 59082
},
{
"icon_id": "24932455",
"name": "a-rilidaka-filled",
"font_class": "calendar-filled",
"unicode": "e6c0",
"unicode_decimal": 59072
},
{
"icon_id": "24932456",
"name": "notification-filled",
"font_class": "notification-filled",
"unicode": "e6c1",
"unicode_decimal": 59073
},
{
"icon_id": "24932457",
"name": "wallet-filled",
"font_class": "wallet-filled",
"unicode": "e6c2",
"unicode_decimal": 59074
},
{
"icon_id": "24932458",
"name": "paihangbang-filled",
"font_class": "medal-filled",
"unicode": "e6c3",
"unicode_decimal": 59075
},
{
"icon_id": "24932459",
"name": "gift-filled",
"font_class": "gift-filled",
"unicode": "e6c4",
"unicode_decimal": 59076
},
{
"icon_id": "24932460",
"name": "fire-filled",
"font_class": "fire-filled",
"unicode": "e6c5",
"unicode_decimal": 59077
},
{
"icon_id": "24928001",
"name": "refreshempty",
"font_class": "refreshempty",
"unicode": "e6bf",
"unicode_decimal": 59071
},
{
"icon_id": "24926853",
"name": "location-ellipse",
"font_class": "location-filled",
"unicode": "e6af",
"unicode_decimal": 59055
},
{
"icon_id": "24926735",
"name": "person-filled",
"font_class": "person-filled",
"unicode": "e69d",
"unicode_decimal": 59037
},
{
"icon_id": "24926703",
"name": "personadd-filled",
"font_class": "personadd-filled",
"unicode": "e698",
"unicode_decimal": 59032
},
{
"icon_id": "24923351",
"name": "back",
"font_class": "back",
"unicode": "e6b9",
"unicode_decimal": 59065
},
{
"icon_id": "24923352",
"name": "forward",
"font_class": "forward",
"unicode": "e6ba",
"unicode_decimal": 59066
},
{
"icon_id": "24923353",
"name": "arrowthinright",
"font_class": "arrow-right",
"unicode": "e6bb",
"unicode_decimal": 59067
},
{
"icon_id": "24923353",
"name": "arrowthinright",
"font_class": "arrowthinright",
"unicode": "e6bb",
"unicode_decimal": 59067
},
{
"icon_id": "24923354",
"name": "arrowthinleft",
"font_class": "arrow-left",
"unicode": "e6bc",
"unicode_decimal": 59068
},
{
"icon_id": "24923354",
"name": "arrowthinleft",
"font_class": "arrowthinleft",
"unicode": "e6bc",
"unicode_decimal": 59068
},
{
"icon_id": "24923355",
"name": "arrowthinup",
"font_class": "arrow-up",
"unicode": "e6bd",
"unicode_decimal": 59069
},
{
"icon_id": "24923355",
"name": "arrowthinup",
"font_class": "arrowthinup",
"unicode": "e6bd",
"unicode_decimal": 59069
},
{
"icon_id": "24923356",
"name": "arrowthindown",
"font_class": "arrow-down",
"unicode": "e6be",
"unicode_decimal": 59070
},{
"icon_id": "24923356",
"name": "arrowthindown",
"font_class": "arrowthindown",
"unicode": "e6be",
"unicode_decimal": 59070
},
{
"icon_id": "24923349",
"name": "arrowdown",
"font_class": "bottom",
"unicode": "e6b8",
"unicode_decimal": 59064
},{
"icon_id": "24923349",
"name": "arrowdown",
"font_class": "arrowdown",
"unicode": "e6b8",
"unicode_decimal": 59064
},
{
"icon_id": "24923346",
"name": "arrowright",
"font_class": "right",
"unicode": "e6b5",
"unicode_decimal": 59061
},
{
"icon_id": "24923346",
"name": "arrowright",
"font_class": "arrowright",
"unicode": "e6b5",
"unicode_decimal": 59061
},
{
"icon_id": "24923347",
"name": "arrowup",
"font_class": "top",
"unicode": "e6b6",
"unicode_decimal": 59062
},
{
"icon_id": "24923347",
"name": "arrowup",
"font_class": "arrowup",
"unicode": "e6b6",
"unicode_decimal": 59062
},
{
"icon_id": "24923348",
"name": "arrowleft",
"font_class": "left",
"unicode": "e6b7",
"unicode_decimal": 59063
},
{
"icon_id": "24923348",
"name": "arrowleft",
"font_class": "arrowleft",
"unicode": "e6b7",
"unicode_decimal": 59063
},
{
"icon_id": "24923334",
"name": "eye",
"font_class": "eye",
"unicode": "e651",
"unicode_decimal": 58961
},
{
"icon_id": "24923335",
"name": "eye-filled",
"font_class": "eye-filled",
"unicode": "e66a",
"unicode_decimal": 58986
},
{
"icon_id": "24923336",
"name": "eye-slash",
"font_class": "eye-slash",
"unicode": "e6b3",
"unicode_decimal": 59059
},
{
"icon_id": "24923337",
"name": "eye-slash-filled",
"font_class": "eye-slash-filled",
"unicode": "e6b4",
"unicode_decimal": 59060
},
{
"icon_id": "24923305",
"name": "info-filled",
"font_class": "info-filled",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "24923299",
"name": "reload-01",
"font_class": "reload",
"unicode": "e6b2",
"unicode_decimal": 59058
},
{
"icon_id": "24923195",
"name": "mic_slash_fill",
"font_class": "micoff-filled",
"unicode": "e6b0",
"unicode_decimal": 59056
},
{
"icon_id": "24923165",
"name": "map-pin-ellipse",
"font_class": "map-pin-ellipse",
"unicode": "e6ac",
"unicode_decimal": 59052
},
{
"icon_id": "24923166",
"name": "map-pin",
"font_class": "map-pin",
"unicode": "e6ad",
"unicode_decimal": 59053
},
{
"icon_id": "24923167",
"name": "location",
"font_class": "location",
"unicode": "e6ae",
"unicode_decimal": 59054
},
{
"icon_id": "24923064",
"name": "starhalf",
"font_class": "starhalf",
"unicode": "e683",
"unicode_decimal": 59011
},
{
"icon_id": "24923065",
"name": "star",
"font_class": "star",
"unicode": "e688",
"unicode_decimal": 59016
},
{
"icon_id": "24923066",
"name": "star-filled",
"font_class": "star-filled",
"unicode": "e68f",
"unicode_decimal": 59023
},
{
"icon_id": "24899646",
"name": "a-rilidaka",
"font_class": "calendar",
"unicode": "e6a0",
"unicode_decimal": 59040
},
{
"icon_id": "24899647",
"name": "fire",
"font_class": "fire",
"unicode": "e6a1",
"unicode_decimal": 59041
},
{
"icon_id": "24899648",
"name": "paihangbang",
"font_class": "medal",
"unicode": "e6a2",
"unicode_decimal": 59042
},
{
"icon_id": "24899649",
"name": "font",
"font_class": "font",
"unicode": "e6a3",
"unicode_decimal": 59043
},
{
"icon_id": "24899650",
"name": "gift",
"font_class": "gift",
"unicode": "e6a4",
"unicode_decimal": 59044
},
{
"icon_id": "24899651",
"name": "link",
"font_class": "link",
"unicode": "e6a5",
"unicode_decimal": 59045
},
{
"icon_id": "24899652",
"name": "notification",
"font_class": "notification",
"unicode": "e6a6",
"unicode_decimal": 59046
},
{
"icon_id": "24899653",
"name": "staff",
"font_class": "staff",
"unicode": "e6a7",
"unicode_decimal": 59047
},
{
"icon_id": "24899654",
"name": "VIP",
"font_class": "vip",
"unicode": "e6a8",
"unicode_decimal": 59048
},
{
"icon_id": "24899655",
"name": "folder_add",
"font_class": "folder-add",
"unicode": "e6a9",
"unicode_decimal": 59049
},
{
"icon_id": "24899656",
"name": "tune",
"font_class": "tune",
"unicode": "e6aa",
"unicode_decimal": 59050
},
{
"icon_id": "24899657",
"name": "shimingrenzheng",
"font_class": "auth",
"unicode": "e6ab",
"unicode_decimal": 59051
},
{
"icon_id": "24899565",
"name": "person",
"font_class": "person",
"unicode": "e699",
"unicode_decimal": 59033
},
{
"icon_id": "24899566",
"name": "email-filled",
"font_class": "email-filled",
"unicode": "e69a",
"unicode_decimal": 59034
},
{
"icon_id": "24899567",
"name": "phone-filled",
"font_class": "phone-filled",
"unicode": "e69b",
"unicode_decimal": 59035
},
{
"icon_id": "24899568",
"name": "phone",
"font_class": "phone",
"unicode": "e69c",
"unicode_decimal": 59036
},
{
"icon_id": "24899570",
"name": "email",
"font_class": "email",
"unicode": "e69e",
"unicode_decimal": 59038
},
{
"icon_id": "24899571",
"name": "personadd",
"font_class": "personadd",
"unicode": "e69f",
"unicode_decimal": 59039
},
{
"icon_id": "24899558",
"name": "chatboxes-filled",
"font_class": "chatboxes-filled",
"unicode": "e692",
"unicode_decimal": 59026
},
{
"icon_id": "24899559",
"name": "contact",
"font_class": "contact",
"unicode": "e693",
"unicode_decimal": 59027
},
{
"icon_id": "24899560",
"name": "chatbubble-filled",
"font_class": "chatbubble-filled",
"unicode": "e694",
"unicode_decimal": 59028
},
{
"icon_id": "24899561",
"name": "contact-filled",
"font_class": "contact-filled",
"unicode": "e695",
"unicode_decimal": 59029
},
{
"icon_id": "24899562",
"name": "chatboxes",
"font_class": "chatboxes",
"unicode": "e696",
"unicode_decimal": 59030
},
{
"icon_id": "24899563",
"name": "chatbubble",
"font_class": "chatbubble",
"unicode": "e697",
"unicode_decimal": 59031
},
{
"icon_id": "24881290",
"name": "upload-filled",
"font_class": "upload-filled",
"unicode": "e68e",
"unicode_decimal": 59022
},
{
"icon_id": "24881292",
"name": "upload",
"font_class": "upload",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "24881293",
"name": "weixin",
"font_class": "weixin",
"unicode": "e691",
"unicode_decimal": 59025
},
{
"icon_id": "24881274",
"name": "compose",
"font_class": "compose",
"unicode": "e67f",
"unicode_decimal": 59007
},
{
"icon_id": "24881275",
"name": "qq",
"font_class": "qq",
"unicode": "e680",
"unicode_decimal": 59008
},
{
"icon_id": "24881276",
"name": "download-filled",
"font_class": "download-filled",
"unicode": "e681",
"unicode_decimal": 59009
},
{
"icon_id": "24881277",
"name": "pengyouquan",
"font_class": "pyq",
"unicode": "e682",
"unicode_decimal": 59010
},
{
"icon_id": "24881279",
"name": "sound",
"font_class": "sound",
"unicode": "e684",
"unicode_decimal": 59012
},
{
"icon_id": "24881280",
"name": "trash-filled",
"font_class": "trash-filled",
"unicode": "e685",
"unicode_decimal": 59013
},
{
"icon_id": "24881281",
"name": "sound-filled",
"font_class": "sound-filled",
"unicode": "e686",
"unicode_decimal": 59014
},
{
"icon_id": "24881282",
"name": "trash",
"font_class": "trash",
"unicode": "e687",
"unicode_decimal": 59015
},
{
"icon_id": "24881284",
"name": "videocam-filled",
"font_class": "videocam-filled",
"unicode": "e689",
"unicode_decimal": 59017
},
{
"icon_id": "24881285",
"name": "spinner-cycle",
"font_class": "spinner-cycle",
"unicode": "e68a",
"unicode_decimal": 59018
},
{
"icon_id": "24881286",
"name": "weibo",
"font_class": "weibo",
"unicode": "e68b",
"unicode_decimal": 59019
},
{
"icon_id": "24881288",
"name": "videocam",
"font_class": "videocam",
"unicode": "e68c",
"unicode_decimal": 59020
},
{
"icon_id": "24881289",
"name": "download",
"font_class": "download",
"unicode": "e68d",
"unicode_decimal": 59021
},
{
"icon_id": "24879601",
"name": "help",
"font_class": "help",
"unicode": "e679",
"unicode_decimal": 59001
},
{
"icon_id": "24879602",
"name": "navigate-filled",
"font_class": "navigate-filled",
"unicode": "e67a",
"unicode_decimal": 59002
},
{
"icon_id": "24879603",
"name": "plusempty",
"font_class": "plusempty",
"unicode": "e67b",
"unicode_decimal": 59003
},
{
"icon_id": "24879604",
"name": "smallcircle",
"font_class": "smallcircle",
"unicode": "e67c",
"unicode_decimal": 59004
},
{
"icon_id": "24879605",
"name": "minus-filled",
"font_class": "minus-filled",
"unicode": "e67d",
"unicode_decimal": 59005
},
{
"icon_id": "24879606",
"name": "micoff",
"font_class": "micoff",
"unicode": "e67e",
"unicode_decimal": 59006
},
{
"icon_id": "24879588",
"name": "closeempty",
"font_class": "closeempty",
"unicode": "e66c",
"unicode_decimal": 58988
},
{
"icon_id": "24879589",
"name": "clear",
"font_class": "clear",
"unicode": "e66d",
"unicode_decimal": 58989
},
{
"icon_id": "24879590",
"name": "navigate",
"font_class": "navigate",
"unicode": "e66e",
"unicode_decimal": 58990
},
{
"icon_id": "24879591",
"name": "minus",
"font_class": "minus",
"unicode": "e66f",
"unicode_decimal": 58991
},
{
"icon_id": "24879592",
"name": "image",
"font_class": "image",
"unicode": "e670",
"unicode_decimal": 58992
},
{
"icon_id": "24879593",
"name": "mic",
"font_class": "mic",
"unicode": "e671",
"unicode_decimal": 58993
},
{
"icon_id": "24879594",
"name": "paperplane",
"font_class": "paperplane",
"unicode": "e672",
"unicode_decimal": 58994
},
{
"icon_id": "24879595",
"name": "close",
"font_class": "close",
"unicode": "e673",
"unicode_decimal": 58995
},
{
"icon_id": "24879596",
"name": "help-filled",
"font_class": "help-filled",
"unicode": "e674",
"unicode_decimal": 58996
},
{
"icon_id": "24879597",
"name": "plus-filled",
"font_class": "paperplane-filled",
"unicode": "e675",
"unicode_decimal": 58997
},
{
"icon_id": "24879598",
"name": "plus",
"font_class": "plus",
"unicode": "e676",
"unicode_decimal": 58998
},
{
"icon_id": "24879599",
"name": "mic-filled",
"font_class": "mic-filled",
"unicode": "e677",
"unicode_decimal": 58999
},
{
"icon_id": "24879600",
"name": "image-filled",
"font_class": "image-filled",
"unicode": "e678",
"unicode_decimal": 59000
},
{
"icon_id": "24855900",
"name": "locked-filled",
"font_class": "locked-filled",
"unicode": "e668",
"unicode_decimal": 58984
},
{
"icon_id": "24855901",
"name": "info",
"font_class": "info",
"unicode": "e669",
"unicode_decimal": 58985
},
{
"icon_id": "24855903",
"name": "locked",
"font_class": "locked",
"unicode": "e66b",
"unicode_decimal": 58987
},
{
"icon_id": "24855884",
"name": "camera-filled",
"font_class": "camera-filled",
"unicode": "e658",
"unicode_decimal": 58968
},
{
"icon_id": "24855885",
"name": "chat-filled",
"font_class": "chat-filled",
"unicode": "e659",
"unicode_decimal": 58969
},
{
"icon_id": "24855886",
"name": "camera",
"font_class": "camera",
"unicode": "e65a",
"unicode_decimal": 58970
},
{
"icon_id": "24855887",
"name": "circle",
"font_class": "circle",
"unicode": "e65b",
"unicode_decimal": 58971
},
{
"icon_id": "24855888",
"name": "checkmarkempty",
"font_class": "checkmarkempty",
"unicode": "e65c",
"unicode_decimal": 58972
},
{
"icon_id": "24855889",
"name": "chat",
"font_class": "chat",
"unicode": "e65d",
"unicode_decimal": 58973
},
{
"icon_id": "24855890",
"name": "circle-filled",
"font_class": "circle-filled",
"unicode": "e65e",
"unicode_decimal": 58974
},
{
"icon_id": "24855891",
"name": "flag",
"font_class": "flag",
"unicode": "e65f",
"unicode_decimal": 58975
},
{
"icon_id": "24855892",
"name": "flag-filled",
"font_class": "flag-filled",
"unicode": "e660",
"unicode_decimal": 58976
},
{
"icon_id": "24855893",
"name": "gear-filled",
"font_class": "gear-filled",
"unicode": "e661",
"unicode_decimal": 58977
},
{
"icon_id": "24855894",
"name": "home",
"font_class": "home",
"unicode": "e662",
"unicode_decimal": 58978
},
{
"icon_id": "24855895",
"name": "home-filled",
"font_class": "home-filled",
"unicode": "e663",
"unicode_decimal": 58979
},
{
"icon_id": "24855896",
"name": "gear",
"font_class": "gear",
"unicode": "e664",
"unicode_decimal": 58980
},
{
"icon_id": "24855897",
"name": "smallcircle-filled",
"font_class": "smallcircle-filled",
"unicode": "e665",
"unicode_decimal": 58981
},
{
"icon_id": "24855898",
"name": "map-filled",
"font_class": "map-filled",
"unicode": "e666",
"unicode_decimal": 58982
},
{
"icon_id": "24855899",
"name": "map",
"font_class": "map",
"unicode": "e667",
"unicode_decimal": 58983
},
{
"icon_id": "24855825",
"name": "refresh-filled",
"font_class": "refresh-filled",
"unicode": "e656",
"unicode_decimal": 58966
},
{
"icon_id": "24855826",
"name": "refresh",
"font_class": "refresh",
"unicode": "e657",
"unicode_decimal": 58967
},
{
"icon_id": "24855808",
"name": "cloud-upload",
"font_class": "cloud-upload",
"unicode": "e645",
"unicode_decimal": 58949
},
{
"icon_id": "24855809",
"name": "cloud-download-filled",
"font_class": "cloud-download-filled",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "24855810",
"name": "cloud-download",
"font_class": "cloud-download",
"unicode": "e647",
"unicode_decimal": 58951
},
{
"icon_id": "24855811",
"name": "cloud-upload-filled",
"font_class": "cloud-upload-filled",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "24855813",
"name": "redo",
"font_class": "redo",
"unicode": "e64a",
"unicode_decimal": 58954
},
{
"icon_id": "24855814",
"name": "images-filled",
"font_class": "images-filled",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "24855815",
"name": "undo-filled",
"font_class": "undo-filled",
"unicode": "e64c",
"unicode_decimal": 58956
},
{
"icon_id": "24855816",
"name": "more",
"font_class": "more",
"unicode": "e64d",
"unicode_decimal": 58957
},
{
"icon_id": "24855817",
"name": "more-filled",
"font_class": "more-filled",
"unicode": "e64e",
"unicode_decimal": 58958
},
{
"icon_id": "24855818",
"name": "undo",
"font_class": "undo",
"unicode": "e64f",
"unicode_decimal": 58959
},
{
"icon_id": "24855819",
"name": "images",
"font_class": "images",
"unicode": "e650",
"unicode_decimal": 58960
},
{
"icon_id": "24855821",
"name": "paperclip",
"font_class": "paperclip",
"unicode": "e652",
"unicode_decimal": 58962
},
{
"icon_id": "24855822",
"name": "settings",
"font_class": "settings",
"unicode": "e653",
"unicode_decimal": 58963
},
{
"icon_id": "24855823",
"name": "search",
"font_class": "search",
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "24855824",
"name": "redo-filled",
"font_class": "redo-filled",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "24841702",
"name": "list",
"font_class": "list",
"unicode": "e644",
"unicode_decimal": 58948
},
{
"icon_id": "24841489",
"name": "mail-open-filled",
"font_class": "mail-open-filled",
"unicode": "e63a",
"unicode_decimal": 58938
},
{
"icon_id": "24841491",
"name": "hand-thumbsdown-filled",
"font_class": "hand-down-filled",
"unicode": "e63c",
"unicode_decimal": 58940
},
{
"icon_id": "24841492",
"name": "hand-thumbsdown",
"font_class": "hand-down",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "24841493",
"name": "hand-thumbsup-filled",
"font_class": "hand-up-filled",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "24841494",
"name": "hand-thumbsup",
"font_class": "hand-up",
"unicode": "e63f",
"unicode_decimal": 58943
},
{
"icon_id": "24841496",
"name": "heart-filled",
"font_class": "heart-filled",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "24841498",
"name": "mail-open",
"font_class": "mail-open",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "24841488",
"name": "heart",
"font_class": "heart",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "24839963",
"name": "loop",
"font_class": "loop",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "24839866",
"name": "pulldown",
"font_class": "pulldown",
"unicode": "e632",
"unicode_decimal": 58930
},
{
"icon_id": "24813798",
"name": "scan",
"font_class": "scan",
"unicode": "e62a",
"unicode_decimal": 58922
},
{
"icon_id": "24813786",
"name": "bars",
"font_class": "bars",
"unicode": "e627",
"unicode_decimal": 58919
},
{
"icon_id": "24813788",
"name": "cart-filled",
"font_class": "cart-filled",
"unicode": "e629",
"unicode_decimal": 58921
},
{
"icon_id": "24813790",
"name": "checkbox",
"font_class": "checkbox",
"unicode": "e62b",
"unicode_decimal": 58923
},
{
"icon_id": "24813791",
"name": "checkbox-filled",
"font_class": "checkbox-filled",
"unicode": "e62c",
"unicode_decimal": 58924
},
{
"icon_id": "24813794",
"name": "shop",
"font_class": "shop",
"unicode": "e62f",
"unicode_decimal": 58927
},
{
"icon_id": "24813795",
"name": "headphones",
"font_class": "headphones",
"unicode": "e630",
"unicode_decimal": 58928
},
{
"icon_id": "24813796",
"name": "cart",
"font_class": "cart",
"unicode": "e631",
"unicode_decimal": 58929
}
]
}
<template>
<!-- #ifdef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
<!-- #endif -->
</template>
<script>
import icons from './icons.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
domModule.addRule('fontFace', {
'fontFamily': "uniicons",
'src': "url('"+iconUrl+"')"
});
// #endif
/**
* Icons 图标
* @description 用于展示 icons 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number} size 图标大小
* @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: 'UniIcons',
emits:['click'],
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
customPrefix:{
type: String,
default: ''
}
},
data() {
return {
icons: icons.glyphs
}
},
computed:{
unicode(){
let code = this.icons.find(v=>v.font_class === this.type)
if(code){
return unescape(`%u${code.unicode}`)
}
return ''
},
iconSize(){
return getVal(this.size)
}
},
methods: {
_onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
@import './uniicons.css';
@font-face {
font-family: uniicons;
src: url('./uniicons.ttf') format('truetype');
}
/* #endif */
.uni-icons {
font-family: uniicons;
text-decoration: none;
text-align: center;
}
</style>
.uniui-color:before {
content: "\e6cf";
}
.uniui-wallet:before {
content: "\e6b1";
}
.uniui-settings-filled:before {
content: "\e6ce";
}
.uniui-auth-filled:before {
content: "\e6cc";
}
.uniui-shop-filled:before {
content: "\e6cd";
}
.uniui-staff-filled:before {
content: "\e6cb";
}
.uniui-vip-filled:before {
content: "\e6c6";
}
.uniui-plus-filled:before {
content: "\e6c7";
}
.uniui-folder-add-filled:before {
content: "\e6c8";
}
.uniui-color-filled:before {
content: "\e6c9";
}
.uniui-tune-filled:before {
content: "\e6ca";
}
.uniui-calendar-filled:before {
content: "\e6c0";
}
.uniui-notification-filled:before {
content: "\e6c1";
}
.uniui-wallet-filled:before {
content: "\e6c2";
}
.uniui-medal-filled:before {
content: "\e6c3";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-fire-filled:before {
content: "\e6c5";
}
.uniui-refreshempty:before {
content: "\e6bf";
}
.uniui-location-filled:before {
content: "\e6af";
}
.uniui-person-filled:before {
content: "\e69d";
}
.uniui-personadd-filled:before {
content: "\e698";
}
.uniui-back:before {
content: "\e6b9";
}
.uniui-forward:before {
content: "\e6ba";
}
.uniui-arrow-right:before {
content: "\e6bb";
}
.uniui-arrowthinright:before {
content: "\e6bb";
}
.uniui-arrow-left:before {
content: "\e6bc";
}
.uniui-arrowthinleft:before {
content: "\e6bc";
}
.uniui-arrow-up:before {
content: "\e6bd";
}
.uniui-arrowthinup:before {
content: "\e6bd";
}
.uniui-arrow-down:before {
content: "\e6be";
}
.uniui-arrowthindown:before {
content: "\e6be";
}
.uniui-bottom:before {
content: "\e6b8";
}
.uniui-arrowdown:before {
content: "\e6b8";
}
.uniui-right:before {
content: "\e6b5";
}
.uniui-arrowright:before {
content: "\e6b5";
}
.uniui-top:before {
content: "\e6b6";
}
.uniui-arrowup:before {
content: "\e6b6";
}
.uniui-left:before {
content: "\e6b7";
}
.uniui-arrowleft:before {
content: "\e6b7";
}
.uniui-eye:before {
content: "\e651";
}
.uniui-eye-filled:before {
content: "\e66a";
}
.uniui-eye-slash:before {
content: "\e6b3";
}
.uniui-eye-slash-filled:before {
content: "\e6b4";
}
.uniui-info-filled:before {
content: "\e649";
}
.uniui-reload:before {
content: "\e6b2";
}
.uniui-micoff-filled:before {
content: "\e6b0";
}
.uniui-map-pin-ellipse:before {
content: "\e6ac";
}
.uniui-map-pin:before {
content: "\e6ad";
}
.uniui-location:before {
content: "\e6ae";
}
.uniui-starhalf:before {
content: "\e683";
}
.uniui-star:before {
content: "\e688";
}
.uniui-star-filled:before {
content: "\e68f";
}
.uniui-calendar:before {
content: "\e6a0";
}
.uniui-fire:before {
content: "\e6a1";
}
.uniui-medal:before {
content: "\e6a2";
}
.uniui-font:before {
content: "\e6a3";
}
.uniui-gift:before {
content: "\e6a4";
}
.uniui-link:before {
content: "\e6a5";
}
.uniui-notification:before {
content: "\e6a6";
}
.uniui-staff:before {
content: "\e6a7";
}
.uniui-vip:before {
content: "\e6a8";
}
.uniui-folder-add:before {
content: "\e6a9";
}
.uniui-tune:before {
content: "\e6aa";
}
.uniui-auth:before {
content: "\e6ab";
}
.uniui-person:before {
content: "\e699";
}
.uniui-email-filled:before {
content: "\e69a";
}
.uniui-phone-filled:before {
content: "\e69b";
}
.uniui-phone:before {
content: "\e69c";
}
.uniui-email:before {
content: "\e69e";
}
.uniui-personadd:before {
content: "\e69f";
}
.uniui-chatboxes-filled:before {
content: "\e692";
}
.uniui-contact:before {
content: "\e693";
}
.uniui-chatbubble-filled:before {
content: "\e694";
}
.uniui-contact-filled:before {
content: "\e695";
}
.uniui-chatboxes:before {
content: "\e696";
}
.uniui-chatbubble:before {
content: "\e697";
}
.uniui-upload-filled:before {
content: "\e68e";
}
.uniui-upload:before {
content: "\e690";
}
.uniui-weixin:before {
content: "\e691";
}
.uniui-compose:before {
content: "\e67f";
}
.uniui-qq:before {
content: "\e680";
}
.uniui-download-filled:before {
content: "\e681";
}
.uniui-pyq:before {
content: "\e682";
}
.uniui-sound:before {
content: "\e684";
}
.uniui-trash-filled:before {
content: "\e685";
}
.uniui-sound-filled:before {
content: "\e686";
}
.uniui-trash:before {
content: "\e687";
}
.uniui-videocam-filled:before {
content: "\e689";
}
.uniui-spinner-cycle:before {
content: "\e68a";
}
.uniui-weibo:before {
content: "\e68b";
}
.uniui-videocam:before {
content: "\e68c";
}
.uniui-download:before {
content: "\e68d";
}
.uniui-help:before {
content: "\e679";
}
.uniui-navigate-filled:before {
content: "\e67a";
}
.uniui-plusempty:before {
content: "\e67b";
}
.uniui-smallcircle:before {
content: "\e67c";
}
.uniui-minus-filled:before {
content: "\e67d";
}
.uniui-micoff:before {
content: "\e67e";
}
.uniui-closeempty:before {
content: "\e66c";
}
.uniui-clear:before {
content: "\e66d";
}
.uniui-navigate:before {
content: "\e66e";
}
.uniui-minus:before {
content: "\e66f";
}
.uniui-image:before {
content: "\e670";
}
.uniui-mic:before {
content: "\e671";
}
.uniui-paperplane:before {
content: "\e672";
}
.uniui-close:before {
content: "\e673";
}
.uniui-help-filled:before {
content: "\e674";
}
.uniui-paperplane-filled:before {
content: "\e675";
}
.uniui-plus:before {
content: "\e676";
}
.uniui-mic-filled:before {
content: "\e677";
}
.uniui-image-filled:before {
content: "\e678";
}
.uniui-locked-filled:before {
content: "\e668";
}
.uniui-info:before {
content: "\e669";
}
.uniui-locked:before {
content: "\e66b";
}
.uniui-camera-filled:before {
content: "\e658";
}
.uniui-chat-filled:before {
content: "\e659";
}
.uniui-camera:before {
content: "\e65a";
}
.uniui-circle:before {
content: "\e65b";
}
.uniui-checkmarkempty:before {
content: "\e65c";
}
.uniui-chat:before {
content: "\e65d";
}
.uniui-circle-filled:before {
content: "\e65e";
}
.uniui-flag:before {
content: "\e65f";
}
.uniui-flag-filled:before {
content: "\e660";
}
.uniui-gear-filled:before {
content: "\e661";
}
.uniui-home:before {
content: "\e662";
}
.uniui-home-filled:before {
content: "\e663";
}
.uniui-gear:before {
content: "\e664";
}
.uniui-smallcircle-filled:before {
content: "\e665";
}
.uniui-map-filled:before {
content: "\e666";
}
.uniui-map:before {
content: "\e667";
}
.uniui-refresh-filled:before {
content: "\e656";
}
.uniui-refresh:before {
content: "\e657";
}
.uniui-cloud-upload:before {
content: "\e645";
}
.uniui-cloud-download-filled:before {
content: "\e646";
}
.uniui-cloud-download:before {
content: "\e647";
}
.uniui-cloud-upload-filled:before {
content: "\e648";
}
.uniui-redo:before {
content: "\e64a";
}
.uniui-images-filled:before {
content: "\e64b";
}
.uniui-undo-filled:before {
content: "\e64c";
}
.uniui-more:before {
content: "\e64d";
}
.uniui-more-filled:before {
content: "\e64e";
}
.uniui-undo:before {
content: "\e64f";
}
.uniui-images:before {
content: "\e650";
}
.uniui-paperclip:before {
content: "\e652";
}
.uniui-settings:before {
content: "\e653";
}
.uniui-search:before {
content: "\e654";
}
.uniui-redo-filled:before {
content: "\e655";
}
.uniui-list:before {
content: "\e644";
}
.uniui-mail-open-filled:before {
content: "\e63a";
}
.uniui-hand-down-filled:before {
content: "\e63c";
}
.uniui-hand-down:before {
content: "\e63d";
}
.uniui-hand-up-filled:before {
content: "\e63e";
}
.uniui-hand-up:before {
content: "\e63f";
}
.uniui-heart-filled:before {
content: "\e641";
}
.uniui-mail-open:before {
content: "\e643";
}
.uniui-heart:before {
content: "\e639";
}
.uniui-loop:before {
content: "\e633";
}
.uniui-pulldown:before {
content: "\e632";
}
.uniui-scan:before {
content: "\e62a";
}
.uniui-bars:before {
content: "\e627";
}
.uniui-cart-filled:before {
content: "\e629";
}
.uniui-checkbox:before {
content: "\e62b";
}
.uniui-checkbox-filled:before {
content: "\e62c";
}
.uniui-shop:before {
content: "\e62f";
}
.uniui-headphones:before {
content: "\e630";
}
.uniui-cart:before {
content: "\e631";
}
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "1.3.5",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",
"uniui",
"icon",
"图标"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.2.14"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
## Icons 图标
> **组件名:uni-icons**
> 代码块: `uIcons`
用于展示 icons 图标 。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
## 1.0.3(2022-01-21)
- 优化 组件示例
## 1.0.2(2021-11-22)
- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
## 1.0.1(2021-11-22)
- 修复 vue3中scss语法兼容问题
## 1.0.0(2021-11-18)
- init
@import './styles/index.scss';
{
"id": "uni-scss",
"displayName": "uni-scss 辅助样式",
"version": "1.0.3",
"description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。",
"keywords": [
"uni-scss",
"uni-ui",
"辅助样式"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"JS SDK",
"通用 SDK"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
`uni-sass``uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
@import './setting/_variables.scss';
@import './setting/_border.scss';
@import './setting/_color.scss';
@import './setting/_space.scss';
@import './setting/_radius.scss';
@import './setting/_text.scss';
@import './setting/_styles.scss';
.uni-border {
border: 1px $uni-border-1 solid;
}
\ No newline at end of file
// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐
// @mixin get-styles($k,$c) {
// @if $k == size or $k == weight{
// font-#{$k}:#{$c}
// }@else{
// #{$k}:#{$c}
// }
// }
$uni-ui-color:(
// 主色
primary: $uni-primary,
primary-disable: $uni-primary-disable,
primary-light: $uni-primary-light,
// 辅助色
success: $uni-success,
success-disable: $uni-success-disable,
success-light: $uni-success-light,
warning: $uni-warning,
warning-disable: $uni-warning-disable,
warning-light: $uni-warning-light,
error: $uni-error,
error-disable: $uni-error-disable,
error-light: $uni-error-light,
info: $uni-info,
info-disable: $uni-info-disable,
info-light: $uni-info-light,
// 中性色
main-color: $uni-main-color,
base-color: $uni-base-color,
secondary-color: $uni-secondary-color,
extra-color: $uni-extra-color,
// 背景色
bg-color: $uni-bg-color,
// 边框颜色
border-1: $uni-border-1,
border-2: $uni-border-2,
border-3: $uni-border-3,
border-4: $uni-border-4,
// 黑色
black:$uni-black,
// 白色
white:$uni-white,
// 透明
transparent:$uni-transparent
) !default;
@each $key, $child in $uni-ui-color {
.uni-#{"" + $key} {
color: $child;
}
.uni-#{"" + $key}-bg {
background-color: $child;
}
}
.uni-shadow-sm {
box-shadow: $uni-shadow-sm;
}
.uni-shadow-base {
box-shadow: $uni-shadow-base;
}
.uni-shadow-lg {
box-shadow: $uni-shadow-lg;
}
.uni-mask {
background-color:$uni-mask;
}
@mixin radius($r,$d:null ,$important: false){
$radius-value:map-get($uni-radius, $r) if($important, !important, null);
// Key exists within the $uni-radius variable
@if (map-has-key($uni-radius, $r) and $d){
@if $d == t {
border-top-left-radius:$radius-value;
border-top-right-radius:$radius-value;
}@else if $d == r {
border-top-right-radius:$radius-value;
border-bottom-right-radius:$radius-value;
}@else if $d == b {
border-bottom-left-radius:$radius-value;
border-bottom-right-radius:$radius-value;
}@else if $d == l {
border-top-left-radius:$radius-value;
border-bottom-left-radius:$radius-value;
}@else if $d == tl {
border-top-left-radius:$radius-value;
}@else if $d == tr {
border-top-right-radius:$radius-value;
}@else if $d == br {
border-bottom-right-radius:$radius-value;
}@else if $d == bl {
border-bottom-left-radius:$radius-value;
}
}@else{
border-radius:$radius-value;
}
}
@each $key, $child in $uni-radius {
@if($key){
.uni-radius-#{"" + $key} {
@include radius($key)
}
}@else{
.uni-radius {
@include radius($key)
}
}
}
@each $direction in t, r, b, l,tl, tr, br, bl {
@each $key, $child in $uni-radius {
@if($key){
.uni-radius-#{"" + $direction}-#{"" + $key} {
@include radius($key,$direction,false)
}
}@else{
.uni-radius-#{$direction} {
@include radius($key,$direction,false)
}
}
}
}
@mixin fn($space,$direction,$size,$n) {
@if $n {
#{$space}-#{$direction}: #{$size*$uni-space-root}px
} @else {
#{$space}-#{$direction}: #{-$size*$uni-space-root}px
}
}
@mixin get-styles($direction,$i,$space,$n){
@if $direction == t {
@include fn($space, top,$i,$n);
}
@if $direction == r {
@include fn($space, right,$i,$n);
}
@if $direction == b {
@include fn($space, bottom,$i,$n);
}
@if $direction == l {
@include fn($space, left,$i,$n);
}
@if $direction == x {
@include fn($space, left,$i,$n);
@include fn($space, right,$i,$n);
}
@if $direction == y {
@include fn($space, top,$i,$n);
@include fn($space, bottom,$i,$n);
}
@if $direction == a {
@if $n {
#{$space}:#{$i*$uni-space-root}px;
} @else {
#{$space}:#{-$i*$uni-space-root}px;
}
}
}
@each $orientation in m,p {
$space: margin;
@if $orientation == m {
$space: margin;
} @else {
$space: padding;
}
@for $i from 0 through 16 {
@each $direction in t, r, b, l, x, y, a {
.uni-#{$orientation}#{$direction}-#{$i} {
@include get-styles($direction,$i,$space,true);
}
.uni-#{$orientation}#{$direction}-n#{$i} {
@include get-styles($direction,$i,$space,false);
}
}
}
}
\ No newline at end of file
/* #ifndef APP-NVUE */
$-color-white:#fff;
$-color-black:#000;
@mixin base-style($color) {
color: #fff;
background-color: $color;
border-color: mix($-color-black, $color, 8%);
&:not([hover-class]):active {
background: mix($-color-black, $color, 10%);
border-color: mix($-color-black, $color, 20%);
color: $-color-white;
outline: none;
}
}
@mixin is-color($color) {
@include base-style($color);
&[loading] {
@include base-style($color);
&::before {
margin-right:5px;
}
}
&[disabled] {
&,
&[loading],
&:not([hover-class]):active {
color: $-color-white;
border-color: mix(darken($color,10%), $-color-white);
background-color: mix($color, $-color-white);
}
}
}
@mixin base-plain-style($color) {
color:$color;
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 70%);
&:not([hover-class]):active {
background: mix($-color-white, $color, 80%);
color: $color;
outline: none;
border-color: mix($-color-white, $color, 50%);
}
}
@mixin is-plain($color){
&[plain] {
@include base-plain-style($color);
&[loading] {
@include base-plain-style($color);
&::before {
margin-right:5px;
}
}
&[disabled] {
&,
&:active {
color: mix($-color-white, $color, 40%);
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 80%);
}
}
}
}
.uni-btn {
margin: 5px;
color: #393939;
border:1px solid #ccc;
font-size: 16px;
font-weight: 200;
background-color: #F9F9F9;
// TODO 暂时处理边框隐藏一边的问题
overflow: visible;
&::after{
border: none;
}
&:not([type]),&[type=default] {
color: #999;
&[loading] {
background: none;
&::before {
margin-right:5px;
}
}
&[disabled]{
color: mix($-color-white, #999, 60%);
&,
&[loading],
&:active {
color: mix($-color-white, #999, 60%);
background-color: mix($-color-white,$-color-black , 98%);
border-color: mix($-color-white, #999, 85%);
}
}
&[plain] {
color: #999;
background: none;
border-color: $uni-border-1;
&:not([hover-class]):active {
background: none;
color: mix($-color-white, $-color-black, 80%);
border-color: mix($-color-white, $-color-black, 90%);
outline: none;
}
&[disabled]{
&,
&[loading],
&:active {
background: none;
color: mix($-color-white, #999, 60%);
border-color: mix($-color-white, #999, 85%);
}
}
}
}
&:not([hover-class]):active {
color: mix($-color-white, $-color-black, 50%);
}
&[size=mini] {
font-size: 16px;
font-weight: 200;
border-radius: 8px;
}
&.uni-btn-small {
font-size: 14px;
}
&.uni-btn-mini {
font-size: 12px;
}
&.uni-btn-radius {
border-radius: 999px;
}
&[type=primary] {
@include is-color($uni-primary);
@include is-plain($uni-primary)
}
&[type=success] {
@include is-color($uni-success);
@include is-plain($uni-success)
}
&[type=error] {
@include is-color($uni-error);
@include is-plain($uni-error)
}
&[type=warning] {
@include is-color($uni-warning);
@include is-plain($uni-warning)
}
&[type=info] {
@include is-color($uni-info);
@include is-plain($uni-info)
}
}
/* #endif */
@mixin get-styles($k,$c) {
@if $k == size or $k == weight{
font-#{$k}:#{$c}
}@else{
#{$k}:#{$c}
}
}
@each $key, $child in $uni-headings {
/* #ifndef APP-NVUE */
.uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k,$c)
}
}
/* #endif */
/* #ifdef APP-NVUE */
.container .uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k,$c)
}
}
/* #endif */
}
// @use "sass:math";
@import '../tools/functions.scss';
// 间距基础倍数
$uni-space-root: 2 !default;
// 边框半径默认值
$uni-radius-root:5px !default;
$uni-radius: () !default;
// 边框半径断点
$uni-radius: map-deep-merge(
(
0: 0,
// TODO 当前版本暂时不支持 sm 属性
// 'sm': math.div($uni-radius-root, 2),
null: $uni-radius-root,
'lg': $uni-radius-root * 2,
'xl': $uni-radius-root * 6,
'pill': 9999px,
'circle': 50%
),
$uni-radius
);
// 字体家族
$body-font-family: 'Roboto', sans-serif !default;
// 文本
$heading-font-family: $body-font-family !default;
$uni-headings: () !default;
$letterSpacing: -0.01562em;
$uni-headings: map-deep-merge(
(
'h1': (
size: 32px,
weight: 300,
line-height: 50px,
// letter-spacing:-0.01562em
),
'h2': (
size: 28px,
weight: 300,
line-height: 40px,
// letter-spacing: -0.00833em
),
'h3': (
size: 24px,
weight: 400,
line-height: 32px,
// letter-spacing: normal
),
'h4': (
size: 20px,
weight: 400,
line-height: 30px,
// letter-spacing: 0.00735em
),
'h5': (
size: 16px,
weight: 400,
line-height: 24px,
// letter-spacing: normal
),
'h6': (
size: 14px,
weight: 500,
line-height: 18px,
// letter-spacing: 0.0125em
),
'subtitle': (
size: 12px,
weight: 400,
line-height: 20px,
// letter-spacing: 0.00937em
),
'body': (
font-size: 14px,
font-weight: 400,
line-height: 22px,
// letter-spacing: 0.03125em
),
'caption': (
'size': 12px,
'weight': 400,
'line-height': 20px,
// 'letter-spacing': 0.03333em,
// 'text-transform': false
)
),
$uni-headings
);
// 主色
$uni-primary: #2979ff !default;
$uni-primary-disable:lighten($uni-primary,20%) !default;
$uni-primary-light: lighten($uni-primary,25%) !default;
// 辅助色
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
$uni-success: #18bc37 !default;
$uni-success-disable:lighten($uni-success,20%) !default;
$uni-success-light: lighten($uni-success,25%) !default;
$uni-warning: #f3a73f !default;
$uni-warning-disable:lighten($uni-warning,20%) !default;
$uni-warning-light: lighten($uni-warning,25%) !default;
$uni-error: #e43d33 !default;
$uni-error-disable:lighten($uni-error,20%) !default;
$uni-error-light: lighten($uni-error,25%) !default;
$uni-info: #8f939c !default;
$uni-info-disable:lighten($uni-info,20%) !default;
$uni-info-light: lighten($uni-info,25%) !default;
// 中性色
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
$uni-main-color: #3a3a3a !default; // 主要文字
$uni-base-color: #6a6a6a !default; // 常规文字
$uni-secondary-color: #909399 !default; // 次要文字
$uni-extra-color: #c7c7c7 !default; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0 !default;
$uni-border-2: #EDEDED !default;
$uni-border-3: #DCDCDC !default;
$uni-border-4: #B9B9B9 !default;
// 常规色
$uni-black: #000000 !default;
$uni-white: #ffffff !default;
$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
// 背景色
$uni-bg-color: #f7f7f7 !default;
/* 水平间距 */
$uni-spacing-sm: 8px !default;
$uni-spacing-base: 15px !default;
$uni-spacing-lg: 30px !default;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;
// 合并 map
@function map-deep-merge($parent-map, $child-map){
$result: $parent-map;
@each $key, $child in $child-map {
$parent-has-key: map-has-key($result, $key);
$parent-value: map-get($result, $key);
$parent-type: type-of($parent-value);
$child-type: type-of($child);
$parent-is-map: $parent-type == map;
$child-is-map: $child-type == map;
@if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){
$result: map-merge($result, ( $key: $child ));
}@else {
$result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) ));
}
}
@return $result;
};
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root:5px;
// 主色
$uni-primary: #2979ff;
// 辅助色
$uni-success: #4cd964;
// 警告色
$uni-warning: #f0ad4e;
// 错误色
$uni-error: #dd524d;
// 描述色
$uni-info: #909399;
// 中性色
$uni-main-color: #303133;
$uni-base-color: #606266;
$uni-secondary-color: #909399;
$uni-extra-color: #C0C4CC;
// 背景色
$uni-bg-color: #f5f5f5;
// 边框颜色
$uni-border-1: #DCDFE6;
$uni-border-2: #E4E7ED;
$uni-border-3: #EBEEF5;
$uni-border-4: #F2F6FC;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba($color: #000000, $alpha: 0);
@import './styles/setting/_variables.scss';
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root:5px;
// 主色
$uni-primary: #2979ff;
$uni-primary-disable:mix(#fff,$uni-primary,50%);
$uni-primary-light: mix(#fff,$uni-primary,80%);
// 辅助色
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
$uni-success: #18bc37;
$uni-success-disable:mix(#fff,$uni-success,50%);
$uni-success-light: mix(#fff,$uni-success,80%);
$uni-warning: #f3a73f;
$uni-warning-disable:mix(#fff,$uni-warning,50%);
$uni-warning-light: mix(#fff,$uni-warning,80%);
$uni-error: #e43d33;
$uni-error-disable:mix(#fff,$uni-error,50%);
$uni-error-light: mix(#fff,$uni-error,80%);
$uni-info: #8f939c;
$uni-info-disable:mix(#fff,$uni-info,50%);
$uni-info-light: mix(#fff,$uni-info,80%);
// 中性色
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
$uni-main-color: #3a3a3a; // 主要文字
$uni-base-color: #6a6a6a; // 常规文字
$uni-secondary-color: #909399; // 次要文字
$uni-extra-color: #c7c7c7; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0;
$uni-border-2: #EDEDED;
$uni-border-3: #DCDCDC;
$uni-border-4: #B9B9B9;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba($color: #000000, $alpha: 0);
// 背景色
$uni-bg-color: #f7f7f7;
/* 水平间距 */
$uni-spacing-sm: 8px;
$uni-spacing-base: 15px;
$uni-spacing-lg: 30px;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5);
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2);
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5);
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4);
// 计算两点之间距离
const distance = (la1, lo1, la2, lo2) => {
let La1 = la1 * Math.PI / 180.0;
let La2 = la2 * Math.PI / 180.0;
let La3 = La1 - La2;
let Lb3 = lo1 * Math.PI / 180.0 - lo2 * Math.PI / 180.0;
let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(La3 / 2), 2) + Math.cos(La1) * Math.cos(La2) * Math.pow(Math.sin(Lb3 / 2), 2)));
s = s * 6378.137;
s = Math.round(s * 10000) / 10000;
s = s.toFixed(2);
return s; //单位千米
}
//逆地址解析 坐标经纬度转地址描述
const reverseGeocoder = () => {
return new Promise((reslove, reject) => {
// #ifdef H5
H5ReverseGeocoder(reslove, reject) // H5适配
// #endif
// #ifdef MP
WXReverseGeocoder(reslove, reject) //微信地址逆解析
// #endif
})
}
const H5ReverseGeocoder = (reslove, reject) => {
let { userLocation, cacheUserLocation, MapIns} = getApp().globalData
let { latitude, longitude } = userLocation //每次通过JSSDK获取经纬度后维护的当前最新位置
const oldLatitude = cacheUserLocation.latitude //已缓存纬度
const oldLongitude = cacheUserLocation.longitude // 已缓存经度
if(!oldLatitude || (oldLatitude && +distance(latitude, longitude, oldLatitude, oldLongitude) > 0.015 )){ //Distance()方法返回值为千米, 15米内使用缓存位置
MapIns.plugin('AMap.Geocoder', function() {
const geocoder = new MapIns.Geocoder()
const lnglat = [longitude, latitude] // todo经纬度顺序固定
geocoder.getAddress(lnglat, function(status, result) {
if (status === 'complete' && result.info === 'OK') {
// result为对应的地理位置详细信息
const regeocode = result.regeocode
const addressComponent = regeocode.addressComponent
let markers = [{
latitude: latitude,
longitude: longitude,
}]
let textData = {
desc: regeocode.formattedAddress,
province: addressComponent.province,
city: addressComponent.city,
district: addressComponent.district,
street: addressComponent.street + addressComponent.streetNumber,
}
const addressInfo = {markers, textData, latitude, longitude} //整理数据结构
getApp().globalData.cacheUserLocation = addressInfo //缓存位置信息
reslove(addressInfo)
} else {
const text = result === 'INVALID_USER_DOMAIN' ? '地址解析失败,当前IP未在高德域名白名单' : result
uni.showToast({
title: text,
icon: 'none',
duration: 3000
});
}
})
})
} else {
reslove(cacheUserLocation)
}
}
const WXReverseGeocoder = (reslove, reject) => {
let {MapIns} = getApp().globalData
MapIns.getRegeo({
iconWidth: 20,
iconHeight: 30,
success: (data) => {
const res = data[0]
let addressComponent = res.regeocodeData.addressComponent
let markers = [{
id: res.id,
latitude: res.latitude,
longitude: res.longitude,
iconPath: res.iconPath,
width: res.width,
height: res.height
}]
let textData = {
name: res.name,
desc: res.desc,
province: addressComponent.province,
city: addressComponent.city.length ? addressComponent.city : '',
district: addressComponent.district,
siteName: res.regeocodeData.aois.length ? res.regeocodeData.aois[0].name : res.name
}
//整理数据结构
reslove({
markers,
textData,
latitude: res.latitude,
longitude: res.longitude,
})
},
fail: (err) => {
reject(err)
}
})
}
//H5获取定位经纬度 注:PC上使用 Chrome 浏览器的时候,位置信息是连接谷歌服务器获取的,国内用户可能获取位置信息失败。
const AMapGetLocation = () => {
return new Promise((reslove, reject) => {
let {MapIns} = getApp().globalData
MapIns.plugin('AMap.Geolocation', function() {
const geolocation = new MapIns.Geolocation({
enableHighAccuracy: true, // 是否使用高精度定位,默认:true
timeout: 4000, // 设置定位超时时间,默认:无穷大
})
geolocation.getCurrentPosition(function(status,result){
console.log('高德获取经纬度:', result)
if(status=='complete' && result.info === 'SUCCESS'){ //result是具体的定位信息
const {lat, lng} = result.position
reslove({latitude: lat, longitude: lng})
} else { // 定位出错
uni.showToast({
title: result.message,
icon: 'none',
duration: 3000
});
}
});
})
})
}
let AMap = {
reverseGeocoder, //高德地图Functions API
AMapGetLocation
}
export default AMap
// 计算两点之间距离
const distance = (la1, lo1, la2, lo2) => {
let La1 = la1 * Math.PI / 180.0;
let La2 = la2 * Math.PI / 180.0;
let La3 = La1 - La2;
let Lb3 = lo1 * Math.PI / 180.0 - lo2 * Math.PI / 180.0;
let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(La3 / 2), 2) + Math.cos(La1) * Math.cos(La2) * Math.pow(Math.sin(Lb3 / 2), 2)));
s = s * 6378.137;
s = Math.round(s * 10000) / 10000;
s = s.toFixed(2);
return s; //单位千米
}
//逆地址解析 坐标经纬度转地址描述
const reverseGeocoder = () => {
return new Promise((reslove, reject) => {
// #ifdef H5
H5ReverseGeocoder(reslove, reject) // H5适配
// #endif
// #ifdef MP
WXReverseGeocoder(reslove, reject) //微信地址逆解析
// #endif
})
}
const H5ReverseGeocoder = (reslove, reject) => {
let { userLocation, cacheUserLocation, MapIns} = getApp().globalData
let { latitude, longitude } = userLocation //每次通过JSSDK获取经纬度后维护的当前最新位置
const oldLatitude = cacheUserLocation.latitude //已缓存纬度
const oldLongitude = cacheUserLocation.longitude // 已缓存经度
if(!oldLatitude || (oldLatitude && +distance(latitude, longitude, oldLatitude, oldLongitude) > 0.015 )){ //Distance()方法返回值为千米, 15米内使用缓存位置
const myGeo = new MapIns.Geocoder(); // 创建地理编码实例
const point = new MapIns.Point(longitude, latitude) //转换当前坐标点
myGeo.getLocation(point, function(result){ // 根据坐标得到地址描述, result为对应的地理位置详细信息
if (result){
const addressComponent = result.addressComponents
let markers = [{
latitude: latitude,
longitude: longitude,
}]
let textData = {
desc: result.address,
province: addressComponent.province,
city: addressComponent.city,
district: addressComponent.district,
street: addressComponent.street + addressComponent.streetNumber,
}
const addressInfo = {markers, textData, latitude, longitude} //整理数据结构
getApp().globalData.cacheUserLocation = addressInfo //缓存位置信息
reslove(addressInfo)
}
});
} else {
reslove(cacheUserLocation)
}
}
const WXReverseGeocoder = (reslove, reject) => {
let {MapIns} = getApp().globalData
MapIns.regeocoding({
iconWidth: 20,
iconHeight: 30,
success: (data) => {
const res = data.wxMarkerData[0]
let addressComponent = data.originalData.result.addressComponent
let markers = [{
id: res.id,
latitude: res.latitude,
longitude: res.longitude,
iconPath: res.iconPath,
width: res.width || 20,
height: res.height || 30
}]
let textData = {
name: res.address || res.desc,
desc: res.desc,
province: addressComponent.province,
city: addressComponent.city,
district: addressComponent.district,
siteName: res.address || res.desc
}
//整理数据结构
reslove({
markers,
textData,
latitude: res.latitude,
longitude: res.longitude,
})
},
fail: (err) => {
reject(err)
}
})
}
//H5获取定位经纬度 注:PC上使用 Chrome 浏览器的时候,位置信息是连接谷歌服务器获取的,国内用户可能获取位置信息失败。
const BMapGetLocation = () => {
return new Promise((reslove, reject) => {
let {MapIns} = getApp().globalData
const geolocation = new MapIns.Geolocation();
geolocation.enableSDKLocation(); //开启SDK辅助定位
geolocation.getCurrentPosition(function(res){
const errCode = {
6: '没有权限,定位被拒绝',
2: '定位不可用',
8: '定位超时',
}
const status = this.getStatus()
if(status === 0){
reslove({latitude: res.latitude, longitude: res.longitude})
} else {
uni.showToast({
title: errCode[status] || res,
icon: 'none',
duration: 3000
});
}
})
})
}
let BMap = {
reverseGeocoder, //高德地图Functions API
BMapGetLocation
}
export default BMap
function AMapWX(a){this.key=a.key;this.requestConfig={key:a.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"};this.MeRequestConfig={key:a.key,serviceName:"https://restapi.amap.com/rest/me"}}
AMapWX.prototype.getWxLocation=function(a,b){wx.getLocation({type:"gcj02",success:function(c){c=c.longitude+","+c.latitude;wx.setStorage({key:"userLocation",data:c});b(c)},fail:function(c){wx.getStorage({key:"userLocation",success:function(d){d.data&&b(d.data)}});a.fail({errCode:"0",errMsg:c.errMsg||""})}})};
AMapWX.prototype.getMEKeywordsSearch=function(a){if(!a.options)return a.fail({errCode:"0",errMsg:"\u7f3a\u5c11\u5fc5\u8981\u53c2\u6570"});var b=a.options,c=this.MeRequestConfig,d={key:c.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"};b.layerId&&(d.layerId=b.layerId);b.keywords&&(d.keywords=b.keywords);b.city&&(d.city=b.city);b.filter&&(d.filter=b.filter);b.sortrule&&(d.sortrule=b.sortrule);b.pageNum&&(d.pageNum=b.pageNum);b.pageSize&&(d.pageSize=b.pageSize);b.sig&&(d.sig=
b.sig);wx.request({url:c.serviceName+"/cpoint/datasearch/local",data:d,method:"GET",header:{"content-type":"application/json"},success:function(e){(e=e.data)&&e.status&&"1"===e.status&&0===e.code?a.success(e.data):a.fail({errCode:"0",errMsg:e})},fail:function(e){a.fail({errCode:"0",errMsg:e.errMsg||""})}})};
AMapWX.prototype.getMEIdSearch=function(a){if(!a.options)return a.fail({errCode:"0",errMsg:"\u7f3a\u5c11\u5fc5\u8981\u53c2\u6570"});var b=a.options,c=this.MeRequestConfig,d={key:c.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"};b.layerId&&(d.layerId=b.layerId);b.id&&(d.id=b.id);b.sig&&(d.sig=b.sig);wx.request({url:c.serviceName+"/cpoint/datasearch/id",data:d,method:"GET",header:{"content-type":"application/json"},success:function(e){(e=e.data)&&e.status&&"1"===e.status&&
0===e.code?a.success(e.data):a.fail({errCode:"0",errMsg:e})},fail:function(e){a.fail({errCode:"0",errMsg:e.errMsg||""})}})};
AMapWX.prototype.getMEPolygonSearch=function(a){if(!a.options)return a.fail({errCode:"0",errMsg:"\u7f3a\u5c11\u5fc5\u8981\u53c2\u6570"});var b=a.options,c=this.MeRequestConfig,d={key:c.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"};b.layerId&&(d.layerId=b.layerId);b.keywords&&(d.keywords=b.keywords);b.polygon&&(d.polygon=b.polygon);b.filter&&(d.filter=b.filter);b.sortrule&&(d.sortrule=b.sortrule);b.pageNum&&(d.pageNum=b.pageNum);b.pageSize&&(d.pageSize=b.pageSize);
b.sig&&(d.sig=b.sig);wx.request({url:c.serviceName+"/cpoint/datasearch/polygon",data:d,method:"GET",header:{"content-type":"application/json"},success:function(e){(e=e.data)&&e.status&&"1"===e.status&&0===e.code?a.success(e.data):a.fail({errCode:"0",errMsg:e})},fail:function(e){a.fail({errCode:"0",errMsg:e.errMsg||""})}})};
AMapWX.prototype.getMEaroundSearch=function(a){if(!a.options)return a.fail({errCode:"0",errMsg:"\u7f3a\u5c11\u5fc5\u8981\u53c2\u6570"});var b=a.options,c=this.MeRequestConfig,d={key:c.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"};b.layerId&&(d.layerId=b.layerId);b.keywords&&(d.keywords=b.keywords);b.center&&(d.center=b.center);b.radius&&(d.radius=b.radius);b.filter&&(d.filter=b.filter);b.sortrule&&(d.sortrule=b.sortrule);b.pageNum&&(d.pageNum=b.pageNum);b.pageSize&&
(d.pageSize=b.pageSize);b.sig&&(d.sig=b.sig);wx.request({url:c.serviceName+"/cpoint/datasearch/around",data:d,method:"GET",header:{"content-type":"application/json"},success:function(e){(e=e.data)&&e.status&&"1"===e.status&&0===e.code?a.success(e.data):a.fail({errCode:"0",errMsg:e})},fail:function(e){a.fail({errCode:"0",errMsg:e.errMsg||""})}})};
AMapWX.prototype.getGeo=function(a){var b=this.requestConfig,c=a.options;b={key:this.key,extensions:"all",s:b.s,platform:b.platform,appname:this.key,sdkversion:b.sdkversion,logversion:b.logversion};c.address&&(b.address=c.address);c.city&&(b.city=c.city);c.batch&&(b.batch=c.batch);c.sig&&(b.sig=c.sig);wx.request({url:"https://restapi.amap.com/v3/geocode/geo",data:b,method:"GET",header:{"content-type":"application/json"},success:function(d){(d=d.data)&&d.status&&"1"===d.status?a.success(d):a.fail({errCode:"0",
errMsg:d})},fail:function(d){a.fail({errCode:"0",errMsg:d.errMsg||""})}})};
AMapWX.prototype.getRegeo=function(a){function b(d){var e=c.requestConfig;wx.request({url:"https://restapi.amap.com/v3/geocode/regeo",data:{key:c.key,location:d,extensions:"all",s:e.s,platform:e.platform,appname:c.key,sdkversion:e.sdkversion,logversion:e.logversion},method:"GET",header:{"content-type":"application/json"},success:function(g){if(g.data.status&&"1"==g.data.status){g=g.data.regeocode;var h=g.addressComponent,f=[],k=g.roads[0].name+"\u9644\u8fd1",m=d.split(",")[0],n=d.split(",")[1];if(g.pois&&
g.pois[0]){k=g.pois[0].name+"\u9644\u8fd1";var l=g.pois[0].location;l&&(m=parseFloat(l.split(",")[0]),n=parseFloat(l.split(",")[1]))}h.provice&&f.push(h.provice);h.city&&f.push(h.city);h.district&&f.push(h.district);h.streetNumber&&h.streetNumber.street&&h.streetNumber.number?(f.push(h.streetNumber.street),f.push(h.streetNumber.number)):f.push(g.roads[0].name);f=f.join("");a.success([{iconPath:a.iconPath,width:a.iconWidth,height:a.iconHeight,name:f,desc:k,longitude:m,latitude:n,id:0,regeocodeData:g}])}else a.fail({errCode:g.data.infocode,
errMsg:g.data.info})},fail:function(g){a.fail({errCode:"0",errMsg:g.errMsg||""})}})}var c=this;a.location?b(a.location):c.getWxLocation(a,function(d){b(d)})};
AMapWX.prototype.getWeather=function(a){function b(g){var h="base";a.type&&"forecast"==a.type&&(h="all");wx.request({url:"https://restapi.amap.com/v3/weather/weatherInfo",data:{key:d.key,city:g,extensions:h,s:e.s,platform:e.platform,appname:d.key,sdkversion:e.sdkversion,logversion:e.logversion},method:"GET",header:{"content-type":"application/json"},success:function(f){if(f.data.status&&"1"==f.data.status)if(f.data.lives){if((f=f.data.lives)&&0<f.length){f=f[0];var k={city:{text:"\u57ce\u5e02",data:f.city},
weather:{text:"\u5929\u6c14",data:f.weather},temperature:{text:"\u6e29\u5ea6",data:f.temperature},winddirection:{text:"\u98ce\u5411",data:f.winddirection+"\u98ce"},windpower:{text:"\u98ce\u529b",data:f.windpower+"\u7ea7"},humidity:{text:"\u6e7f\u5ea6",data:f.humidity+"%"}};k.liveData=f;a.success(k)}}else f.data.forecasts&&f.data.forecasts[0]&&a.success({forecast:f.data.forecasts[0]});else a.fail({errCode:f.data.infocode,errMsg:f.data.info})},fail:function(f){a.fail({errCode:"0",errMsg:f.errMsg||""})}})}
function c(g){wx.request({url:"https://restapi.amap.com/v3/geocode/regeo",data:{key:d.key,location:g,extensions:"all",s:e.s,platform:e.platform,appname:d.key,sdkversion:e.sdkversion,logversion:e.logversion},method:"GET",header:{"content-type":"application/json"},success:function(h){if(h.data.status&&"1"==h.data.status){h=h.data.regeocode;if(h.addressComponent)var f=h.addressComponent.adcode;else h.aois&&0<h.aois.length&&(f=h.aois[0].adcode);b(f)}else a.fail({errCode:h.data.infocode,errMsg:h.data.info})},
fail:function(h){a.fail({errCode:"0",errMsg:h.errMsg||""})}})}var d=this,e=d.requestConfig;a.city?b(a.city):d.getWxLocation(a,function(g){c(g)})};
AMapWX.prototype.getPoiAround=function(a){function b(e){e={key:c.key,location:e,s:d.s,platform:d.platform,appname:c.key,sdkversion:d.sdkversion,logversion:d.logversion};a.querytypes&&(e.types=a.querytypes);a.querykeywords&&(e.keywords=a.querykeywords);wx.request({url:"https://restapi.amap.com/v3/place/around",data:e,method:"GET",header:{"content-type":"application/json"},success:function(g){if(g.data.status&&"1"==g.data.status){if((g=g.data)&&g.pois){for(var h=[],f=0;f<g.pois.length;f++){var k=0==
f?a.iconPathSelected:a.iconPath;h.push({latitude:parseFloat(g.pois[f].location.split(",")[1]),longitude:parseFloat(g.pois[f].location.split(",")[0]),iconPath:k,width:22,height:32,id:f,name:g.pois[f].name,address:g.pois[f].address})}a.success({markers:h,poisData:g.pois})}}else a.fail({errCode:g.data.infocode,errMsg:g.data.info})},fail:function(g){a.fail({errCode:"0",errMsg:g.errMsg||""})}})}var c=this,d=c.requestConfig;a.location?b(a.location):c.getWxLocation(a,function(e){b(e)})};
AMapWX.prototype.getStaticmap=function(a){function b(e){c.push("location="+e);a.zoom&&c.push("zoom="+a.zoom);a.size&&c.push("size="+a.size);a.scale&&c.push("scale="+a.scale);a.markers&&c.push("markers="+a.markers);a.labels&&c.push("labels="+a.labels);a.paths&&c.push("paths="+a.paths);a.traffic&&c.push("traffic="+a.traffic);e="https://restapi.amap.com/v3/staticmap?"+c.join("&");a.success({url:e})}var c=[];c.push("key="+this.key);var d=this.requestConfig;c.push("s="+d.s);c.push("platform="+d.platform);
c.push("appname="+d.appname);c.push("sdkversion="+d.sdkversion);c.push("logversion="+d.logversion);a.location?b(a.location):this.getWxLocation(a,function(e){b(e)})};
AMapWX.prototype.getInputtips=function(a){var b=Object.assign({},this.requestConfig);a.location&&(b.location=a.location);a.keywords&&(b.keywords=a.keywords);a.type&&(b.type=a.type);a.city&&(b.city=a.city);a.citylimit&&(b.citylimit=a.citylimit);wx.request({url:"https://restapi.amap.com/v3/assistant/inputtips",data:b,method:"GET",header:{"content-type":"application/json"},success:function(c){c&&c.data&&c.data.tips&&a.success({tips:c.data.tips})},fail:function(c){a.fail({errCode:"0",errMsg:c.errMsg||
""})}})};
AMapWX.prototype.getDrivingRoute=function(a){var b=Object.assign({},this.requestConfig);a.origin&&(b.origin=a.origin);a.destination&&(b.destination=a.destination);a.strategy&&(b.strategy=a.strategy);a.waypoints&&(b.waypoints=a.waypoints);a.avoidpolygons&&(b.avoidpolygons=a.avoidpolygons);a.avoidroad&&(b.avoidroad=a.avoidroad);wx.request({url:"https://restapi.amap.com/v3/direction/driving",data:b,method:"GET",header:{"content-type":"application/json"},success:function(c){c&&c.data&&c.data.route&&a.success({paths:c.data.route.paths,
taxi_cost:c.data.route.taxi_cost||""})},fail:function(c){a.fail({errCode:"0",errMsg:c.errMsg||""})}})};
AMapWX.prototype.getWalkingRoute=function(a){var b=Object.assign({},this.requestConfig);a.origin&&(b.origin=a.origin);a.destination&&(b.destination=a.destination);wx.request({url:"https://restapi.amap.com/v3/direction/walking",data:b,method:"GET",header:{"content-type":"application/json"},success:function(c){c&&c.data&&c.data.route&&a.success({paths:c.data.route.paths})},fail:function(c){a.fail({errCode:"0",errMsg:c.errMsg||""})}})};
AMapWX.prototype.getTransitRoute=function(a){var b=Object.assign({},this.requestConfig);a.origin&&(b.origin=a.origin);a.destination&&(b.destination=a.destination);a.strategy&&(b.strategy=a.strategy);a.city&&(b.city=a.city);a.cityd&&(b.cityd=a.cityd);wx.request({url:"https://restapi.amap.com/v3/direction/transit/integrated",data:b,method:"GET",header:{"content-type":"application/json"},success:function(c){c&&c.data&&c.data.route&&(c=c.data.route,a.success({distance:c.distance||"",taxi_cost:c.taxi_cost||
"",transits:c.transits}))},fail:function(c){a.fail({errCode:"0",errMsg:c.errMsg||""})}})};
AMapWX.prototype.getRidingRoute=function(a){var b=Object.assign({},this.requestConfig);a.origin&&(b.origin=a.origin);a.destination&&(b.destination=a.destination);wx.request({url:"https://restapi.amap.com/v3/direction/riding",data:b,method:"GET",header:{"content-type":"application/json"},success:function(c){c&&c.data&&c.data.route&&a.success({paths:c.data.route.paths})},fail:function(c){a.fail({errCode:"0",errMsg:c.errMsg||""})}})};module.exports.AMapWX=AMapWX;
\ No newline at end of file
"use strict"; function _classCallCheck(t, a) { if (!(t instanceof a)) throw new TypeError("Cannot call a class as a function") } var _createClass = function () { function t(t, a) { for (var e = 0; e < a.length; e++) { var i = a[e]; i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) } } return function (a, e, i) { return e && t(a.prototype, e), i && t(a, i), a } }(), BMapWX = function () { function t(a) { _classCallCheck(this, t), this.ak = a.ak } return _createClass(t, [{ key: "getWXLocation", value: function (t, a, e, i) { t = t || "gcj02", a = a || function () { }, e = e || function () { }, i = i || function () { }, wx.getLocation({ type: t, success: a, fail: e, complete: i }) } }, { key: "search", value: function (t) { var a = this; t = t || {}; var e = { query: t.query || "生活服务$美食&酒店", scope: t.scope || 1, filter: t.filter || "", coord_type: t.coord_type || 2, page_size: t.page_size || 10, page_num: t.page_num || 0, output: t.output || "json", ak: a.ak, sn: t.sn || "", timestamp: t.timestamp || "", radius: t.radius || 2e3, ret_coordtype: "gcj02ll" }, i = { iconPath: t.iconPath, iconTapPath: t.iconTapPath, width: t.width, height: t.height, alpha: t.alpha || 1, success: t.success || function () { }, fail: t.fail || function () { } }, n = function (t) { e.location = t.latitude + "," + t.longitude, wx.request({ url: "https://api.map.baidu.com/place/v2/search", data: e, header: { "content-type": "application/json" }, method: "GET", success: function (t) { var a = t.data; if (0 === a.status) { var e = a.results, n = {}; n.originalData = a, n.wxMarkerData = []; for (var s = 0; s < e.length; s++)n.wxMarkerData[s] = { id: s, latitude: e[s].location.lat, longitude: e[s].location.lng, title: e[s].name, iconPath: i.iconPath, iconTapPath: i.iconTapPath, address: e[s].address, telephone: e[s].telephone, alpha: i.alpha, width: i.width, height: i.height }; i.success(n) } else i.fail({ errMsg: a.message, statusCode: a.status }) }, fail: function (t) { i.fail(t) } }) }, s = function (t) { i.fail(t) }, o = function (t) { }; if (t.location) { var c = t.location.split(",")[1]; n({ errMsg: "input location", latitude: t.location.split(",")[0], longitude: c }) } else a.getWXLocation("gcj02", n, s, o) } }, { key: "suggestion", value: function (t) { var a = this; t = t || {}; var e = { query: t.query || "", region: t.region || "全国", city_limit: t.city_limit || !1, output: t.output || "json", ak: a.ak, sn: t.sn || "", timestamp: t.timestamp || "", ret_coordtype: "gcj02ll" }, i = { success: t.success || function () { }, fail: t.fail || function () { } }; wx.request({ url: "https://api.map.baidu.com/place/v2/suggestion", data: e, header: { "content-type": "application/json" }, method: "GET", success: function (t) { var a = t.data; 0 === a.status ? i.success(a) : i.fail({ errMsg: a.message, statusCode: a.status }) }, fail: function (t) { i.fail(t) } }) } }, { key: "regeocoding", value: function (t) { var a = this; t = t || {}; var e = { coordtype: t.coordtype || "gcj02ll", ret_coordtype: "gcj02ll", radius: t.radius || 1e3, ak: a.ak, sn: t.sn || "", output: t.output || "json", callback: t.callback || function () { }, extensions_poi: t.extensions_poi || 1, extensions_road: t.extensions_road || !1, extensions_town: t.extensions_town || !1, language: t.language || "zh-CN", language_auto: t.language_auto || 0 }, i = { iconPath: t.iconPath, iconTapPath: t.iconTapPath, width: t.width, height: t.height, alpha: t.alpha || 1, success: t.success || function () { }, fail: t.fail || function () { } }, n = function (t) { e.location = t.latitude + "," + t.longitude, wx.request({ url: "https://api.map.baidu.com/reverse_geocoding/v3", data: e, header: { "content-type": "application/json" }, method: "GET", success: function (a) { var e = a.data; if (0 === e.status) { var n = e.result, s = {}; s.originalData = e, s.wxMarkerData = [], s.wxMarkerData[0] = { id: 0, latitude: t.latitude, longitude: t.longitude, address: n.formatted_address, iconPath: i.iconPath, iconTapPath: i.iconTapPath, desc: n.sematic_description, business: n.business, alpha: i.alpha, width: i.width, height: i.height }, i.success(s) } else i.fail({ errMsg: e.message, statusCode: e.status }) }, fail: function (t) { i.fail(t) } }) }, s = function (t) { i.fail(t) }, o = function (t) { }; if (t.location) { var c = t.location.split(",")[1]; n({ errMsg: "input location", latitude: t.location.split(",")[0], longitude: c }) } else a.getWXLocation("gcj02", n, s, o) } }, { key: "geocoding", value: function (t) { var a = this; t = t || {}; var e = { address: t.address || "", city: t.city || "", ret_coordtype: t.coordtype || "gcj02ll", ak: a.ak, sn: t.sn || "", output: t.output || "json", callback: t.callback || function () { } }, i = { iconPath: t.iconPath, iconTapPath: t.iconTapPath, width: t.width, height: t.height, alpha: t.alpha || 1, success: t.success || function () { }, fail: t.fail || function () { } }; if (t.address) wx.request({ url: "https://api.map.baidu.com/geocoding/v3", data: e, header: { "content-type": "application/json" }, method: "GET", success: function (t) { var a = t.data; if (0 === a.status) { var e = a.result, n = a; n.originalData = a, n.wxMarkerData = [], n.wxMarkerData[0] = { id: 0, latitude: e.location.lat, longitude: e.location.lng, iconPath: i.iconPath, iconTapPath: i.iconTapPath, alpha: i.alpha, width: i.width, height: i.height }, i.success(n) } else i.fail({ errMsg: a.message, statusCode: a.status }) }, fail: function (t) { i.fail(t) } }); else { var n = { errMsg: "input address!" }; i.fail(n) } } }, { key: "weather", value: function (t) { var a = this; t = t || {}; var e = { coord_type: t.coord_type || "gcj02", output: t.output || "json", ak: a.ak, sn: t.sn || "", timestamp: t.timestamp || "" }, i = { success: t.success || function () { }, fail: t.fail || function () { } }, n = function (t) { e.location = t.longitude + "," + t.latitude, wx.request({ url: "https://api.map.baidu.com/telematics/v3/weather", data: e, header: { "content-type": "application/json" }, method: "GET", success: function (t) { var a = t.data; if (0 === a.error && "success" === a.status) { var e = a.results, n = {}; n.originalData = a, n.currentWeather = [], n.currentWeather[0] = { currentCity: e[0].currentCity, pm25: e[0].pm25, date: e[0].weather_data[0].date, temperature: e[0].weather_data[0].temperature, weatherDesc: e[0].weather_data[0].weather, wind: e[0].weather_data[0].wind }, i.success(n) } else i.fail({ errMsg: a.message, statusCode: a.status }) }, fail: function (t) { i.fail(t) } }) }, s = function (t) { i.fail(t) }, o = function (t) { }; if (t.location) { var c = t.location.split(",")[0]; n({ errMsg: "input location", latitude: t.location.split(",")[1], longitude: c }) } else a.getWXLocation("gcj02", n, s, o) } }]), t }(); module.exports.BMapWX = BMapWX;
\ No newline at end of file
/**
* 图片压缩
* @param {String} imgUrl 需要压缩的图片路径
* @param {Object} options 压缩参数
* width: 压缩到多宽,默认图片宽度(待优化,传入宽度,应计算高度)
* height: 压缩到多高,默认图片高度
* pixels: 压缩图片的最大分辨率,默认二百万
* quality: 压缩质量,默认0.8
* type: 获取的base64类型,默认jpg
* base64: 是否返回base64,默认true(非H5有效)
* @return {Promise}
* reject
* code
* -1: 获取图片信息错误
* -2: 极大可能创建图片对象出错(h5会出现,出现概率无限接近0)
* -3: canvas转图片错误(小程序会出现)
* -4: 图片转base64错误(小程序会出现)
*/
// 图片分辨率压缩
const calcImageSize = (res, pixels) => {
let imgW, imgH
imgW = res.width
imgH = res.height
let ratio
if((ratio = imgW * imgH / pixels) > 1) {
ratio = Math.sqrt(ratio)
imgW = parseInt(imgW / ratio)
imgH = parseInt(imgH / ratio)
} else {
ratio = 1
}
return { imgW, imgH }
}
const urlTobase64 = (url, type) => {
return new Promise((resolve, reject) => {
uni.getFileSystemManager().readFile({
filePath: url,
encoding: 'base64',
success: res => {
let base64 = res.data
base64 = `data:image/${type};base64,${base64}`
resolve(base64)
}
})
})
}
const compress = (imgUrl, options={}) => {
/*************** 参数默认值 ***************/
const MAX_PIXELS = 2000000 // 最大分辨率,宽 * 高 的值
const MAX_QUALITY = 0.8 // 压缩质量
const IMG_TYPE = 'jpg'
const BASE_64 = false
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: imgUrl,
success: res => {
let pixels = options.pixels || MAX_PIXELS
let quality = options.quality || MAX_QUALITY
let type = options.type || IMG_TYPE
let isBase64 = options.base64 || BASE_64
let { imgW, imgH } = calcImageSize(res, pixels)
let w = options.width || imgW
let h = options.height || imgH
// #ifdef H5
type = type == 'jpg' ? 'jpeg' : type,
// #endif
// #ifndef H5
type = type == 'png' ? 'png' : 'jpg',
// #endif
console.log(`%c 宽: ${w} %c 高: ${h} %c 分辨率: ${w * h} %c 质量: ${quality} %c 类型: ${type}`, 'color:#f00', 'background-color:#f60;color:#fff', 'color:#F00', 'background-color:#f60;color:#fff', 'color:#F00')
// #ifdef H5
let img = new Image()
img.src = res.path
img.onload = () => {
let canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = w
canvas.height = h
let drawW = w, drawH = h
ctx.drawImage(img, 0, 0, drawW, drawH)
let base64 = canvas.toDataURL(`image/${type}`, quality)
resolve(base64)
canvas = null
}
// #endif
// 微信小程序
// #ifdef MP-WEIXIN
if(type === 'jpg'){
uni.compressImage({ //仅对jpg有效
src: res.path,
quality: 80,
success: wxRes => resolve(wxRes.tempFilePath)
})
} else {
const canvasConfig = { type: '2d', width: w, height: h }
const canvasIns = wx.createOffscreenCanvas({...canvasConfig}) //创建离屏 2D canvas 实例
canvasIns.width = w
canvasIns.height = h
const image = canvasIns.createImage()
// 等待图片加载
image.src = res.path
image.onload = () => {
let canvas = canvasIns.getContext('2d')
canvas.drawImage(image, 0, 0, w, h)
uni.canvasToTempFilePath({
canvas: canvasIns,
x: 0,
y: 0,
width: w,
height: h,
destWidth: w,
destHeight: h,
fileType: type, //目标文件类型,默认为png
quality: quality, //图片的质量, 仅对 jpg 有效
success: file => {
if(isBase64) {
urlTobase64(file.tempFilePath, type).then(res => {
canvas = null
resolve(res)
}).catch(e => {
reject({
code: -4,
msg: '图片转base64错误',
data: e
})
})
} else {
canvas = null
resolve(file.tempFilePath)
}
},
fail: e => {
reject({
code: -3,
msg: 'canvas转图片错误',
data: e
})
}
})
}
}
// #endif
}
})
})
}
export default compress
//默认时间转换
const formatTime = (date, type) => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
if(type === 'D'){ //只传递年月日
return `${[year, month, day].map(formatNumber).join('-')}T00:00:00+08:00`
}else{
return `${[year, month, day].map(formatNumber).join('-')}T${[hour, minute, second].map(formatNumber).join(':')}+08:00`
}
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : `0${n}`
}
//获取图片base
function getImgBase64(filePaths) {
let pictures_str = ''
filePaths.forEach(function (filePath) {
var suffixs = filePath.split(".")
//文件名后缀
var suffix = suffixs[suffixs.length - 1]
var fs = wx.getFileSystemManager()
var filedata = ''
if (filePath.indexOf("data:image") != -1) {
filedata = filePath
} else {
filedata = "data:image/" + suffix + ";base64," + fs.readFileSync(filePath, 'base64')
}
if (pictures_str == '') {
pictures_str = filedata
} else {
pictures_str = pictures_str + '|' + filedata
}
})
return pictures_str
}
//格林威治时间转换
const formatGMT = (time, type) => { // time 为UTC时间格式 2022-06-30T16:00:00Z
if(!time) return
const timestamp = new Date(time).getTime() //转本地时间
let date = formatTime(new Date(timestamp))
if (type === 'D') { //只显示年月日
date = date.substring(0, 10)
} else if(type === 'H'){ //只显示时分秒
date = date.substring(0, 19).split('T')[1]
} else if(type === 'M'){ //只显示小时分钟
date = date.substring(0, 16).split('T')[1]
} else {
date = date.substring(0, 19).replace('T', ' ')
}
return date
}
function deepCopy(obj) {
if (obj instanceof Object) {
const newObj = {};
if (Array.isArray(obj)) {
const arr = [];
obj.forEach(item => {
arr.push(deepCopy(item));
});
return arr;
} else {
for (const key in obj) {
const value = obj[key];
if (typeof value === 'function') {
newObj[key] = value.bind(newObj);
} else if (typeof value === 'object') {
if (Array.isArray(value)) {
newObj[key] = [];
value.forEach(item => {
newObj[key].push(deepCopy(item));
});
} else {
newObj[key] = deepCopy(value);
}
} else {
newObj[key] = value;
}
}
}
return newObj;
} else {
return obj;
}
}
module.exports = {
formatTime,
getImgBase64,
formatGMT,
deepCopy
}
\ No newline at end of file
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@amap/amap-jsapi-loader@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz#9ec4b4d5d2467eac451f6c852e35db69e9f9f0c0"
integrity sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==
"@babel/runtime@^7.17.2":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd"
integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==
dependencies:
regenerator-runtime "^0.13.11"
copy-text-to-clipboard@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz#8cbf8f90e0a47f12e4a24743736265d157bce69c"
integrity sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==
core-js@^3.11.0:
version "3.27.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.1.tgz#23cc909b315a6bb4e418bf40a52758af2103ba46"
integrity sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==
image-tools@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/image-tools/-/image-tools-1.4.0.tgz#66aacbafad677af7f3fd7f32f8fa1e0881b83783"
integrity sha512-TKtvJ6iUwM0mfaD4keMnk1ENHFC470QEjBfA3IlvKdEOufzvWbjbaoNcoyYq6HlViF8+d5tOS1ooE6j7CHf1lQ==
jweixin-module@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/jweixin-module/-/jweixin-module-1.6.0.tgz#4a7ea614083e3c9c3f49e2fdc2bb882cfa58dfcd"
integrity sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w==
mutation-observer@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mutation-observer/-/mutation-observer-1.0.3.tgz#42e9222b101bca82e5ba9d5a7acf4a14c0f263d0"
integrity sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==
regenerator-runtime@^0.13.11:
version "0.13.11"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
uview-ui@^2.0.31:
version "2.0.33"
resolved "https://registry.yarnpkg.com/uview-ui/-/uview-ui-2.0.33.tgz#229c222b60846190f45e935c3661b9c8affb84a1"
integrity sha512-M3NsLFAY0z95NGMnTCDUR/TvJb6a/UYZzi1km5Gi6TkBCaoHdbmtQymkc1C4eszeoQOrpEIhit/2V47UglzHRw==
vconsole@^3.15.0:
version "3.15.0"
resolved "https://registry.yarnpkg.com/vconsole/-/vconsole-3.15.0.tgz#2383482b0a4106204090046ec128071284e04a90"
integrity sha512-8hq7wabPcRucSWQyN7/1tthMawP9JPvM95zgtMHpPknMMMCKj+abpoK7P7oKK4B0qw58C24Mdvo9+raUdpHyVQ==
dependencies:
"@babel/runtime" "^7.17.2"
copy-text-to-clipboard "^3.0.1"
core-js "^3.11.0"
mutation-observer "^1.0.3"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment