You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

633 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view>
<slot
:options="options"
:data="dataList"
:pagination="paginationInternal"
:loading="loading"
:hasMore="hasMore"
:error="errorMessage"
/>
</view>
</template>
<script>
import { onMounted, getCurrentInstance } from 'vue'
import { ssrRef, shallowSsrRef } from '@dcloudio/uni-app'
import { initVueI18n } from '@dcloudio/uni-i18n'
import messages from './i18n/index'
const isArray = Array.isArray
const { t } = initVueI18n(messages)
const events = {
load: 'load',
error: 'error'
}
const pageMode = {
add: 'add',
replace: 'replace'
}
const loadMode = {
auto: 'auto',
onready: 'onready',
manual: 'manual'
}
const attrs = [
'pageCurrent',
'pageSize',
'collection',
'action',
'field',
'getcount',
'orderby',
'where',
'groupby',
'groupField',
'distinct'
]
export default {
name: 'UniClouddb',
// #ifdef VUE3
setup(props) {
// 单条记录时使用shallowRef仅支持赋值修改列表时采用ref支持push等修改
const dataListRef = props.ssrKey ? (props.getone ? shallowSsrRef(undefined, props.ssrKey) : ssrRef([], props.ssrKey)) : (props.getone ? shallowSsrRef(undefined) : ssrRef([]))
const instance = getCurrentInstance()
onMounted(() => {
// client端判断是否需要再次请求数据正常情况下SSR返回的html中已包含此数据状态无需再次额外请求
if ((!dataListRef.value || dataListRef.value.length === 0) && !props.manual && props.loadtime === loadMode.auto) {
instance.proxy.loadData()
}
})
return { dataList: dataListRef }
},
// 服务端serverPrefetch生命周期用于服务端加载数据等将来全端支持Suspense时可以采用 Suspense + async setup 来实现一版
async serverPrefetch() {
if (!this.manual && this.loadtime === loadMode.auto) {
return this.loadData()
}
},
// #endif
props: {
options: {
type: [Object, Array],
default() {
return {}
}
},
spaceInfo: {
type: Object,
default() {
return {}
}
},
collection: {
type: [String, Array],
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, Object],
default: false
},
gettreepath: {
type: [Boolean, String],
default: false
},
startwith: {
type: String,
default: ''
},
limitlevel: {
type: Number,
default: 10
},
groupby: {
type: String,
default: ''
},
groupField: {
type: String,
default: ''
},
distinct: {
type: [Boolean, String],
default: false
},
pageIndistinct: {
type: [Boolean, String],
default: false
},
foreignKey: {
type: String,
default: ''
},
loadtime: {
type: String,
default: 'auto'
},
manual: {
type: Boolean,
default: false
},
ssrKey: {
type: [String, Number],
default: ""
}
},
data() {
return {
loading: false,
hasMore: false,
// #ifndef VUE3
dataList: [],
// #endif
paginationInternal: {},
errorMessage: ''
}
},
computed: {
collectionArgs () {
return isArray(this.collection) ? this.collection : [this.collection]
},
isLookup () {
return (isArray(this.collection) && this.collection.length > 1) || (typeof this.collection === 'string' && this.collection.indexOf(',') > -1)
},
mainCollection () {
if (typeof this.collection === 'string') {
return this.collection.split(',')[0]
}
const mainQuery = JSON.parse(JSON.stringify(this.collection[0]))
return mainQuery.$db[0].$param[0]
}
},
created() {
this._isEnded = false
this.paginationInternal = {
current: this.pageCurrent,
size: this.pageSize,
count: 0
}
// #ifndef VUE3
if (this.getone) {
this.dataList = undefined
}
// #endif
this.$watch(() => {
var al = []
attrs.forEach(key => {
al.push(this[key])
})
return al
}, (newValue, oldValue) => {
this.paginationInternal.size = this.pageSize
if (newValue[0] !== oldValue[0]) {
this.paginationInternal.current = this.pageCurrent
}
if (this.loadtime === loadMode.manual) {
return
}
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()
}
this._execLoadData()
})
// #ifdef MP-TOUTIAO
let changeName
const events = this.$scope.dataset.eventOpts || []
for (var i = 0; i < events.length; i++) {
const 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) {
const fun = parent[changeName]
if (fun && typeof fun === 'function') {
this._changeDataFunction = fun
maxDepth = 0
break
}
parent = parent.$parent
maxDepth--
}
}
// #endif
},
// #ifndef VUE3
mounted() {
if (!this.manual && this.loadtime === loadMode.auto) {
this.loadData()
}
},
// #endif
methods: {
loadData(args1, args2) {
let callback = null
let clear = false
if (typeof args1 === 'object') {
if (args1.clear) {
if (this.pageData === pageMode.replace) {
this.clear()
} else {
clear = args1.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
}
return this._execLoadData(callback, clear)
},
loadMore() {
if (this._isEnded || this.loading) {
return
}
if (this.pageData === pageMode.add) {
this.paginationInternal.current++
}
this._execLoadData()
},
refresh() {
this.clear()
this._execLoadData()
},
clear() {
this._isEnded = false
this.dataList = []
},
reset() {
this.paginationInternal.current = 1
},
add(value, {
action,
showToast = true,
toastTitle,
success,
fail,
complete,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (needLoading) {
uni.showLoading({
title: loadingTitle
})
}
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
if (action) {
db = db.action(action)
}
db.collection(this.mainCollection).add(value).then((res) => {
success && success(res)
if (showToast) {
uni.showToast({
title: toastTitle || t('uniCloud.component.add.success')
})
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
remove(id, {
action,
success,
fail,
complete,
confirmTitle,
confirmContent,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (!id || !id.length) {
return
}
if (!needConfirm) {
this._execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle)
return
}
uni.showModal({
title: confirmTitle || t('uniCloud.component.remove.showModal.title'),
content: confirmContent || t('uniCloud.component.remove.showModal.content'),
showCancel: true,
success: (res) => {
if (!res.confirm) {
return
}
this._execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle)
}
})
},
update(id, value, {
action,
showToast = true,
toastTitle,
success,
fail,
complete,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (needLoading) {
uni.showLoading({
title: loadingTitle
})
}
let db = uniCloud.database(this.spaceInfo)
if (action) {
db = db.action(action)
}
return db.collection(this.mainCollection).doc(id).update(value).then((res) => {
success && success(res)
if (showToast) {
uni.showToast({
title: toastTitle || t('uniCloud.component.update.success')
})
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
getTemp(isTemp = true) {
let db = uniCloud.database(this.spaceInfo)
if (this.action) {
db = db.action(this.action)
}
db = db.collection(...this.collectionArgs)
if (this.foreignKey) {
db = db.foreignKey(this.foreignKey)
}
if (!(!this.where || !Object.keys(this.where).length)) {
db = db.where(this.where)
}
if (this.field) {
db = db.field(this.field)
}
if (this.groupby) {
db = db.groupBy(this.groupby)
}
if (this.groupField) {
db = db.groupField(this.groupField)
}
if (this.distinct === true) {
db = db.distinct()
}
if (this.orderby) {
db = db.orderBy(this.orderby)
}
const {
current,
size
} = this.paginationInternal
const getOptions = {}
if (this.getcount) {
getOptions.getCount = this.getcount
}
const treeOptions = {
limitLevel: this.limitlevel,
startWith: this.startwith
}
if (this.gettree) {
getOptions.getTree = treeOptions
}
if (this.gettreepath) {
getOptions.getTreePath = treeOptions
}
db = db.skip(size * (current - 1)).limit(size)
if (isTemp) {
db = db.getTemp(getOptions)
db.udb = this
} else {
db = db.get(getOptions)
}
return db
},
setResult(result) {
if (result.code === 0) {
this._execLoadDataSuccess(result)
} else {
this._execLoadDataFail(new Error(result.message))
}
},
_execLoadData(callback, clear) {
if (this.loading) {
return
}
this.loading = true
this.errorMessage = ''
return this._getExec().then((res) => {
this.loading = false
this._execLoadDataSuccess(res.result, callback, clear)
}).catch((err) => {
this.loading = false
this._execLoadDataFail(err, callback)
})
},
_execLoadDataSuccess(result, callback, clear) {
const {
data,
count
} = result
this._isEnded = count !== undefined ? (this.paginationInternal.current * this.paginationInternal.size >= count) : (data.length < this.pageSize)
this.hasMore = !this._isEnded
const data2 = this.getone ? (data.length ? data[0] : undefined) : data
if (this.getcount) {
this.paginationInternal.count = count
}
callback && callback(data2, this._isEnded, this.paginationInternal)
this._dispatchEvent(events.load, data2)
if (this.getone || this.pageData === pageMode.replace) {
this.dataList = data2
} else {
if (clear) {
this.dataList = data2
} else {
this.dataList.push(...data2)
}
}
},
_execLoadDataFail(err, callback) {
this.errorMessage = err
callback && callback()
this.$emit(events.error, err)
if (process.env.NODE_ENV === 'development') {
console.error(err)
}
},
_getExec() {
return this.getTemp(false)
},
_execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle) {
if (!this.collection || !id) {
return
}
const ids = isArray(id) ? id : [id]
if (!ids.length) {
return
}
if (needLoading) {
uni.showLoading({
mask: true,
title: loadingTitle
})
}
const db = uniCloud.database(this.spaceInfo)
const dbCmd = db.command
let exec = db
if (action) {
exec = exec.action(action)
}
exec.collection(this.mainCollection).where({
_id: dbCmd.in(ids)
}).remove().then((res) => {
success && success(res.result)
if (this.pageData === pageMode.replace) {
this.refresh()
} else {
this.removeData(ids)
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
removeData(ids) {
const il = ids.slice(0)
const dl = this.dataList
for (let i = dl.length - 1; i >= 0; i--) {
const 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, this.paginationInternal)
} else {
this.$emit(type, data, this._isEnded, this.paginationInternal)
}
}
}
}
</script>