| 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.isArrayconst { 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>
 |