提交 8b5ae6f8 编写于 作者: inkwalk's avatar inkwalk

merge for sync to dev

...@@ -61,19 +61,19 @@ npm run dev:h5 ...@@ -61,19 +61,19 @@ npm run dev:h5
<div style="display: flex;"> <div style="display: flex;">
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box"> <div class="barcode-img-box">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/uni-android.png" width="160" /> <img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/ba7d0750-517d-11eb-bdc1-8bd33eb6adaa.png" width="160" />
</div> </div>
<b>Android版</b> <b>Android版</b>
</a> </a>
<a href="https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8" target="_blank" class="clear-style barcode-view"> <a href="https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box"> <div class="barcode-img-box">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/uni-ios.png" width="160" /> <img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/bb3ef7c0-517d-11eb-bdc1-8bd33eb6adaa.png" width="160" />
</div> </div>
<b>iOS版</b> <b>iOS版</b>
</a> </a>
<a href="https://hellouniapp.dcloud.net.cn/" target="_blank" class="clear-style barcode-view"> <a href="https://hellouniapp.dcloud.net.cn/" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box"> <div class="barcode-img-box">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/uni-h5.png" width="160" /> <img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/bb3ef7c0-517d-11eb-bdc1-8bd33eb6adaa.png" width="160" />
</div> </div>
<b>H5版</b> <b>H5版</b>
</a> </a>
...@@ -82,13 +82,13 @@ npm run dev:h5 ...@@ -82,13 +82,13 @@ npm run dev:h5
<b>微信小程序版</b> <b>微信小程序版</b>
</a> </a>
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box"><img src="https://img-cdn-qiniu.dcloud.net.cn/img/alipay1.png" width="160" /></div> <div class="barcode-img-box"><img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/b131e0d0-517d-11eb-a16f-5b3e54966275.png" width="160" /></div>
<b>支付宝小程序版</b> <b>支付宝小程序版</b>
</a> </a>
</div> </div>
<div class="flex-img-group-view" style="margin-top: 20px;"> <div class="flex-img-group-view" style="margin-top: 20px;">
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box"><img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/baidu-uniapp.png" width="160" /></div> <div class="barcode-img-box"><img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/b204e840-517d-11eb-8ff1-d5dcf8779628.png" width="160" /></div>
<b>百度小程序版</b> <b>百度小程序版</b>
</a> </a>
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view">
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
* @property {Boolean} isFull = [true | false] 卡片内容是否通栏,为 true 时将去除padding值 * @property {Boolean} isFull = [true | false] 卡片内容是否通栏,为 true 时将去除padding值
* @property {Boolean} isShadow = [true | false] 卡片内容是否开启阴影 * @property {Boolean} isShadow = [true | false] 卡片内容是否开启阴影
* @event {Function} click 点击 Card 触发事件 * @event {Function} click 点击 Card 触发事件
* @example <uni-card title="标题文字" thumbnail="https://img-cdn-qiniu.dcloud.net.cn/new-page/uni.png" extra="额外信息" note="Tips">内容主体,可自定义内容及样式</uni-card> * @example <uni-card title="标题文字" thumbnail="xxx.jpg" extra="额外信息" note="Tips">内容主体,可自定义内容及样式</uni-card>
*/ */
export default { export default {
name: 'UniCard', name: 'UniCard',
......
此差异已折叠。
const events = {
load: 'load',
error: 'error'
}
const pageMode = {
add: 'add',
replace: 'replace'
}
const attrs = [
'pageCurrent',
'pageSize',
'collection',
'action',
'field',
'getcount',
'orderby',
'where'
]
export default {
props: {
collection: {
type: String,
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
getone: {
type: [Boolean, String],
default: false
},
manual: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
listData: this.getone ? {} : [],
paginationInternal: {
current: this.pageCurrent,
size: this.pageSize,
count: 0
},
errorMessage: ''
}
},
created() {
let db = null;
let dbCmd = null;
if(this.collection){
this.db = uniCloud.database();
this.dbCmd = this.db.command;
}
this._isEnded = false
this.$watch(() => {
var al = []
attrs.forEach(key => {
al.push(this[key])
})
return al
}, (newValue, oldValue) => {
this.paginationInternal.pageSize = this.pageSize
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] != oldValue[i]) {
needReset = true
break
}
}
if (needReset) {
this.clear()
this.reset()
}
if (newValue[0] != oldValue[0]) {
this.paginationInternal.current = this.pageCurrent
}
this._execLoadData()
})
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList = []
if (!window.unidev) {
window.unidev = {
clientDB: {
data: []
}
}
}
unidev.clientDB.data.push(this._debugDataList)
}
// #endif
// #ifdef MP-TOUTIAO
let changeName
let events = this.$scope.dataset.eventOpts
for (var i = 0; i < events.length; i++) {
let event = events[i]
if (event[0].includes('^load')) {
changeName = event[1][0][0]
}
}
if (changeName) {
let parent = this.$parent
let maxDepth = 16
this._changeDataFunction = null
while (parent && maxDepth > 0) {
let fun = parent[changeName]
if (fun && typeof fun === 'function') {
this._changeDataFunction = fun
maxDepth = 0
break
}
parent = parent.$parent
maxDepth--;
}
}
// #endif
// if (!this.manual) {
// this.loadData()
// }
},
// #ifdef H5
beforeDestroy() {
if (process.env.NODE_ENV === 'development' && window.unidev) {
var cd = this._debugDataList
var dl = unidev.clientDB.data
for (var i = dl.length - 1; i >= 0; i--) {
if (dl[i] === cd) {
dl.splice(i, 1)
break
}
}
}
},
// #endif
methods: {
loadData(args1, args2) {
let callback = null
if (typeof args1 === 'object') {
if (args1.clear) {
this.clear()
this.reset()
}
if (args1.current !== undefined) {
this.paginationInternal.current = args1.current
}
if (typeof args2 === 'function') {
callback = args2
}
} else if (typeof args1 === 'function') {
callback = args1
}
this._execLoadData(callback)
},
loadMore() {
if (this._isEnded) {
return
}
this._execLoadData()
},
refresh() {
this.clear()
this._execLoadData()
},
clear() {
this._isEnded = false
this.listData = []
},
reset() {
this.paginationInternal.current = 1
},
remove(id, {
action,
callback,
confirmTitle,
confirmContent
} = {}) {
if (!id || !id.length) {
return
}
uni.showModal({
title: confirmTitle || '提示',
content: confirmContent || '是否删除该数据',
showCancel: true,
success: (res) => {
if (!res.confirm) {
return
}
this._execRemove(id, action, callback)
}
})
},
_execLoadData(callback) {
if (this.loading) {
return
}
this.loading = true
this.errorMessage = ''
this._getExec().then((res) => {
this.loading = false
const {
data,
count
} = res.result
this._isEnded = data.length < this.pageSize
callback && callback(data, this._isEnded)
this._dispatchEvent(events.load, data)
if (this.getone) {
this.listData = data.length ? data[0] : undefined
} else if (this.pageData === pageMode.add) {
this.listData.push(...data)
if (this.listData.length) {
this.paginationInternal.current++
}
} else if (this.pageData === pageMode.replace) {
this.listData = data
this.paginationInternal.count = count
}
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList.length = 0
this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData)))
}
// #endif
}).catch((err) => {
this.loading = false
this.errorMessage = err
callback && callback()
this.$emit(events.error, err)
})
},
_getExec() {
let exec = this.db
if (this.action) {
exec = exec.action(this.action)
}
exec = exec.collection(this.collection)
if (!(!this.where || !Object.keys(this.where).length)) {
exec = exec.where(this.where)
}
if (this.field) {
exec = exec.field(this.field)
}
if (this.orderby) {
exec = exec.orderBy(this.orderby)
}
const {
current,
size
} = this.paginationInternal
exec = exec.skip(size * (current - 1)).limit(size).get({
getCount: this.getcount
})
return exec
},
_execRemove(id, action, callback) {
if (!this.collection || !id) {
return
}
const ids = Array.isArray(id) ? id : [id]
if (!ids.length) {
return
}
uni.showLoading({
mask: true
})
let exec = this.db
if (action) {
exec = exec.action(action)
}
exec.collection(this.collection).where({
_id: dbCmd.in(ids)
}).remove().then((res) => {
callback && callback(res.result)
if (this.pageData === pageMode.replace) {
this.refresh()
} else {
this.removeData(ids)
}
}).catch((err) => {
uni.showModal({
content: err.message,
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
removeData(ids) {
let il = ids.slice(0)
let dl = this.listData
for (let i = dl.length - 1; i >= 0; i--) {
let index = il.indexOf(dl[i]._id)
if (index >= 0) {
dl.splice(i, 1)
il.splice(index, 1)
}
}
},
_dispatchEvent(type, data) {
if (this._changeDataFunction) {
this._changeDataFunction(data, this._isEnded)
} else {
this.$emit(type, data, this._isEnded)
}
}
}
}
<template>
<view>
<view v-if="loaded || list.itemIndex < 15" class="uni-indexed-list__title-wrapper">
<text v-if="list.items && list.items.length > 0" class="uni-indexed-list__title">{{ list.title }}</text>
</view>
<view v-if="(loaded || list.itemIndex < 15) && list.items && list.items.length > 0" class="uni-indexed-list__list">
<view v-for="(item, index) in list.items" :key="index" class="uni-indexed-list__item" hover-class="uni-indexed-list__item--hover">
<view class="uni-indexed-list__item-container" @click="onClick(idx, index)">
<view class="uni-indexed-list__item-border" :class="{'uni-indexed-list__item-border--last':index===list.items.length-1}">
<view v-if="showSelect" style="margin-right: 20rpx;">
<uni-icons :type="item.checked ? 'checkbox-filled' : 'circle'" :color="item.checked ? '#007aff' : '#aaa'" size="24" />
</view>
<text class="uni-indexed-list__item-content">{{ item.text }}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import uniIcons from '../uni-icons/uni-icons.vue'
export default {
name: 'UniIndexedList',
components: {
uniIcons
},
props: {
loaded: {
type: Boolean,
default: false
},
idx: {
type: Number,
default: 0
},
list: {
type: Object,
default () {
return {}
}
},
showSelect: {
type: Boolean,
default: false
}
},
methods: {
onClick(idx, index) {
this.$emit("itemClick", {
idx,
index
})
}
}
}
</script>
<style scoped>
.uni-indexed-list__list {
background-color: #ffffff;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
border-top-style: solid;
border-top-width: 1px;
border-top-color: #e5e5e5;
}
.uni-indexed-list__item {
font-size: 16px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.uni-indexed-list__item-container {
padding-left: 15px;
flex: 1;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.uni-indexed-list__item-border {
flex: 1;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 50px;
padding: 15px;
padding-left: 0;
border-bottom-style: solid;
border-bottom-width: 1px;
border-bottom-color: #e5e5e5;
}
.uni-indexed-list__item-border--last {
border-bottom-width: 0px;
}
.uni-indexed-list__item-content {
flex: 1;
font-size: 14px;
}
.uni-indexed-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-indexed-list__title-wrapper {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
/* #endif */
background-color: #f7f7f7;
}
.uni-indexed-list__title {
padding: 6px 12px;
line-height: 24px;
font-size: 12px;
}
</style>
\ No newline at end of file
<template>
<view class="uni-indexed-list" ref="list" id="list">
<!-- #ifdef APP-NVUE -->
<list class="uni-indexed-list__scroll" scrollable="true" show-scrollbar="false">
<cell v-for="(list, idx) in lists" :key="idx" :ref="'uni-indexed-list-' + idx">
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<scroll-view :scroll-into-view="scrollViewId" class="uni-indexed-list__scroll" scroll-y>
<view v-for="(list, idx) in lists" :key="idx" :id="'uni-indexed-list-' + idx">
<!-- #endif -->
<uni-indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect" @itemClick="onClick"></uni-indexed-list-item>
<!-- #ifndef APP-NVUE -->
</view>
</scroll-view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
</cell>
</list>
<!-- #endif -->
<view :class="touchmove ? 'uni-indexed-list__menu--active' : ''" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd" class="uni-indexed-list__menu">
<view v-for="(list, key) in lists" :key="key" class="uni-indexed-list__menu-item">
<text class="uni-indexed-list__menu-text" :class="touchmoveIndex == key ? 'uni-indexed-list__menu-text--active' : ''">{{ list.value }}</text>
</view>
</view>
<view v-if="touchmove" class="uni-indexed-list__alert-wrapper">
<text class="uni-indexed-list__alert">{{ lists[touchmoveIndex] }}</text>
</view>
</view>
</template>
<script>
import uniIcons from '../uni-icons/uni-icons.vue'
import uniIndexedListItem from './uni-data-indexed-list-item.vue'
import clientdb from './clientdb.js'
// #ifdef APP-NVUE
const dom = weex.requireModule('dom');
// #endif
// #ifdef APP-PLUS
function throttle(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function touchMove(e) {
let pageY = e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
if (this.touchmoveIndex === index) {
return false
}
let item = this.lists[index]
if (item) {
// #ifndef APP-NVUE
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
// #endif
// #ifdef APP-NVUE
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], {
animated: false
})
this.touchmoveIndex = index
// #endif
}
}
const throttleTouchMove = throttle(touchMove, 40)
// #endif
/**
* IndexedList 索引列表
* @description 用于展示索引列表
* @tutorial https://ext.dcloud.net.cn/plugin?id=375
* @property {Boolean} showSelect = [true|false] 展示模式
* @value true 展示模式
* @value false 选择模式
* @property {Object} options 索引列表需要的数据对象
* @property {String|DBCollectionString} collection 表名
* @property {String|ClientDBActionString} action 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
* @event {Function} click 点击列表事件 ,返回当前选择项的事件对象
* @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list>
*/
export default {
name: 'UniDataIndexedList',
mixins: [clientdb],
components: {
uniIcons,
uniIndexedListItem
},
props: {
options: {
type: Array,
default () {
return []
}
},
localdata: {
type: Array,
default () {
return []
}
},
showSelect: {
type: Boolean,
default: false
}
},
data() {
return {
lists: [],
winHeight: 0,
itemHeight: 0,
winOffsetY: 0,
touchmove: false,
touchmoveIndex: -1,
scrollViewId: '',
touchmoveTimeout: '',
loaded: false
}
},
watch: {
options: {
handler: function() {
this.setList()
},
deep: true
}
},
mounted() {
if (this.localdata.length || this.options.length) {
setTimeout(() => {
this.setList()
}, 50)
setTimeout(() => {
this.loaded = true
}, 300);
} else if (this.collection) {
if (!this.manual) {
this._execLoadData((data) => {
this.lists = this.groupData(data);
})
}
}
},
methods: {
groupData(data) {
let groups = {};
for (let i = 0; i < data.length; i++) {
let item = data[i];
let group = item.group;
if (!groups[group]) {
groups[group] = {
"title": group,
"value": group,
"itemIndex": i,
"items": []
}
}
groups[group].items.push(item);
}
let result = []
for (let g in groups) {
let group = groups[g];
let items = group.items;
for (let j = 0; j < items.length; j++) {
items[j].itemIndex = j;
}
result.push(group);
}
return result;
},
setList(data) {
let index = 0;
this.lists = []
this.options.forEach((value, index) => {
if (value.data.length === 0) {
return
}
let indexBefore = index
let items = value.data.map(item => {
let obj = {}
obj['value'] = value.letter
obj['text'] = item
obj['itemIndex'] = index
index++
obj.checked = item.checked ? item.checked : false
return obj
})
this.lists.push({
title: value.letter,
value: value.letter,
items: items,
itemIndex: indexBefore
})
})
// #ifndef APP-NVUE
uni.createSelectorQuery()
.in(this)
.select('#list')
.boundingClientRect()
.exec(ret => {
this.winOffsetY = ret[0].top
this.winHeight = ret[0].height
this.itemHeight = this.winHeight / this.lists.length
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['list'], (res) => {
this.winOffsetY = res.size.top
this.winHeight = res.size.height
this.itemHeight = this.winHeight / this.lists.length
})
// #endif
},
touchStart(e) {
this.touchmove = true
let pageY = e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
let item = this.lists[index]
if (item) {
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
// #ifdef APP-NVUE
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], {
animated: false
})
// #endif
}
},
touchMove(e) {
// #ifndef APP-PLUS
let pageY = e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
if (this.touchmoveIndex === index) {
return false
}
let item = this.lists[index]
if (item) {
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
}
// #endif
// #ifdef APP-PLUS
throttleTouchMove.call(this, e)
// #endif
},
touchEnd() {
this.touchmove = false
this.touchmoveIndex = -1
},
onClick(e) {
let {
idx,
index
} = e
let obj = {}
for (let key in this.lists[idx].items[index]) {
obj[key] = this.lists[idx].items[index][key]
}
let select = []
if (this.showSelect) {
this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked
this.lists.forEach((value, idx) => {
value.items.forEach((item, index) => {
if (item.checked) {
let obj = {}
for (let key in this.lists[idx].items[index]) {
obj[key] = this.lists[idx].items[index][key]
}
select.push(obj)
}
})
})
}
this.$emit('click', {
item: obj,
select: select
})
}
}
}
</script>
<style scoped>
.uni-indexed-list {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-indexed-list__scroll {
flex: 1;
}
.uni-indexed-list__menu {
width: 24px;
background-color: lightgrey;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-indexed-list__menu-item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
align-items: center;
justify-content: center;
}
.uni-indexed-list__menu-text {
line-height: 20px;
font-size: 12px;
text-align: center;
color: #aaa;
}
.uni-indexed-list__menu--active {
background-color: #c8c8c8;
}
.uni-indexed-list__menu-text--active {
color: #007aff;
}
.uni-indexed-list__alert-wrapper {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
}
.uni-indexed-list__alert {
width: 80px;
height: 80px;
border-radius: 80px;
text-align: center;
line-height: 80px;
font-size: 35px;
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
}
</style>
\ No newline at end of file
<template>
<view class="uni-data-tree">
<view class="uni-data-tree-input" @click="handleInput">
<slot :options="options" :data="inputSelected" :error="errorMessage">
<!-- <view class="input-value">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view> -->
<view v-if="errorMessage" class="input-value">
<text class="error-text">{{errorMessage}}</text>
</view>
<view v-else-if="loading && !isOpened" class="input-value">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view v-else-if="inputSelected.length" class="input-value">
<view v-for="(item,index) in inputSelected" :key="index" class="input-value-item">
<text>{{item.text}}</text><text v-if="index<inputSelected.length-1" class="input-split-line">/</text>
</view>
</view>
<view v-else class="input-value placeholder">
<text>{{placeholder}}</text>
</view>
</slot>
</view>
<view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
<view class="uni-data-tree-dialog" v-if="isOpened">
<view class="dialog-caption">
<view class="title-area">
<text class="title">{{popupTitle}}</text>
</view>
<view class="dialog-close" @click="handleClose">
<view class="dialog-close-plus" data-id="close"></view>
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
</view>
</view>
<data-picker-view class="picker-view" ref="pickerView" v-model="value" :localdata="localdata" :preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where" :step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" @change="onchange" @datachange="ondatachange"></data-picker-view>
</view>
</view>
</template>
<script>
import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
/**
* uni-data-picker
* @description uni-data-picker
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-data-picker
* @property {String} title 弹出窗口标题
* @property {Array} localdata 本地数据,参考
* @property {Boolean} preload = [true|false] 是否预加载数据
* @value true 开启预加载数据,点击弹出窗口后显示已加载数据
* @value false 关闭预加载数据,点击弹出窗口后开始加载数据
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询,仅查询当前选中节点
* @value false 关闭分布查询,一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {Boolean} array2tree = [true|false] 是否查询出树结构数据
* @value true
* @value false
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
* @event {Function} onpopupshow 弹出的选择窗口打开时触发此事件
* @event {Function} onpopuphide 弹出的选择窗口关闭时触发此事件
*/
export default {
name: 'UniDataPicker',
mixins: [dataPicker],
components: {
DataPickerView
},
props: {
popupTitle: {
type: String,
default: '请选择'
},
placeholder: {
type: String,
default: '请选择'
},
options: {
type: [Object, Array],
default () {
return {}
}
}
},
data() {
return {
isOpened: false,
inputSelected: []
}
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
this.$nextTick(() => {
this.load()
})
},
methods: {
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.isLocaldata) {
this.loadData()
this.inputSelected = this.selected.slice(0)
} else if (this.value.length) {
this.getTreePath(() => {
this.inputSelected = this.selected.slice(0)
})
}
},
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
},
show() {
this.isOpened = true
this.$nextTick(() => {
this.$refs.pickerView.updateData({
treeData: this._treeData,
selected: this.selected,
selectedIndex: this.selectedIndex
})
})
},
hide() {
this.isOpened = false
},
handleInput() {
this.show()
},
handleClose(e) {
this.hide()
},
ondatachange(e) {
this._treeData = this.$refs.pickerView._treeData
},
onchange(e) {
this.hide()
this.inputSelected = e
this._dispatchEvent(e)
},
_dispatchEvent(selected) {
var value = new Array(selected.length)
for (var i = 0; i < selected.length; i++) {
value[i] = selected[i].value
}
if (this.formItem) {
const v = value[value.length - 1]
this.formItem.setValue(v)
}
this.$emit('change', value)
}
}
}
</script>
<style scoped>
.uni-data-tree {
position: relative;
font-size: 14px;
}
.error-text {
color: #DD524D;
}
.loading-cover {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.5);
display: flex;
flex-direction: column;
align-items: center;
z-index: 101;
}
.input-value {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
font-size: 14px;
line-height: 38px;
border: 1px #e5e5e5 solid;
border-radius: 5px;
padding: 0 5px;
}
.input-value-item {
padding: 0 1px;
}
.placeholder {
opacity: .5;
}
.input-split-line {
opacity: .5;
}
.uni-data-tree-cover {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: column;
z-index: 100;
}
.uni-data-tree-dialog {
position: fixed;
left: 0;
top: auto;
right: 0;
bottom: 0;
height: 80vh;
background-color: #FFFFFF;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
display: flex;
flex-direction: column;
z-index: 102;
}
.dialog-caption {
position: relative;
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
}
.title-area {
display: flex;
align-items: center;
margin: auto;
padding: 0 10px;
}
.title {
font-weight: bold;
line-height: 44px;
}
.dialog-close {
position: absolute;
top: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
padding: 0 15px;
}
.dialog-close-plus {
width: 16px;
height: 2px;
background-color: #666;
border-radius: 2px;
transform: rotate(45deg);
}
.dialog-close-rotate {
position: absolute;
transform: rotate(-45deg);
}
/* #ifdef H5 */
@media all and (min-width: 768px) {
.uni-data-tree-cover {
background-color: transparent;
}
.uni-data-tree-dialog {
position: absolute;
top: 100%;
height: auto;
min-height: 400px;
max-height: 50vh;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 20px 5px rgba(0, 0, 0, 0.3);
}
.dialog-caption {
display: none;
}
}
/* #endif */
</style>
\ No newline at end of file
export default {
props: {
localdata: {
type: Array,
default () {
return []
}
},
collection: {
type: String,
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
getone: {
type: [Boolean, String],
default: false
},
gettree: {
type: [Boolean, String],
default: false
},
manual: {
type: Boolean,
default: false
},
value: {
type: [Array, String, Number],
default () {
return []
}
},
preload: {
type: Boolean,
default: false
},
stepSearh: {
type: Boolean,
default: true
},
selfField: {
type: String,
default: ''
},
parentField: {
type: String,
default: ''
}
},
data() {
return {
loading: false,
errorMessage: '',
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
},
dataList: [],
selected: [],
selectedIndex: 0,
page: {
current: this.pageCurrent,
size: this.pageSize,
count: 0
}
}
},
computed: {
isLocaldata() {
return this.localdata.length > 0
},
postField() {
return `${this.field}, ${this.parentField} as parent_value`
},
postWhere() {
let result = []
let selected = this.selected
result.push(`${this.parentField} == null`)
if (selected.length) {
for (var i = 0; i < selected.length - 1; i++) {
result.push(`${this.parentField} == '${selected[i].value}'`)
}
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
nodeWhere() {
let result = []
let selected = this.selected
if (selected.length) {
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
formatValue(value) {
var dl = new Array(value.length)
for (let i = 0; i < dl.length; i++) {
dl[i] = value[i].value
}
this._value = dl
}
},
created() {
this.$watch(() => {
var al = [];
['pageCurrent',
'pageSize',
'value',
'localdata',
'collection',
'action',
'field',
'orderby',
'where',
'getont',
'getcount',
'gettree'
].forEach(key => {
al.push(this[key])
});
return al
}, (newValue, oldValue) => {
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] != oldValue[i]) {
needReset = true
break
}
}
if (newValue[0] != oldValue[0]) {
this.page.current = this.pageCurrent
}
this.page.size = this.pageSize
this.onPropsChange()
})
this._treeData = []
},
methods: {
onPropsChange() {
this._treeData = []
},
getCommand(options = {}) {
/* eslint-disable no-undef */
let db = uniCloud.database()
const action = options.action || this.action
if (action) {
db = db.action(action)
}
const collection = options.collection || this.collection
db = db.collection(collection)
const where = options.where || this.where
if (!(!where || !Object.keys(where).length)) {
db = db.where(where)
}
const field = options.field || this.field
if (field) {
db = db.field(field)
}
const orderby = options.orderby || this.orderby
if (orderby) {
db = db.orderBy(orderby)
}
const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
const size = options.pageSize !== undefined ? options.pageSize : this.page.size
const getCount = options.getcount !== undefined ? options.getcount : this.getcount
const getTree = options.gettree !== undefined ? options.gettree : this.gettree
const getOptions = {
getCount,
getTree
}
if (options.getTreePath) {
getOptions.getTreePath = options.getTreePath
}
db = db.skip(size * (current - 1)).limit(size).get(getOptions)
return db
},
getTreePath(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
getTreePath: {
startWith: `${this.selfField}=='${this.value}'`
}
}).then((res) => {
this.loading = false
let treePath = []
this._extractTreePath(res.result.data, treePath)
this.selected = treePath
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
loadData() {
if (this.isLocaldata) {
this._processLocalData()
return
}
if (this.value.length) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
this._updateSelected()
})
return
}
if (this.stepSearh) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
})
} else {
this._loadAllData((data) => {
this._treeData = []
this._extractTree(data, this._treeData, null)
this._updateBindData()
})
}
},
_loadAllData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
gettree: true,
startwith: `${this.selfField}=='${this.value}'`
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_loadNodeData(callback, pw) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: pw || this.postWhere,
pageSize: 500
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_updateSelected() {
var dl = this.dataList
var sl = this.selected
for (var i = 0; i < sl.length; i++) {
var value = sl[i].value
var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j]
if (item2.value === value) {
sl[i].text = item2.text
break
}
}
}
},
_updateBindData(node) {
const {
dataList,
hasNodes
} = this._filterData(this._treeData, this.selected)
let isLeaf = this._stepSearh === false && !hasNodes
if (node) {
node.isLeaf = isLeaf
}
this.dataList = dataList
this.selectedIndex = dataList.length - 1
if (!isLeaf && this.selected.length < dataList.length) {
this.selected.push({
value: null,
text: "请选择"
})
}
return {
isLeaf,
hasNodes
}
},
_filterData(data, paths) {
let dataList = []
let hasNodes = true
dataList.push(data.filter((item) => {
return item.parent_value === undefined
}))
for (let i = 0; i < paths.length; i++) {
var value = paths[i].value
var nodes = data.filter((item) => {
return item.parent_value === value
})
if (nodes.length) {
dataList.push(nodes)
} else {
hasNodes = false
}
}
return {
dataList,
hasNodes
}
},
_extractTree(nodes, result, parent_value) {
let list = result || []
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let child = {}
for (let key in node) {
if (key !== 'children') {
child[key] = node[key]
}
}
if (parent_value !== null) {
child.parent_value = parent_value
}
result.push(child)
let children = node.children
if (children) {
this._extractTree(children, result, node.value)
}
}
},
_extractTreePath(nodes, result) {
let list = result || []
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let child = {}
for (let key in node) {
if (key !== 'children') {
child[key] = node[key]
}
}
result.push(child)
let children = node.children
if (children) {
this._extractTreePath(children, result)
}
}
},
_findNodePath(key, nodes, path) {
for (let i = 0; i < nodes.length; i++) {
let {
value,
text,
children
} = nodes[i]
path.push({
value,
text
})
if (value === key) {
break;
}
if (children) {
this._findNodePath(key, children, path)
} else {
path.pop()
}
}
},
_processLocalData() {
this._treeData = []
this._extractTree(this.localdata, this._treeData)
var inputValue = this.value
if (!inputValue || !inputValue.length) {
return
}
if (typeof inputValue === "string") {
let nodePath = []
this._findNodePath(inputValue, this.localdata, nodePath)
this.selected = nodePath
} else {
let selected = new Array(inputValue.length)
for (var i = 0; i < inputValue.length; i++) {
selected[i] = {
value: inputValue[i]
}
}
this.selected = selected
}
//this._updateBindData()
}
}
}
<template>
<view class="uni-data-pickerview">
<scroll-view class="selected-area" scroll-x="true">
<view class="selected-list">
<view class="selected-item" :class="{'selected-item-active':index==selectedIndex}" v-for="(item,index) in selected" :key="index" v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
</view>
</view>
</scroll-view>
<view class="tab-c">
<scroll-view class="list" v-for="(child, i) in dataList" :key="i" v-if="i==selectedIndex" scroll-y="false">
<view class="item" v-for="(item, j) in child" :key="j" @click="handleNodeClick(i, j)">
<text class="item-text">{{item.text}}</text>
<view class="check" v-if="selected.length > i && item.value == selected[i].value"></view>
</view>
</scroll-view>
<view class="loading-cover" v-if="loading">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view class="error-message" v-if="errorMessage">
<text class="error-text">{{errorMessage}}</text>
</view>
</view>
</view>
</template>
<script>
import dataPicker from "./uni-data-picker.js"
/**
* uni-data-pickerview
* @description uni-data-pickerview
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-data-picker
* @property {Array} localdata 本地数据,参考
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询,仅查询当前选中节点
* @value false 关闭分布查询,一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
*/
export default {
name: 'UniDataPickerView',
mixins: [dataPicker],
props: {
managedMode: {
type: Boolean,
default: false
}
},
data() {
return {}
},
created() {
if (this.managedMode) {
return
}
this.$nextTick(() => {
this.load()
})
},
methods: {
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.isLocaldata) {
this.loadData()
} else if (this.value.length) {
this.getTreePath((res) => {
this.loadData()
})
}
},
handleSelect(index) {
this.selectedIndex = index
},
handleNodeClick(i, j) {
const node = this.dataList[i][j]
const {
value,
text
} = node
if (i < this.selected.length - 1) {
this.selected.splice(i, this.selected.length - i)
this.selected.push(node)
} else if (i === this.selected.length - 1) {
this.selected[i] = node
}
if (node.isLeaf) {
this.onSelectedChange(node, node.isLeaf)
return
}
const {
isLeaf,
hasNodes
} = this._updateBindData()
if (this.isLocaldata && (!hasNodes || isLeaf)) {
this.onSelectedChange(node, true)
return
}
if (!isLeaf && !hasNodes) {
this._loadNodeData((data) => {
if (!data.length) {
node.isLeaf = true
} else {
this._treeData.push(...data)
this._updateBindData(node)
}
this.onSelectedChange(node, node.isLeaf)
}, this.nodeWhere)
return
}
this.onSelectedChange(node, false)
},
updateData(data) {
this._treeData = data.treeData
this.selected = data.selected
if (!this._treeData.length) {
this.loadData()
} else {
//this.selected = data.selected
this._updateBindData()
}
},
onDataChange() {
this.$emit('datachange')
},
onSelectedChange(node, isLeaf) {
if (isLeaf) {
this._dispatchEvent()
} else if (node) {
this.$emit('nodeclick', node)
}
},
_dispatchEvent() {
this.$emit('change', this.selected.slice(0))
}
}
}
</script>
<style scoped>
.uni-data-pickerview {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.error-text {
color: #DD524D;
}
.loading-cover {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.5);
display: flex;
flex-direction: column;
align-items: center;
z-index: 1001;
}
.load-more {
margin: auto;
}
.error-message {
background-color: #fff;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 15px;
opacity: .9;
z-index: 102;
}
.selected-list {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-item {
margin-left: 10px;
margin-right: 10px;
padding: 12px 0;
}
.selected-item-active {
border-bottom: 2px solid #007aff;
}
.selected-item-text {
color: #007aff;
}
.tab-c {
position: relative;
flex: 1;
display: flex;
flex-direction: row;
overflow: hidden;
}
.list {
flex: 1;
height: 100%;
}
.item {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
display: flex;
flex-direction: row;
}
.item-text {
flex: 1;
color: #333333;
}
.check {
margin-right: 5px;
border: 2px solid #007aff;
border-left: 0;
border-top: 0;
height: 12px;
width: 6px;
transform-origin: center;
transition: all 0.3s;
transform: rotate(45deg);
}
</style>
\ No newline at end of file
...@@ -45,6 +45,13 @@ ...@@ -45,6 +45,13 @@
* @property {String} prefixIcon 输入框头部图标 * @property {String} prefixIcon 输入框头部图标
* @property {String} suffixIcon 输入框尾部图标 * @property {String} suffixIcon 输入框尾部图标
* @property {Boolean} trim 是否自动去除两端的空格 * @property {Boolean} trim 是否自动去除两端的空格
* @value both 去除两端空格
* @value left 去除左侧空格
* @value right 去除右侧空格
* @value start 去除左侧空格
* @value end 去除右侧空格
* @value all 去除全部空格
* @value none 不去除空格
* @property {Boolean} inputBorder 是否显示input输入框的边框(默认false) * @property {Boolean} inputBorder 是否显示input输入框的边框(默认false)
* @property {Object} styles 自定义颜色 * @property {Object} styles 自定义颜色
* @event {Function} input 输入框内容发生变化时触发 * @event {Function} input 输入框内容发生变化时触发
...@@ -115,7 +122,7 @@ ...@@ -115,7 +122,7 @@
}, },
// 是否自动去除两端的空格 // 是否自动去除两端的空格
trim: { trim: {
type: Boolean, type: [Boolean, String],
default: true default: true
}, },
// 自定义样式 // 自定义样式
...@@ -155,7 +162,7 @@ ...@@ -155,7 +162,7 @@
value(newVal) { value(newVal) {
if (this.errMsg) this.errMsg = '' if (this.errMsg) this.errMsg = ''
this.val = newVal this.val = newVal
if (this.formItem) { if (this.form && this.formItem) {
this.formItem.setValue(newVal) this.formItem.setValue(newVal)
} }
}, },
...@@ -169,13 +176,12 @@ ...@@ -169,13 +176,12 @@
this.val = this.value this.val = this.value
this.form = this.getForm('uniForms') this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem') this.formItem = this.getForm('uniFormsItem')
if (this.formItem) { if (this.form && this.formItem) {
if (this.formItem.name) { if (this.formItem.name) {
this.rename = this.formItem.name this.rename = this.formItem.name
this.form.inputChildrens.push(this) this.form.inputChildrens.push(this)
} }
} }
}, },
mounted() { mounted() {
// this.onInput = throttle(this.input, 500) // this.onInput = throttle(this.input, 500)
...@@ -213,7 +219,14 @@ ...@@ -213,7 +219,14 @@
onInput(event) { onInput(event) {
let value = event.detail.value; let value = event.detail.value;
// 判断是否去除空格 // 判断是否去除空格
if (this.trim) value = this.trimStr(value); if (this.trim) {
if (typeof(this.trim) === 'boolean' && this.trim) {
value = this.trimStr(value)
}
if (typeof(this.trim) === 'string') {
value = this.trimStr(value, this.trim)
}
};
if (this.errMsg) this.errMsg = '' if (this.errMsg) this.errMsg = ''
this.val = value this.val = value
this.$emit('input', value); this.$emit('input', value);
...@@ -243,17 +256,22 @@ ...@@ -243,17 +256,22 @@
this.$emit('click'); this.$emit('click');
}, },
trimStr(str, pos = 'both') { trimStr(str, pos = 'both') {
if (pos == 'both') { if (pos === 'both') {
return str.replace(/^\s+|\s+$/g, ''); return str.trim();
} else if (pos == 'left') { } else if (pos === 'left') {
return str.replace(/^\s*/, ''); return str.trimLeft();
} else if (pos == 'right') { } else if (pos === 'right') {
return str.replace(/(\s*$)/g, ''); return str.trimRight();
} else if (pos == 'all') { } else if (pos === 'start') {
return str.trimStart()
} else if (pos === 'end') {
return str.trimEnd()
} else if (pos === 'all') {
return str.replace(/\s+/g, ''); return str.replace(/\s+/g, '');
} else { } else if (pos === 'none') {
return str; return str;
} }
return str;
} }
} }
}; };
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -99,6 +99,9 @@ ...@@ -99,6 +99,9 @@
} }
.uni-section__content { .uni-section__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
color: #333; color: #333;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册