123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- <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>
|