uniapp工作积累
关于rpx
- rpx是基于整个屏幕为750px来进行匹配的
- 即如果设置成375rpx,按照比例的话,它会是屏幕的一半
- 如果换到其他不同分辨率的设备,它依旧会是占屏幕的一半
uniapp中生命周期
- Page页面生命周期函数执行顺序
- beforeCreate => onLoad => onShow => created => beforeMount => onReady => mounted
- 刷新数据后
- beforeUpdate => updated
- 页面加载过程:
- 加载=》显示=》加载完成=》页面隐藏=》页面卸载
- 触发页面生命周期:
- onLoad-监听页面加载 =》onShow-监听页面显示 =》 onReady-监听页面初次渲染完成 =》 onHide-监听页面隐藏 =》onUnload-监听页面卸载
uniapp中使用地图
vue
<template>
<map
style="width: 100%; height: 300rpx"
:show-location="true"
:latitude="mapConfig.latitude"
:longitude="mapConfig.longitude"
:markers="mapConfig.marker"
:scale="scale"
@markertap="markertap"
@callouttap="callouttap">
</map>
</template>
<script>
export default {
data() {
return {
mapCtx: {},
mapConfig: {
latitude: 23.106574, //纬度
longitude: 113.324587, //经度
scale: 13, //缩放级别
marker: [
{
id: 0,
latitude: 23.13065, //纬度
longitude: 113.3274, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
// title:'我在这里',//标注点名
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '天宝大厦', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 1234597,
latitude: 23.106574, //纬度
longitude: 113.324587, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
// title:'我在这里',//标注点名
alpha: 0.5, //透明度
// label:{//为标记点旁边增加标签 //因背景颜色H5不支持
// color:'red',//文本颜色
// },
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '广州塔', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 2,
latitude: 23.1338, //纬度
longitude: 113.33052, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '德隆大厦', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 3,
latitude: 23.136455, //纬度
longitude: 113.329002, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '羊城国际商贸中心', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 4,
latitude: 23.224781, //纬度
longitude: 113.293911, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '天瑞广场A座', //文本
color: '#ffffff', //文字颜色
fontSize: 16, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '12',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 5,
latitude: 23.072726, //纬度
longitude: 113.277921, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '大米和小米儿童康复(广州盈丰)中心', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '8',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
}
]
}
}
},
computed: {
marker1() {
return [
{
id: 0,
latitude: this.mapConfig.latitude, //纬度
longitude: this.mapConfig.longitude, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
title: '我在这里', //标注点名
// alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '天宝大厦', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
},
label: {
content: '文本1',
color: '#F76350',
bgColor: '#fff',
padding: 5,
borderRadius: 4
}
}
]
}
},
onReady() {
this.mapCtx = wx.createMapContext('myMap')
// console.log('onReady', this.mapCtx)
},
methods: {
//地图点击事件
markertap(e) {
console.log('===你点击了标记点===', e)
},
//地图点击事件
callouttap(e) {
console.log('地图点击事件', e)
}
}
}
</script>
<template>
<map
style="width: 100%; height: 300rpx"
:show-location="true"
:latitude="mapConfig.latitude"
:longitude="mapConfig.longitude"
:markers="mapConfig.marker"
:scale="scale"
@markertap="markertap"
@callouttap="callouttap">
</map>
</template>
<script>
export default {
data() {
return {
mapCtx: {},
mapConfig: {
latitude: 23.106574, //纬度
longitude: 113.324587, //经度
scale: 13, //缩放级别
marker: [
{
id: 0,
latitude: 23.13065, //纬度
longitude: 113.3274, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
// title:'我在这里',//标注点名
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '天宝大厦', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 1234597,
latitude: 23.106574, //纬度
longitude: 113.324587, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
// title:'我在这里',//标注点名
alpha: 0.5, //透明度
// label:{//为标记点旁边增加标签 //因背景颜色H5不支持
// color:'red',//文本颜色
// },
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '广州塔', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 2,
latitude: 23.1338, //纬度
longitude: 113.33052, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '德隆大厦', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 3,
latitude: 23.136455, //纬度
longitude: 113.329002, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '羊城国际商贸中心', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 4,
latitude: 23.224781, //纬度
longitude: 113.293911, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '天瑞广场A座', //文本
color: '#ffffff', //文字颜色
fontSize: 16, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '12',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
},
{
id: 5,
latitude: 23.072726, //纬度
longitude: 113.277921, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '大米和小米儿童康复(广州盈丰)中心', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '8',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
}
}
]
}
}
},
computed: {
marker1() {
return [
{
id: 0,
latitude: this.mapConfig.latitude, //纬度
longitude: this.mapConfig.longitude, //经度
iconPath: '', //显示的图标
rotate: 0, // 旋转度数
width: 20, //宽
height: 30, //高
title: '我在这里', //标注点名
// alpha: 0.5, //透明度
callout: {
//自定义标记点上方的气泡窗口 点击有效
content: '天宝大厦', //文本
color: '#ffffff', //文字颜色
fontSize: 14, //文本大小
borderRadius: 15, //边框圆角
borderWidth: '10',
bgColor: '#e51860', //背景颜色
display: 'ALWAYS' //常显
},
label: {
content: '文本1',
color: '#F76350',
bgColor: '#fff',
padding: 5,
borderRadius: 4
}
}
]
}
},
onReady() {
this.mapCtx = wx.createMapContext('myMap')
// console.log('onReady', this.mapCtx)
},
methods: {
//地图点击事件
markertap(e) {
console.log('===你点击了标记点===', e)
},
//地图点击事件
callouttap(e) {
console.log('地图点击事件', e)
}
}
}
</script>
uniapp中转圈动画
vue
<view class="pgmbask_bot">
<image src="/static/2.1/cust_ico_cng.png" style="transition: 1s all" :style="rotationStyle" />
<span @click="changeQues">换一换</span>
</view>
<script>
this.rotate = 0
data() {
rotationStyle: '',
}
methods: {
changeQues(e) {
this.rotate += 360
this.rotationStyle = `transform: rotate(${this.rotate}deg);`
// this.getData()
},
}
</script>
<view class="pgmbask_bot">
<image src="/static/2.1/cust_ico_cng.png" style="transition: 1s all" :style="rotationStyle" />
<span @click="changeQues">换一换</span>
</view>
<script>
this.rotate = 0
data() {
rotationStyle: '',
}
methods: {
changeQues(e) {
this.rotate += 360
this.rotationStyle = `transform: rotate(${this.rotate}deg);`
// this.getData()
},
}
</script>
uniapp外链
vue
<li @click="linkTo"><span>查看官网</span></li>
<script>
linkTo() {
let webUrl = 'https://xxxx/xx.html' // URL是要跳转的外部地址 作为参数
uni.navigateTo({
url: '/pages/components/webLink?url=' + webUrl
})
},
</script>
<li @click="linkTo"><span>查看官网</span></li>
<script>
linkTo() {
let webUrl = 'https://xxxx/xx.html' // URL是要跳转的外部地址 作为参数
uni.navigateTo({
url: '/pages/components/webLink?url=' + webUrl
})
},
</script>
vue
<template>
<web-view :src="pageUrl"></web-view>
</template>
<script>
export default {
data() {
return {
pageUrl: ''
}
},
onLoad(item) {
// console.log(this.url)
// 传入需要跳转的链接 使用web-view标签进行跳转
this.pageUrl = decodeURIComponent(item.webUrl)
}
}
</script>
<template>
<web-view :src="pageUrl"></web-view>
</template>
<script>
export default {
data() {
return {
pageUrl: ''
}
},
onLoad(item) {
// console.log(this.url)
// 传入需要跳转的链接 使用web-view标签进行跳转
this.pageUrl = decodeURIComponent(item.webUrl)
}
}
</script>
uniapp的安全区
css
padding-bottom: env(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
u-view 上传
js
// 获取文件类型
function getFileTypeUpload(fileName) {
const index = fileName.lastIndexOf('.')
const ext = fileName.substr(index + 1).toLowerCase()
const aImageType = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'psd']
const aVideoType = ['mp4', 'rmvb', 'flv']
const aExcel = ['xlsx', 'xls']
let fileType = -1 // -1-文件 0-表格 1-图片 2-视频
if (aExcel.includes(ext)) {
fileType = 0
}
if (aImageType.includes(ext)) {
fileType = 1
}
if (aVideoType.includes(ext)) {
fileType = 2
}
return fileType
}
export default function chooseAndUploadFile(files, vm) {
let uploadArr = []
const len = files.length
let count = 0
return new Promise((resolve, reject) => {
if (!len) {
return resolve([])
}
next()
function next() {
let cur = count++
if (cur >= len) {
return resolve(uploadArr)
}
const fileItem = files[cur]
uni
.uploadFile({
url: baseURL + 'common/obsUpload',
filePath: fileItem.url,
formData: {
fileType: getFileTypeUpload(fileItem.url),
ident: 'ex-patrol'
},
name: 'file',
header: { token: token }
})
.then(res => {
let fileObject = JSON.parse(res[1].data).data
uploadArr.push(fileObject)
if (cur < len) {
next()
}
})
.catch(res => {
if (cur < len) {
next()
}
})
}
})
}
// 获取文件类型
function getFileTypeUpload(fileName) {
const index = fileName.lastIndexOf('.')
const ext = fileName.substr(index + 1).toLowerCase()
const aImageType = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'psd']
const aVideoType = ['mp4', 'rmvb', 'flv']
const aExcel = ['xlsx', 'xls']
let fileType = -1 // -1-文件 0-表格 1-图片 2-视频
if (aExcel.includes(ext)) {
fileType = 0
}
if (aImageType.includes(ext)) {
fileType = 1
}
if (aVideoType.includes(ext)) {
fileType = 2
}
return fileType
}
export default function chooseAndUploadFile(files, vm) {
let uploadArr = []
const len = files.length
let count = 0
return new Promise((resolve, reject) => {
if (!len) {
return resolve([])
}
next()
function next() {
let cur = count++
if (cur >= len) {
return resolve(uploadArr)
}
const fileItem = files[cur]
uni
.uploadFile({
url: baseURL + 'common/obsUpload',
filePath: fileItem.url,
formData: {
fileType: getFileTypeUpload(fileItem.url),
ident: 'ex-patrol'
},
name: 'file',
header: { token: token }
})
.then(res => {
let fileObject = JSON.parse(res[1].data).data
uploadArr.push(fileObject)
if (cur < len) {
next()
}
})
.catch(res => {
if (cur < len) {
next()
}
})
}
})
}
vue
<u-upload :fileList="fileList" @afterRead="onListChange" @delete="deletePic" multiple :maxCount="4" width="154rpx" height="154rpx">
<u-image :fade="false" src="" width="154rpx" height="154rpx"></u-image>
</u-upload>
<script>
data() {
return {
fileList: [],
}
},
methods: {
// 删除图片
deletePic(event) {
this[`fileList${event.name}`].splice(event.index, 1)
},
// 多
onListChange(data) {
uni.showLoading({ title: '文件上传中' })
chooseAndUploadFile(data.file, this)
.then(files => {
uni.hideLoading()
// this.fileList = [...this.fileList, ...files] // 多
// this.form.pictureUrl = files[0].url // 单
// console.log(this.fileList)
})
.catch(err => {
this.fileList = []
uni.hideLoading()
uni.showToast({ title: '图片上传失败,请重新上传', icon: 'none', duration: 2000 })
})
},
getImgStr() {
if (this.fileList > 0) {
this.fileList.forEach(item => {
this.form.pictureUrl += item.url + ','
})
this.form.pictureUrl = this.form.pictureUrl.replace(/,$/gi, '')
}
}
}
</script>
<u-upload :fileList="fileList" @afterRead="onListChange" @delete="deletePic" multiple :maxCount="4" width="154rpx" height="154rpx">
<u-image :fade="false" src="" width="154rpx" height="154rpx"></u-image>
</u-upload>
<script>
data() {
return {
fileList: [],
}
},
methods: {
// 删除图片
deletePic(event) {
this[`fileList${event.name}`].splice(event.index, 1)
},
// 多
onListChange(data) {
uni.showLoading({ title: '文件上传中' })
chooseAndUploadFile(data.file, this)
.then(files => {
uni.hideLoading()
// this.fileList = [...this.fileList, ...files] // 多
// this.form.pictureUrl = files[0].url // 单
// console.log(this.fileList)
})
.catch(err => {
this.fileList = []
uni.hideLoading()
uni.showToast({ title: '图片上传失败,请重新上传', icon: 'none', duration: 2000 })
})
},
getImgStr() {
if (this.fileList > 0) {
this.fileList.forEach(item => {
this.form.pictureUrl += item.url + ','
})
this.form.pictureUrl = this.form.pictureUrl.replace(/,$/gi, '')
}
}
}
</script>
筛选框封装
- 使用
vue
<!-- 筛选表单 -->
<form-layer #scrollView :filterOptions="filterOptions" @getFormData="getFormData"></form-layer>
<script setup>
import dayjs from 'dayjs'
import FormLayer from '@/components/form-picker/FormLayer.vue'
const formData = ref({
// 默认时间
startTime: dayjs(Date.now() - 60 * 60 * 24 * 1000 * 15).format('YYYY-MM-DD HH:mm'),
endTime: dayjs(Date.now()).format('YYYY-MM-DD HH:mm')
})
const getFormData = (val) => {
formData.value = val
// console.log(formData.value)
getList()
}
// 状态Map值
const statusMap = new Map([
[1, '生效'],
[2, '作废']
])
const filterOptions = ref([
{
type: 'datetime',
label: '开始时间',
defaultTime: formData.value.startTime
},
{
type: 'datetime',
label: '结束时间',
defaultTime: formData.value.endTime
},
{
type: 'picker',
label: '类型',
props: 'auditType',
pickerColumns: [
[
{
label: '全部',
value: ''
},
{
label: auditTypeMap.get(0),
value: 0
},
{
label: auditTypeMap.get(1),
value: 1
},
{
label: auditTypeMap.get(2),
value: 2
}
]
]
},
{
type: 'picker',
label: '状态',
props: 'status',
pickClass: 'wd80',
pickerColumns: [
[
{
label: '全部',
value: ''
},
{
label: statusMap.get(1),
value: 1
},
{
label: statusMap.get(2),
value: 2
}
]
]
}
])
</script>
<!-- 筛选表单 -->
<form-layer #scrollView :filterOptions="filterOptions" @getFormData="getFormData"></form-layer>
<script setup>
import dayjs from 'dayjs'
import FormLayer from '@/components/form-picker/FormLayer.vue'
const formData = ref({
// 默认时间
startTime: dayjs(Date.now() - 60 * 60 * 24 * 1000 * 15).format('YYYY-MM-DD HH:mm'),
endTime: dayjs(Date.now()).format('YYYY-MM-DD HH:mm')
})
const getFormData = (val) => {
formData.value = val
// console.log(formData.value)
getList()
}
// 状态Map值
const statusMap = new Map([
[1, '生效'],
[2, '作废']
])
const filterOptions = ref([
{
type: 'datetime',
label: '开始时间',
defaultTime: formData.value.startTime
},
{
type: 'datetime',
label: '结束时间',
defaultTime: formData.value.endTime
},
{
type: 'picker',
label: '类型',
props: 'auditType',
pickerColumns: [
[
{
label: '全部',
value: ''
},
{
label: auditTypeMap.get(0),
value: 0
},
{
label: auditTypeMap.get(1),
value: 1
},
{
label: auditTypeMap.get(2),
value: 2
}
]
]
},
{
type: 'picker',
label: '状态',
props: 'status',
pickClass: 'wd80',
pickerColumns: [
[
{
label: '全部',
value: ''
},
{
label: statusMap.get(1),
value: 1
},
{
label: statusMap.get(2),
value: 2
}
]
]
}
])
</script>
- FormLayer.vue
vue
<template>
<!-- <scroll-view scroll-x class="nav_scroll"> -->
<div class="nav_scroll" :class="{ nowrap: tagValue === '' }">
<ul class="nav_ul">
<li class="nav_li" v-for="(item, index) in filterOptions" :key="index">
<date-time v-if="item.type === 'datetime'" :defaultTime="item.defaultTime" :label="item.label" @getDateTime="getDateTime" />
<select-picker
v-if="item.type === 'picker'"
@getPickerData="getPickerData"
:pickClass="item.pickClass"
:pickLabel="item.label"
:pickProps="item.props"
:pickerColumns="item.pickerColumns" />
</li>
</ul>
<b class="tag" @click="getMore">{{ tagValue }}</b>
</div>
<!-- </scroll-view> -->
<view style="position: absolute; right: 0; top: 0; background: #f7f8fa; height: 74rpx; width: 20rpx">
</view>
</template>
<script setup>
import SelectPicker from '@/components/form-picker/SelectPicker.vue'
import DateTime from '@/components/form-picker/DateTime.vue'
import { ref } from 'vue'
const emit = defineEmits(['getFormData'])
const props = defineProps({
filterOptions: Array
})
const formData = {}
const tagValue = ref('...')
const getMore = () => {
// console.log('12456')
switch (tagValue.value) {
case '':
tagValue.value = '...'
break
case '...':
tagValue.value = ''
break
}
}
const getDateTime = (val, mode) => {
// console.log(val, mode)
switch (mode) {
case '开始时间':
formData.startTime = val
break
case '结束时间':
formData.endTime = val
break
}
emit('getFormData', formData)
}
const getPickerData = (obj, mode, keyValue) => {
// console.log(obj, mode, keyValue)
formData[mode] = obj[keyValue]
emit('getFormData', formData)
}
</script>
<style scoped lang="scss">
$navHeight: 80rpx;
.nav_scroll {
position: relative;
white-space: nowrap;
height: 75rpx;
background: #f7f8fa;
.nav_ul {
height: $navHeight;
width: 92%;
overflow: hidden;
.nav_li {
display: inline-block;
height: $navHeight;
line-height: $navHeight;
}
}
.tag {
position: absolute;
right: 18rpx;
top: 1rpx;
font-size: 18px;
letter-spacing: 1px;
z-index: 9999;
}
&.nowrap {
white-space: initial;
height: initial;
.nav_ul {
height: initial;
overflow: initial;
}
.tag {
top: initial;
bottom: 22rpx;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 10px solid #8c8c8c;
}
}
// padding: 0 22rpx;
/* ::-webkit-scrollbar {
width: 4px !important;
height: 1px !important;
overflow: auto !important;
background: transparent !important;
-webkit-appearance: auto !important;
display: block;
} */
/* .item {
display: inline-block; // 设置为行内块
line-height: 95rpx;
padding: 0 22rpx;
} */
}
</style>
<template>
<!-- <scroll-view scroll-x class="nav_scroll"> -->
<div class="nav_scroll" :class="{ nowrap: tagValue === '' }">
<ul class="nav_ul">
<li class="nav_li" v-for="(item, index) in filterOptions" :key="index">
<date-time v-if="item.type === 'datetime'" :defaultTime="item.defaultTime" :label="item.label" @getDateTime="getDateTime" />
<select-picker
v-if="item.type === 'picker'"
@getPickerData="getPickerData"
:pickClass="item.pickClass"
:pickLabel="item.label"
:pickProps="item.props"
:pickerColumns="item.pickerColumns" />
</li>
</ul>
<b class="tag" @click="getMore">{{ tagValue }}</b>
</div>
<!-- </scroll-view> -->
<view style="position: absolute; right: 0; top: 0; background: #f7f8fa; height: 74rpx; width: 20rpx">
</view>
</template>
<script setup>
import SelectPicker from '@/components/form-picker/SelectPicker.vue'
import DateTime from '@/components/form-picker/DateTime.vue'
import { ref } from 'vue'
const emit = defineEmits(['getFormData'])
const props = defineProps({
filterOptions: Array
})
const formData = {}
const tagValue = ref('...')
const getMore = () => {
// console.log('12456')
switch (tagValue.value) {
case '':
tagValue.value = '...'
break
case '...':
tagValue.value = ''
break
}
}
const getDateTime = (val, mode) => {
// console.log(val, mode)
switch (mode) {
case '开始时间':
formData.startTime = val
break
case '结束时间':
formData.endTime = val
break
}
emit('getFormData', formData)
}
const getPickerData = (obj, mode, keyValue) => {
// console.log(obj, mode, keyValue)
formData[mode] = obj[keyValue]
emit('getFormData', formData)
}
</script>
<style scoped lang="scss">
$navHeight: 80rpx;
.nav_scroll {
position: relative;
white-space: nowrap;
height: 75rpx;
background: #f7f8fa;
.nav_ul {
height: $navHeight;
width: 92%;
overflow: hidden;
.nav_li {
display: inline-block;
height: $navHeight;
line-height: $navHeight;
}
}
.tag {
position: absolute;
right: 18rpx;
top: 1rpx;
font-size: 18px;
letter-spacing: 1px;
z-index: 9999;
}
&.nowrap {
white-space: initial;
height: initial;
.nav_ul {
height: initial;
overflow: initial;
}
.tag {
top: initial;
bottom: 22rpx;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 10px solid #8c8c8c;
}
}
// padding: 0 22rpx;
/* ::-webkit-scrollbar {
width: 4px !important;
height: 1px !important;
overflow: auto !important;
background: transparent !important;
-webkit-appearance: auto !important;
display: block;
} */
/* .item {
display: inline-block; // 设置为行内块
line-height: 95rpx;
padding: 0 22rpx;
} */
}
</style>
- DateTime.vue
vue
<template>
<input class="input_wrap" v-model="selectTime" @click="showDatetime = true" :disabled="true" :placeholder="label" />
<u-datetime-picker
:show="showDatetime"
v-model="timeDate"
mode="datetime"
@cancel="showDatetime = false"
@confirm="onConfirm"
:closeOnClickOverlay="true"
@close="showDatetime = false"></u-datetime-picker>
</template>
<script setup>
import { ref } from 'vue'
import dayjs from 'dayjs'
const props = defineProps({
label: {
type: String,
default: ''
},
formatTimeRule: {
type: String,
default: 'YYYY-MM-DD HH:mm:ss'
},
defaultTime: {
type: String,
default: ''
}
})
const emit = defineEmits(['getEndDateTime'])
const timeDate = ref(Date.now())
const showDatetime = ref(false)
const selectTime = ref(props.defaultTime)
const onConfirm = (e) => {
selectTime.value = selectTime.value = dayjs(e.value).format('YYYY-MM-DD HH:mm')
showDatetime.value = false
// console.log(selectTime.value)
emit('getDateTime', selectTime.value, props.label)
}
</script>
<style scoped lang="scss">
.input_wrap {
position: relative;
width: 263rpx;
display: inline-block;
line-height: 95rpx;
padding-right: 42rpx;
padding-left: 15rpx;
margin-right: 25rpx;
&:after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 10px;
height: 10px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #000;
}
}
</style>
<template>
<input class="input_wrap" v-model="selectTime" @click="showDatetime = true" :disabled="true" :placeholder="label" />
<u-datetime-picker
:show="showDatetime"
v-model="timeDate"
mode="datetime"
@cancel="showDatetime = false"
@confirm="onConfirm"
:closeOnClickOverlay="true"
@close="showDatetime = false"></u-datetime-picker>
</template>
<script setup>
import { ref } from 'vue'
import dayjs from 'dayjs'
const props = defineProps({
label: {
type: String,
default: ''
},
formatTimeRule: {
type: String,
default: 'YYYY-MM-DD HH:mm:ss'
},
defaultTime: {
type: String,
default: ''
}
})
const emit = defineEmits(['getEndDateTime'])
const timeDate = ref(Date.now())
const showDatetime = ref(false)
const selectTime = ref(props.defaultTime)
const onConfirm = (e) => {
selectTime.value = selectTime.value = dayjs(e.value).format('YYYY-MM-DD HH:mm')
showDatetime.value = false
// console.log(selectTime.value)
emit('getDateTime', selectTime.value, props.label)
}
</script>
<style scoped lang="scss">
.input_wrap {
position: relative;
width: 263rpx;
display: inline-block;
line-height: 95rpx;
padding-right: 42rpx;
padding-left: 15rpx;
margin-right: 25rpx;
&:after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 10px;
height: 10px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #000;
}
}
</style>
- SelectPicker.vue
vue
<template>
<input class="input_wrap" :class="pickClass" v-model="currentPicker" @click="setPickData(pickLabel)" :disabled="true" :placeholder="pickLabel" />
<u-picker
:show="showPicker"
:columns="pickerColumns"
:closeOnClickOverlay="true"
@close="showPicker = false"
@cancel="showPicker = false"
@confirm="onConfirm"
:keyName="keyName"
:keyValue="keyValue"></u-picker>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
pickLabel: String,
pickProps: String,
pickerColumns: {
type: Array,
default: () => []
},
keyName: {
type: String,
default: 'label'
},
keyValue: {
type: String,
default: 'value'
},
pickClass: {
type: String
}
})
const emit = defineEmits(['getPickerData'])
const showPicker = ref(false)
const currentPicker = ref('')
const setPickData = (mode) => {
// console.log(mode)
showPicker.value = true
}
const onConfirm = (e) => {
showPicker.value = false
// console.log(e.value[0])
currentPicker.value = e.value[0].label
emit('getPickerData', e.value[0], props.pickProps, props.keyValue)
}
</script>
<style scoped lang="scss">
.input_wrap {
position: relative;
width: 126rpx;
display: inline-block;
line-height: 95rpx;
padding-right: 85rpx;
padding-left: 15rpx;
margin-right: 60rpx;
@for $i from 80 through 126 {
&.wd#{$i} {
width: #{$i}rpx !important;
}
}
&:after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 10px;
height: 10px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #000;
}
}
</style>
<template>
<input class="input_wrap" :class="pickClass" v-model="currentPicker" @click="setPickData(pickLabel)" :disabled="true" :placeholder="pickLabel" />
<u-picker
:show="showPicker"
:columns="pickerColumns"
:closeOnClickOverlay="true"
@close="showPicker = false"
@cancel="showPicker = false"
@confirm="onConfirm"
:keyName="keyName"
:keyValue="keyValue"></u-picker>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
pickLabel: String,
pickProps: String,
pickerColumns: {
type: Array,
default: () => []
},
keyName: {
type: String,
default: 'label'
},
keyValue: {
type: String,
default: 'value'
},
pickClass: {
type: String
}
})
const emit = defineEmits(['getPickerData'])
const showPicker = ref(false)
const currentPicker = ref('')
const setPickData = (mode) => {
// console.log(mode)
showPicker.value = true
}
const onConfirm = (e) => {
showPicker.value = false
// console.log(e.value[0])
currentPicker.value = e.value[0].label
emit('getPickerData', e.value[0], props.pickProps, props.keyValue)
}
</script>
<style scoped lang="scss">
.input_wrap {
position: relative;
width: 126rpx;
display: inline-block;
line-height: 95rpx;
padding-right: 85rpx;
padding-left: 15rpx;
margin-right: 60rpx;
@for $i from 80 through 126 {
&.wd#{$i} {
width: #{$i}rpx !important;
}
}
&:after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 10px;
height: 10px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #000;
}
}
</style>
uniapp校验
vue
<template>
<u-modal :show="modalShow" :title="taskTitle" @confirm="submit" @cancel="modalShow = false" :showCancelButton="true">
<u--form labelPosition="left" :model="formData" ref="refUForm" labelWidth="100" :rules="rules">
<u-form-item prop="cancelRemark" label="作废备注" v-if="taskTitle === 'zf'">
<u--input
placeholder="请输入"
type="textarea"
height="100rpx"
auto-height="true"
v-model="formData.cancelRemark"
:border="true"
border-color="black"></u--input>
</u-form-item>
<u-form-item prop="abnormalCause" label="异常原因" v-if="taskTitle === 'cdk'">
<u--input
placeholder="请输入"
type="textarea"
height="100rpx"
auto-height="true"
v-model="formData.abnormalCause"
:border="true"
border-color="black"></u--input>
</u-form-item>
<u-form-item prop="handlerRemark" label="处理备注" v-if="taskTitle === 'cdk'">
<u--input
placeholder="请输入"
type="textarea"
height="100rpx"
auto-height="true"
v-model="formData.handlerRemark"
:border="true"
border-color="black"></u--input>
</u-form-item>
</u--form>
</u-modal>
</template>
<script setup name="process">
import { ref } from 'vue'
import { http } from '@/api/index.js'
// import { getStorage } from '@/utils/storage'
const emit = defineEmits(['dialogClosed'])
const dialogClosed = () => {
emit('dialogClosed')
}
const refUForm = ref(null)
const modalShow = ref(false)
const taskTitle = ref('')
const formData = ref({
cancelRemark: '',
abnormalCause: '',
handlerRemark: ''
})
const rules = ref({
cancelRemark: {
type: 'string',
required: true,
message: '请填写',
trigger: ['blur', 'change']
},
abnormalCause: {
type: 'string',
required: true,
message: '请填写',
trigger: ['blur', 'change']
},
handlerRemark: {
type: 'string',
required: true,
message: '请填写',
trigger: ['blur', 'change']
}
})
const showModal = (id, mode) => {
// console.log(id, mode)
modalShow.value = true
taskTitle.value = mode
formData.value = {
id
}
}
const submit = () => {
refUForm.value
.validate()
.then((res) => {
// console.log(res)
setTaskComfirm()
})
.catch((errors) => {
console.log(errors)
// uni.$u.toast('校验失败')
})
}
const setTaskComfirm = async () => {
let apiName = ref('')
switch (taskTitle.value) {
case 'zf':
apiName.value = 'cancellationAuditTaskResult'
break
case 'cdk':
apiName.value = 'disposeAuditTaskResult'
break
default:
break
}
const params = {
...formData.value
}
// console.log(params)
uni.showToast({
title: '操作成功',
icon: 'none'
})
// modalShow.value = false
try {
let res = await http(apiName.value, params)
if (res.isError) return showReqError(res)
uni.showToast({
title: '操作成功',
icon: 'none'
})
modalShow.value = false
dialogClosed()
} catch (error) {
console.log(error)
}
}
defineExpose({ showModal })
</script>
<style scoped lang="scss">
.btn {
width: 120rpx;
height: 60rpx;
background: #c3a767;
border-radius: 40rpx;
color: #ffffff;
font-weight: bold;
font-size: 24rpx;
}
</style>
<template>
<u-modal :show="modalShow" :title="taskTitle" @confirm="submit" @cancel="modalShow = false" :showCancelButton="true">
<u--form labelPosition="left" :model="formData" ref="refUForm" labelWidth="100" :rules="rules">
<u-form-item prop="cancelRemark" label="作废备注" v-if="taskTitle === 'zf'">
<u--input
placeholder="请输入"
type="textarea"
height="100rpx"
auto-height="true"
v-model="formData.cancelRemark"
:border="true"
border-color="black"></u--input>
</u-form-item>
<u-form-item prop="abnormalCause" label="异常原因" v-if="taskTitle === 'cdk'">
<u--input
placeholder="请输入"
type="textarea"
height="100rpx"
auto-height="true"
v-model="formData.abnormalCause"
:border="true"
border-color="black"></u--input>
</u-form-item>
<u-form-item prop="handlerRemark" label="处理备注" v-if="taskTitle === 'cdk'">
<u--input
placeholder="请输入"
type="textarea"
height="100rpx"
auto-height="true"
v-model="formData.handlerRemark"
:border="true"
border-color="black"></u--input>
</u-form-item>
</u--form>
</u-modal>
</template>
<script setup name="process">
import { ref } from 'vue'
import { http } from '@/api/index.js'
// import { getStorage } from '@/utils/storage'
const emit = defineEmits(['dialogClosed'])
const dialogClosed = () => {
emit('dialogClosed')
}
const refUForm = ref(null)
const modalShow = ref(false)
const taskTitle = ref('')
const formData = ref({
cancelRemark: '',
abnormalCause: '',
handlerRemark: ''
})
const rules = ref({
cancelRemark: {
type: 'string',
required: true,
message: '请填写',
trigger: ['blur', 'change']
},
abnormalCause: {
type: 'string',
required: true,
message: '请填写',
trigger: ['blur', 'change']
},
handlerRemark: {
type: 'string',
required: true,
message: '请填写',
trigger: ['blur', 'change']
}
})
const showModal = (id, mode) => {
// console.log(id, mode)
modalShow.value = true
taskTitle.value = mode
formData.value = {
id
}
}
const submit = () => {
refUForm.value
.validate()
.then((res) => {
// console.log(res)
setTaskComfirm()
})
.catch((errors) => {
console.log(errors)
// uni.$u.toast('校验失败')
})
}
const setTaskComfirm = async () => {
let apiName = ref('')
switch (taskTitle.value) {
case 'zf':
apiName.value = 'cancellationAuditTaskResult'
break
case 'cdk':
apiName.value = 'disposeAuditTaskResult'
break
default:
break
}
const params = {
...formData.value
}
// console.log(params)
uni.showToast({
title: '操作成功',
icon: 'none'
})
// modalShow.value = false
try {
let res = await http(apiName.value, params)
if (res.isError) return showReqError(res)
uni.showToast({
title: '操作成功',
icon: 'none'
})
modalShow.value = false
dialogClosed()
} catch (error) {
console.log(error)
}
}
defineExpose({ showModal })
</script>
<style scoped lang="scss">
.btn {
width: 120rpx;
height: 60rpx;
background: #c3a767;
border-radius: 40rpx;
color: #ffffff;
font-weight: bold;
font-size: 24rpx;
}
</style>